summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_inode.c
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2023-12-15 21:03:35 +0300
committerDarrick J. Wong <djwong@kernel.org>2023-12-15 21:03:35 +0300
commitd9041681dd2f5334529a68868c9266631c384de4 (patch)
tree93055bec735bc7aef932d86c1fc32969a650acb1 /fs/xfs/xfs_inode.c
parent6b5d917780219d0d8f8e2cefefcb6f50987d0fa3 (diff)
downloadlinux-d9041681dd2f5334529a68868c9266631c384de4.tar.xz
xfs: set inode sick state flags when we zap either ondisk fork
In a few patches, we'll add some online repair code that tries to massage the ondisk inode record just enough to get it to pass the inode verifiers so that we can continue with more file repairs. Part of that massaging can include zapping the ondisk forks to clear errors. After that point, the bmap fork repair functions will rebuild the zapped forks. Christoph asked for stronger protections against online repair zapping a fork to get the inode to load vs. other threads trying to access the partially repaired file. Do this by adding a special "[DA]FORK_ZAPPED" inode health flag whenever repair zaps a fork, and sprinkling checks for that flag into the various file operations for things that don't like handling an unexpected zero-extents fork. In practice xfs_scrub will scrub and fix the forks almost immediately after zapping them, so the window is very small. However, if a crash or unmount should occur, we can still detect these zapped inode forks by looking for a zero-extents fork when data was expected. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/xfs/xfs_inode.c')
-rw-r--r--fs/xfs/xfs_inode.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index c0f1c89786c2..ea6b277485a4 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -37,6 +37,7 @@
#include "xfs_reflink.h"
#include "xfs_ag.h"
#include "xfs_log_priv.h"
+#include "xfs_health.h"
struct kmem_cache *xfs_inode_cache;
@@ -661,6 +662,8 @@ xfs_lookup(
if (xfs_is_shutdown(dp->i_mount))
return -EIO;
+ if (xfs_ifork_zapped(dp, XFS_DATA_FORK))
+ return -EIO;
error = xfs_dir_lookup(NULL, dp, name, &inum, ci_name);
if (error)
@@ -978,6 +981,8 @@ xfs_create(
if (xfs_is_shutdown(mp))
return -EIO;
+ if (xfs_ifork_zapped(dp, XFS_DATA_FORK))
+ return -EIO;
prid = xfs_get_initial_prid(dp);
@@ -1217,6 +1222,8 @@ xfs_link(
if (xfs_is_shutdown(mp))
return -EIO;
+ if (xfs_ifork_zapped(tdp, XFS_DATA_FORK))
+ return -EIO;
error = xfs_qm_dqattach(sip);
if (error)
@@ -2506,6 +2513,8 @@ xfs_remove(
if (xfs_is_shutdown(mp))
return -EIO;
+ if (xfs_ifork_zapped(dp, XFS_DATA_FORK))
+ return -EIO;
error = xfs_qm_dqattach(dp);
if (error)
@@ -3758,3 +3767,29 @@ xfs_inode_reload_unlinked(
return error;
}
+
+/* Has this inode fork been zapped by repair? */
+bool
+xfs_ifork_zapped(
+ const struct xfs_inode *ip,
+ int whichfork)
+{
+ unsigned int datamask = 0;
+
+ switch (whichfork) {
+ case XFS_DATA_FORK:
+ switch (ip->i_vnode.i_mode & S_IFMT) {
+ case S_IFDIR:
+ datamask = XFS_SICK_INO_DIR_ZAPPED;
+ break;
+ case S_IFLNK:
+ datamask = XFS_SICK_INO_SYMLINK_ZAPPED;
+ break;
+ }
+ return ip->i_sick & (XFS_SICK_INO_BMBTD_ZAPPED | datamask);
+ case XFS_ATTR_FORK:
+ return ip->i_sick & XFS_SICK_INO_BMBTA_ZAPPED;
+ default:
+ return false;
+ }
+}