]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: confirm dotdot target before replacing it during a repair
authorDarrick J. Wong <djwong@kernel.org>
Mon, 4 Nov 2024 04:19:02 +0000 (20:19 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 5 Nov 2024 21:38:34 +0000 (13:38 -0800)
xfs_dir_replace trips an assertion if you tell it to change a dirent to
point to an inumber that it already points at.  Look up the dotdot entry
directly to confirm that we need to make a change.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/scrub/dir_repair.c

index 2456cf1cb744110e3041dfaf26a3c24473bd369c..24931388210872d0a750208a5c30d2fa9fedaef7 100644 (file)
@@ -1638,6 +1638,7 @@ xrep_dir_swap(
        struct xrep_dir         *rd)
 {
        struct xfs_scrub        *sc = rd->sc;
+       xfs_ino_t               ino;
        bool                    ip_local, temp_local;
        int                     error = 0;
 
@@ -1655,14 +1656,17 @@ xrep_dir_swap(
 
        /*
         * Reset the temporary directory's '..' entry to point to the parent
-        * that we found.  The temporary directory was created with the root
-        * directory as the parent, so we can skip this if repairing a
-        * subdirectory of the root.
+        * that we found.  The dirent replace code asserts if the dirent
+        * already points at the new inumber, so we look it up here.
         *
         * It's also possible that this replacement could also expand a sf
         * tempdir into block format.
         */
-       if (rd->pscan.parent_ino != sc->mp->m_rootip->i_ino) {
+       error = xchk_dir_lookup(sc, rd->sc->tempip, &xfs_name_dotdot, &ino);
+       if (error)
+               return error;
+
+       if (rd->pscan.parent_ino != ino) {
                error = xrep_dir_replace(rd, rd->sc->tempip, &xfs_name_dotdot,
                                rd->pscan.parent_ino, rd->tx.req.resblks);
                if (error)