diff options
author | Darrick J. Wong <djwong@kernel.org> | 2023-04-12 05:00:21 +0300 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2023-04-12 05:00:21 +0300 |
commit | 302436c27c3fc61c1dab83f4c995dec12eb43161 (patch) | |
tree | a077b5240b93b9cb2fbfe6e009b21a502b99e6d3 /fs/xfs/scrub/common.h | |
parent | a03297a0ca9f21800c9b88028a3722715b2eb5ba (diff) | |
download | linux-302436c27c3fc61c1dab83f4c995dec12eb43161.tar.xz |
xfs: fix an inode lookup race in xchk_get_inode
In commit d658e, we tried to improve the robustnes of xchk_get_inode in
the face of EINVAL returns from iget by calling xfs_imap to see if the
inobt itself thinks that the inode is allocated. Unfortunately, that
commit didn't consider the possibility that the inode gets allocated
after iget but before imap. In this case, the imap call will succeed,
but we turn that into a corruption error and tell userspace the inode is
corrupt.
Avoid this false corruption report by grabbing the AGI header and
retrying the iget before calling imap. If the iget succeeds, we can
proceed with the usual scrub-by-handle code. Fix all the incorrect
comments too, since unreadable/corrupt inodes no longer result in EINVAL
returns.
Fixes: d658e72b4a09 ("xfs: distinguish between corrupt inode and invalid inum in xfs_scrub_get_inode")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Diffstat (limited to 'fs/xfs/scrub/common.h')
-rw-r--r-- | fs/xfs/scrub/common.h | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/fs/xfs/scrub/common.h b/fs/xfs/scrub/common.h index 7e9e8b7b6cb0..5c76614c2c04 100644 --- a/fs/xfs/scrub/common.h +++ b/fs/xfs/scrub/common.h @@ -32,6 +32,8 @@ xchk_should_terminate( } int xchk_trans_alloc(struct xfs_scrub *sc, uint resblks); +void xchk_trans_cancel(struct xfs_scrub *sc); + bool xchk_process_error(struct xfs_scrub *sc, xfs_agnumber_t agno, xfs_agblock_t bno, int *error); bool xchk_fblock_process_error(struct xfs_scrub *sc, int whichfork, @@ -138,6 +140,8 @@ int xchk_setup_inode_contents(struct xfs_scrub *sc, unsigned int resblks); void xchk_buffer_recheck(struct xfs_scrub *sc, struct xfs_buf *bp); int xchk_iget(struct xfs_scrub *sc, xfs_ino_t inum, struct xfs_inode **ipp); +int xchk_iget_agi(struct xfs_scrub *sc, xfs_ino_t inum, + struct xfs_buf **agi_bpp, struct xfs_inode **ipp); void xchk_irele(struct xfs_scrub *sc, struct xfs_inode *ip); /* |