75 lines
2.5 KiB
Diff
75 lines
2.5 KiB
Diff
From 51e3cc7d8642f4127493ee1e907f6c0abdae295f Mon Sep 17 00:00:00 2001
|
|
From: "Darrick J. Wong" <djwong@kernel.org>
|
|
Date: Mon, 2 Dec 2024 10:57:42 -0800
|
|
Subject: xfs: fix zero byte checking in the superblock scrubber
|
|
|
|
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 | 29 +++++++++++++++++++++++++++--
|
|
1 file changed, 27 insertions(+), 2 deletions(-)
|
|
|
|
--- a/fs/xfs/scrub/agheader.c
|
|
+++ b/fs/xfs/scrub/agheader.c
|
|
@@ -60,6 +60,30 @@ xchk_superblock_xref(
|
|
}
|
|
|
|
/*
|
|
+ * 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_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.
|
|
*
|
|
* Note: We do /not/ attempt to check AG 0's superblock. Mount is
|
|
@@ -75,6 +99,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;
|
|
@@ -350,8 +375,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);
|