diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c index 169123772cb3..d7c5e97801bf 100644 --- a/fs/xfs/xfs_health.c +++ b/fs/xfs/xfs_health.c @@ -38,6 +38,37 @@ xfs_health_unmount_group( } } +static bool +xfs_inode_can_report_file_error( + struct inode *inode) +{ + enum inode_state_flags_enum state; + bool ok; + + spin_lock(&inode->i_lock); + state = inode_state_read(inode); + ok = !inode_unhashed(inode) && + !(state & (I_NEW | I_WILL_FREE | I_FREEING | I_CLEAR)); + if (ok) + inode_state_clear(inode, I_DONTCACHE); + spin_unlock(&inode->i_lock); + + return ok; +} + +static void +xfs_report_inode_corruption( + struct xfs_inode *ip) +{ + struct inode *inode = VFS_I(ip); + + if (xfs_inode_can_report_file_error(inode)) + fserror_report_file_metadata(inode, -EFSCORRUPTED, GFP_NOFS); + else + fserror_report_metadata(ip->i_mount->m_super, -EFSCORRUPTED, + GFP_NOFS); +} + /* * Warn about metadata corruption that we detected but haven't fixed, and * make sure we're not sitting on anything that would get in the way of @@ -330,16 +361,7 @@ xfs_inode_mark_sick( ip->i_sick |= mask; spin_unlock(&ip->i_flags_lock); - /* - * Keep this inode around so we don't lose the sickness report. Scrub - * grabs inodes with DONTCACHE assuming that most inode are ok, which - * is not the case here. - */ - spin_lock(&VFS_I(ip)->i_lock); - inode_state_clear(VFS_I(ip), I_DONTCACHE); - spin_unlock(&VFS_I(ip)->i_lock); - - fserror_report_file_metadata(VFS_I(ip), -EFSCORRUPTED, GFP_NOFS); + xfs_report_inode_corruption(ip); if (mask) xfs_healthmon_report_inode(ip, XFS_HEALTHMON_SICK, old_mask, mask); @@ -362,16 +384,7 @@ xfs_inode_mark_corrupt( ip->i_checked |= mask; spin_unlock(&ip->i_flags_lock); - /* - * Keep this inode around so we don't lose the sickness report. Scrub - * grabs inodes with DONTCACHE assuming that most inode are ok, which - * is not the case here. - */ - spin_lock(&VFS_I(ip)->i_lock); - inode_state_clear(VFS_I(ip), I_DONTCACHE); - spin_unlock(&VFS_I(ip)->i_lock); - - fserror_report_file_metadata(VFS_I(ip), -EFSCORRUPTED, GFP_NOFS); + xfs_report_inode_corruption(ip); if (mask) xfs_healthmon_report_inode(ip, XFS_HEALTHMON_CORRUPT, old_mask, mask);