summaryrefslogtreecommitdiff
path: root/fs/xfs/scrub/iscan.h
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2024-04-16 00:54:04 +0300
committerDarrick J. Wong <djwong@kernel.org>2024-04-16 00:54:04 +0300
commit2afd5276d314d775ae0bdaa6ec22069515bd9c70 (patch)
treeb9002ba772eb5dd152cd5fac566b5e8124ccafc0 /fs/xfs/scrub/iscan.h
parent549d3c9a29921f388ef3bcfd1d4f669b7dd4eed2 (diff)
downloadlinux-2afd5276d314d775ae0bdaa6ec22069515bd9c70.tar.xz
xfs: fix an AGI lock acquisition ordering problem in xrep_dinode_findmode
While reviewing the next patch which fixes an ABBA deadlock between the AGI and a directory ILOCK, someone asked a question about why we're holding the AGI in the first place. The reason for that is to quiesce the inode structures for that AG while we do a repair. I then realized that the xrep_dinode_findmode invokes xchk_iscan_iter, which walks the inobts (and hence the AGIs) to find all the inodes. This itself is also an ABBA vector, since the damaged inode could be in AG 5, which we hold while we scan AG 0 for directories. 5 -> 0 is not allowed. To address this, modify the iscan to allow trylock of the AGI buffer using the flags argument to xfs_ialloc_read_agi that the previous patch added. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/xfs/scrub/iscan.h')
-rw-r--r--fs/xfs/scrub/iscan.h15
1 files changed, 15 insertions, 0 deletions
diff --git a/fs/xfs/scrub/iscan.h b/fs/xfs/scrub/iscan.h
index 71f657552dfa..5e0e4ed9dea6 100644
--- a/fs/xfs/scrub/iscan.h
+++ b/fs/xfs/scrub/iscan.h
@@ -59,6 +59,9 @@ struct xchk_iscan {
/* Set if the scan has been aborted due to some event in the fs. */
#define XCHK_ISCAN_OPSTATE_ABORTED (1)
+/* Use trylock to acquire the AGI */
+#define XCHK_ISCAN_OPSTATE_TRYLOCK_AGI (2)
+
static inline bool
xchk_iscan_aborted(const struct xchk_iscan *iscan)
{
@@ -71,6 +74,18 @@ xchk_iscan_abort(struct xchk_iscan *iscan)
set_bit(XCHK_ISCAN_OPSTATE_ABORTED, &iscan->__opstate);
}
+static inline bool
+xchk_iscan_agi_needs_trylock(const struct xchk_iscan *iscan)
+{
+ return test_bit(XCHK_ISCAN_OPSTATE_TRYLOCK_AGI, &iscan->__opstate);
+}
+
+static inline void
+xchk_iscan_set_agi_trylock(struct xchk_iscan *iscan)
+{
+ set_bit(XCHK_ISCAN_OPSTATE_TRYLOCK_AGI, &iscan->__opstate);
+}
+
void xchk_iscan_start(struct xfs_scrub *sc, unsigned int iget_timeout,
unsigned int iget_retry_delay, struct xchk_iscan *iscan);
void xchk_iscan_teardown(struct xchk_iscan *iscan);