]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: fix an ABBA deadlock in xfs_rename
authorDarrick J. Wong <darrick.wong@oracle.com>
Mon, 5 Apr 2021 21:58:12 +0000 (17:58 -0400)
committerEric Sandeen <sandeen@sandeen.net>
Mon, 5 Apr 2021 21:58:12 +0000 (17:58 -0400)
Source kernel commit: 6da1b4b1ab36d80a3994fd4811c8381de10af604

When overlayfs is running on top of xfs and the user unlinks a file in
the overlay, overlayfs will create a whiteout inode and ask xfs to
"rename" the whiteout file atop the one being unlinked.  If the file
being unlinked loses its one nlink, we then have to put the inode on the
unlinked list.

This requires us to grab the AGI buffer of the whiteout inode to take it
off the unlinked list (which is where whiteouts are created) and to grab
the AGI buffer of the file being deleted.  If the whiteout was created
in a higher numbered AG than the file being deleted, we'll lock the AGIs
in the wrong order and deadlock.

Therefore, grab all the AGI locks we think we'll need ahead of time, and
in order of increasing AG number per the locking rules.

Reported-by: wenli xie <wlxie7296@gmail.com>
Fixes: 93597ae8dac0 ("xfs: Fix deadlock between AGI and AGF when target_ip exists in xfs_rename()")
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
libxfs/xfs_dir2.h
libxfs/xfs_dir2_sf.c

index e55378640b056122348c2594ae4039c4a5ddcaca..d03e6098ded9f9bf7b0e6548cc4b33d4dbdbe8f7 100644 (file)
@@ -47,8 +47,6 @@ extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
 extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
                                struct xfs_name *name, xfs_ino_t ino,
                                xfs_extlen_t tot);
-extern bool xfs_dir2_sf_replace_needblock(struct xfs_inode *dp,
-                               xfs_ino_t inum);
 extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
                                struct xfs_name *name, xfs_ino_t inum,
                                xfs_extlen_t tot);
index fbbb638728bc4d16c0dbb821cc2e32fb1e6fc56b..e5a8e0c8cf2e4ecbb44b2f8a6a0df2ba8908ac8e 100644 (file)
@@ -1018,7 +1018,7 @@ xfs_dir2_sf_removename(
 /*
  * Check whether the sf dir replace operation need more blocks.
  */
-bool
+static bool
 xfs_dir2_sf_replace_needblock(
        struct xfs_inode        *dp,
        xfs_ino_t               inum)