Commit c004a793 authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

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: 21fb4cb1 ("xfs: scrub the secondary superblocks")
Signed-off-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 06b20ef0
Loading
Loading
Loading
Loading
+29 −2
Original line number Diff line number Diff line
@@ -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);