]> www.infradead.org Git - users/hch/misc.git/commitdiff
xfs: fix zero byte checking in the superblock scrubber
authorDarrick J. Wong <djwong@kernel.org>
Mon, 2 Dec 2024 18:57:42 +0000 (10:57 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Fri, 13 Dec 2024 01:45:13 +0000 (17:45 -0800)
The logic to check that the region past the end of the superblock is all
zeroes is wrong -- we don't want to check only the bytes past the end of
the maximally sized ondisk superblock structure as currently defined in
xfs_format.h; we want to check the bytes beyond the end of the ondisk as
defined by the feature bits.

Port the superblock size logic from xfs_repair and then put it to use in
xfs_scrub.

Cc: <stable@vger.kernel.org> # v4.15
Fixes: 21fb4cb1981ef7 ("xfs: scrub the secondary superblocks")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/scrub/agheader.c

index 88063d67cb5fd4e002013096a8c98bead74b2ba5..9f8c312dfd3c8264327a0032491add617e8d9475 100644 (file)
@@ -59,6 +59,32 @@ xchk_superblock_xref(
        /* scrub teardown will take care of sc->sa for us */
 }
 
+/*
+ * Calculate the ondisk superblock size in bytes given the feature set of the
+ * mounted filesystem (aka the primary sb).  This is subtlely different from
+ * the logic in xfs_repair, which computes the size of a secondary sb given the
+ * featureset listed in the secondary sb.
+ */
+STATIC size_t
+xchk_superblock_ondisk_size(
+       struct xfs_mount        *mp)
+{
+       if (xfs_has_metadir(mp))
+               return offsetofend(struct xfs_dsb, sb_pad);
+       if (xfs_has_metauuid(mp))
+               return offsetofend(struct xfs_dsb, sb_meta_uuid);
+       if (xfs_has_crc(mp))
+               return offsetofend(struct xfs_dsb, sb_lsn);
+       if (xfs_sb_version_hasmorebits(&mp->m_sb))
+               return offsetofend(struct xfs_dsb, sb_bad_features2);
+       if (xfs_has_logv2(mp))
+               return offsetofend(struct xfs_dsb, sb_logsunit);
+       if (xfs_has_sector(mp))
+               return offsetofend(struct xfs_dsb, sb_logsectsize);
+       /* only support dirv2 or more recent */
+       return offsetofend(struct xfs_dsb, sb_dirblklog);
+}
+
 /*
  * Scrub the filesystem superblock.
  *
@@ -75,6 +101,7 @@ xchk_superblock(
        struct xfs_buf          *bp;
        struct xfs_dsb          *sb;
        struct xfs_perag        *pag;
+       size_t                  sblen;
        xfs_agnumber_t          agno;
        uint32_t                v2_ok;
        __be32                  features_mask;
@@ -388,8 +415,8 @@ xchk_superblock(
        }
 
        /* Everything else must be zero. */
-       if (memchr_inv(sb + 1, 0,
-                       BBTOB(bp->b_length) - sizeof(struct xfs_dsb)))
+       sblen = xchk_superblock_ondisk_size(mp);
+       if (memchr_inv((char *)sb + sblen, 0, BBTOB(bp->b_length) - sblen))
                xchk_block_set_corrupt(sc, bp);
 
        xchk_superblock_xref(sc, bp);