From: Darrick J. Wong Date: Mon, 27 Jul 2026 05:23:15 +0000 (-0700) Subject: xfs: don't double-lock when deleting a self-referential directory X-Git-Tag: v7.2-rc7~29^2~19 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5fc643fb86599e29b38e7b2c2680b4b15bf8f772;p=thirdparty%2Flinux.git xfs: don't double-lock when deleting a self-referential directory LOLLM notices that the dirtree scrubber can detect a directory that refers to itself. In this case, it's not correct for the directory tree repair code to try to iolock/ilock both sc->ip and dp, because they're the same inode. Fix this by detecting that corner case and handling it appropriately. Cc: stable@vger.kernel.org # v6.10 Fixes: 3f31406aef493b ("xfs: fix corruptions in the directory tree") Signed-off-by: Darrick J. Wong Assisted-by: LOLLM # finding obvious bugs Reviewed-by: Christoph Hellwig Signed-off-by: Carlos Maiolino --- diff --git a/fs/xfs/scrub/dirtree_repair.c b/fs/xfs/scrub/dirtree_repair.c index 1c0d7ea4a5be..bbf6acf6fd40 100644 --- a/fs/xfs/scrub/dirtree_repair.c +++ b/fs/xfs/scrub/dirtree_repair.c @@ -349,6 +349,8 @@ xrep_dirtree_unlink_iolock( ASSERT(sc->ilock_flags & XFS_IOLOCK_EXCL); + if (sc->ip == dp) + return 0; if (xfs_ilock_nowait(dp, XFS_IOLOCK_EXCL)) return 0; @@ -400,8 +402,18 @@ xrep_dirtree_unlink( * directory code can handle a reservationless update. */ resblks = xfs_remove_space_res(mp, step->name_len); - error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, sc->ip, - &resblks, &sc->tp, &dontcare); + if (sc->ip == dp) { +again: + error = xfs_trans_alloc_inode(dp, &M_RES(mp)->tr_remove, + resblks, 0, false, &sc->tp); + if ((error == -ENOSPC || error == -EDQUOT) && resblks > 0) { + resblks = 0; + goto again; + } + } else { + error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, sc->ip, + &resblks, &sc->tp, &dontcare); + } if (error) goto out_iolock; @@ -489,9 +501,11 @@ out_trans_cancel: xchk_trans_cancel(sc); out_ilock: xfs_iunlock(sc->ip, XFS_ILOCK_EXCL); - xfs_iunlock(dp, XFS_ILOCK_EXCL); + if (dp != sc->ip) + xfs_iunlock(dp, XFS_ILOCK_EXCL); out_iolock: - xfs_iunlock(dp, XFS_IOLOCK_EXCL); + if (dp != sc->ip) + xfs_iunlock(dp, XFS_IOLOCK_EXCL); return error; }