summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2018-05-14 09:34:34 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2018-05-15 21:12:50 -0400
commitddd10c2fe20e7ca6d11ddf84f905edba080b26a7 (patch)
tree4959baa41dc5019a27a59d55699a573cfe9afd21
parent517b32b7fa0e7d89f644651cc5f048e77fd6e91e (diff)
xfs: avoid ABBA deadlock when scrubbing parent pointers
In normal operation, the XFS convention is to take an inode's iolock and then allocate a transaction. However, when scrubbing parent inodes this is inverted -- we allocated the transaction to do the scrub, and now we're trying to grab the parent's iolock. This can lead to ABBA deadlocks: some thread grabbed the parent's iolock and is waiting for space for a transaction while our parent scrubber is sitting on a transaction trying to get the parent's iolock. Therefore, convert all iolock attempts to use trylock; if that fails, they can use the existing mechanisms to back off and try again. The ABBA deadlock didn't happen with a non-repair scrub because the transactions don't reserve any space, but repair scrubs require reservation in order to update metadata. However, any other concurrent metadata update (e.g. directory create in the parent) could also induce this deadlock with the parent scrubber. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Brian Foster <bfoster@redhat.com>
-rw-r--r--fs/xfs/scrub/common.c22
-rw-r--r--fs/xfs/scrub/common.h1
-rw-r--r--fs/xfs/scrub/parent.c16
3 files changed, 37 insertions, 2 deletions
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index 62b33c99efe4..518bff2be0c9 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -844,3 +844,25 @@ xfs_scrub_metadata_inode_forks(
844 844
845 return error; 845 return error;
846} 846}
847
848/*
849 * Try to lock an inode in violation of the usual locking order rules. For
850 * example, trying to get the IOLOCK while in transaction context, or just
851 * plain breaking AG-order or inode-order inode locking rules. Either way,
852 * the only way to avoid an ABBA deadlock is to use trylock and back off if
853 * we can't.
854 */
855int
856xfs_scrub_ilock_inverted(
857 struct xfs_inode *ip,
858 uint lock_mode)
859{
860 int i;
861
862 for (i = 0; i < 20; i++) {
863 if (xfs_ilock_nowait(ip, lock_mode))
864 return 0;
865 delay(1);
866 }
867 return -EDEADLOCK;
868}
diff --git a/fs/xfs/scrub/common.h b/fs/xfs/scrub/common.h
index 5d78bb9602ab..119d9b6db887 100644
--- a/fs/xfs/scrub/common.h
+++ b/fs/xfs/scrub/common.h
@@ -156,5 +156,6 @@ static inline bool xfs_scrub_skip_xref(struct xfs_scrub_metadata *sm)
156} 156}
157 157
158int xfs_scrub_metadata_inode_forks(struct xfs_scrub_context *sc); 158int xfs_scrub_metadata_inode_forks(struct xfs_scrub_context *sc);
159int xfs_scrub_ilock_inverted(struct xfs_inode *ip, uint lock_mode);
159 160
160#endif /* __XFS_SCRUB_COMMON_H__ */ 161#endif /* __XFS_SCRUB_COMMON_H__ */
diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c
index fc336807e156..77c6b22c6bfd 100644
--- a/fs/xfs/scrub/parent.c
+++ b/fs/xfs/scrub/parent.c
@@ -214,7 +214,9 @@ xfs_scrub_parent_validate(
214 */ 214 */
215 xfs_iunlock(sc->ip, sc->ilock_flags); 215 xfs_iunlock(sc->ip, sc->ilock_flags);
216 sc->ilock_flags = 0; 216 sc->ilock_flags = 0;
217 xfs_ilock(dp, XFS_IOLOCK_SHARED); 217 error = xfs_scrub_ilock_inverted(dp, XFS_IOLOCK_SHARED);
218 if (error)
219 goto out_rele;
218 220
219 /* Go looking for our dentry. */ 221 /* Go looking for our dentry. */
220 error = xfs_scrub_parent_count_parent_dentries(sc, dp, &nlink); 222 error = xfs_scrub_parent_count_parent_dentries(sc, dp, &nlink);
@@ -223,8 +225,10 @@ xfs_scrub_parent_validate(
223 225
224 /* Drop the parent lock, relock this inode. */ 226 /* Drop the parent lock, relock this inode. */
225 xfs_iunlock(dp, XFS_IOLOCK_SHARED); 227 xfs_iunlock(dp, XFS_IOLOCK_SHARED);
228 error = xfs_scrub_ilock_inverted(sc->ip, XFS_IOLOCK_EXCL);
229 if (error)
230 goto out_rele;
226 sc->ilock_flags = XFS_IOLOCK_EXCL; 231 sc->ilock_flags = XFS_IOLOCK_EXCL;
227 xfs_ilock(sc->ip, sc->ilock_flags);
228 232
229 /* 233 /*
230 * If we're an unlinked directory, the parent /won't/ have a link 234 * If we're an unlinked directory, the parent /won't/ have a link
@@ -326,5 +330,13 @@ xfs_scrub_parent(
326 if (try_again && tries == 20) 330 if (try_again && tries == 20)
327 xfs_scrub_set_incomplete(sc); 331 xfs_scrub_set_incomplete(sc);
328out: 332out:
333 /*
334 * If we failed to lock the parent inode even after a retry, just mark
335 * this scrub incomplete and return.
336 */
337 if (sc->try_harder && error == -EDEADLOCK) {
338 error = 0;
339 xfs_scrub_set_incomplete(sc);
340 }
329 return error; 341 return error;
330} 342}