]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_repair: fix bad next_unlinked field
authorEric Sandeen <sandeen@redhat.com>
Thu, 27 Feb 2020 19:21:45 +0000 (14:21 -0500)
committerEric Sandeen <sandeen@sandeen.net>
Thu, 27 Feb 2020 19:21:45 +0000 (14:21 -0500)
As of xfsprogs-4.17 we started testing whether the di_next_unlinked field
on an inode is valid in the inode verifiers. However, this field is never
tested or repaired during inode processing.

So if, for example, we had a completely zeroed-out inode, we'd detect and
fix the broken magic and version, but the invalid di_next_unlinked field
would not be touched, fail the write verifier, and prevent the inode from
being properly repaired or even written out.

Fix this by checking the di_next_unlinked inode field for validity and
clearing it if it is invalid.

Reported-by: John Jore <john@jore.no>
Fixes: 2949b4677 ("xfs: don't accept inode buffers with suspicious unlinked chains")
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
repair/dinode.c

index 8af2cb259196006e58a64af1d5124abfd540ac48..929ec81702c10d27aa385eb1122f83b167b67617 100644 (file)
@@ -2272,6 +2272,7 @@ process_dinode_int(xfs_mount_t *mp,
        const int               is_free = 0;
        const int               is_used = 1;
        blkmap_t                *dblkmap = NULL;
+       xfs_agino_t             unlinked_ino;
 
        *dirty = *isa_dir = 0;
        *used = is_used;
@@ -2351,6 +2352,23 @@ process_dinode_int(xfs_mount_t *mp,
                }
        }
 
+       unlinked_ino = be32_to_cpu(dino->di_next_unlinked);
+       if (!xfs_verify_agino_or_null(mp, agno, unlinked_ino)) {
+               retval = 1;
+               if (!uncertain)
+                       do_warn(_("bad next_unlinked 0x%x on inode %" PRIu64 "%c"),
+                               be32_to_cpu(dino->di_next_unlinked), lino,
+                               verify_mode ? '\n' : ',');
+               if (!verify_mode) {
+                       if (!no_modify) {
+                               do_warn(_(" resetting next_unlinked\n"));
+                               clear_dinode_unlinked(mp, dino);
+                               *dirty = 1;
+                       } else
+                               do_warn(_(" would reset next_unlinked\n"));
+               }
+       }
+
        /*
         * We don't bother checking the CRC here - we cannot guarantee that when
         * we are called here that the inode has not already been modified in