Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

xfs: refactor superblock verifiers



Split the superblock verifier into the common checks, the read-time
checks, and the write-time check functions.  No functional changes, but
we're setting up to add more write-only checks.

Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarEric Sandeen <sandeen@redhat.com>
parent 86d969b4
Loading
Loading
Loading
Loading
+111 −94
Original line number Original line Diff line number Diff line
@@ -96,48 +96,28 @@ xfs_perag_put(
	trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
	trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
}
}


/*
/* Check all the superblock fields we care about when reading one in. */
 * Check the validity of the SB found.
 */
STATIC int
STATIC int
xfs_mount_validate_sb(
xfs_validate_sb_read(
	xfs_mount_t	*mp,
	struct xfs_mount	*mp,
	xfs_sb_t	*sbp,
	struct xfs_sb		*sbp)
	bool		check_inprogress,
	bool		check_version)
{
{
	uint32_t	agcount = 0;
	if (XFS_SB_VERSION_NUM(sbp) != XFS_SB_VERSION_5)
	uint32_t	rem;
		return 0;

	if (sbp->sb_magicnum != XFS_SB_MAGIC) {
		xfs_warn(mp, "bad magic number");
		return -EWRONGFS;
	}


	if (!xfs_sb_good_version(sbp)) {
		xfs_warn(mp, "bad version");
		return -EWRONGFS;
	}


	/*
	/*
	 * Version 5 superblock feature mask validation. Reject combinations the
	 * Version 5 superblock feature mask validation. Reject combinations
	 * kernel cannot support up front before checking anything else. For
	 * the kernel cannot support up front before checking anything else.
	 * write validation, we don't need to check feature masks.
	 */
	 */
	if (check_version && XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) {
	if (xfs_sb_has_compat_feature(sbp, XFS_SB_FEAT_COMPAT_UNKNOWN)) {
		if (xfs_sb_has_compat_feature(sbp,
					XFS_SB_FEAT_COMPAT_UNKNOWN)) {
		xfs_warn(mp,
		xfs_warn(mp,
"Superblock has unknown compatible features (0x%x) enabled.",
"Superblock has unknown compatible features (0x%x) enabled.",
				(sbp->sb_features_compat &
			(sbp->sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN));
						XFS_SB_FEAT_COMPAT_UNKNOWN));
		xfs_warn(mp,
		xfs_warn(mp,
"Using a more recent kernel is recommended.");
"Using a more recent kernel is recommended.");
	}
	}


		if (xfs_sb_has_ro_compat_feature(sbp,
	if (xfs_sb_has_ro_compat_feature(sbp, XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
					XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
		xfs_alert(mp,
		xfs_alert(mp,
"Superblock has unknown read-only compatible features (0x%x) enabled.",
"Superblock has unknown read-only compatible features (0x%x) enabled.",
			(sbp->sb_features_ro_compat &
			(sbp->sb_features_ro_compat &
@@ -151,8 +131,7 @@ xfs_mount_validate_sb(
			return -EINVAL;
			return -EINVAL;
		}
		}
	}
	}
		if (xfs_sb_has_incompat_feature(sbp,
	if (xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_UNKNOWN)) {
					XFS_SB_FEAT_INCOMPAT_UNKNOWN)) {
		xfs_warn(mp,
		xfs_warn(mp,
"Superblock has unknown incompatible features (0x%x) enabled.",
"Superblock has unknown incompatible features (0x%x) enabled.",
			(sbp->sb_features_incompat &
			(sbp->sb_features_incompat &
@@ -161,15 +140,50 @@ xfs_mount_validate_sb(
"Filesystem cannot be safely mounted by this kernel.");
"Filesystem cannot be safely mounted by this kernel.");
		return -EINVAL;
		return -EINVAL;
	}
	}
	} else if (xfs_sb_version_hascrc(sbp)) {

	return 0;
}

/* Check all the superblock fields we care about when writing one out. */
STATIC int
xfs_validate_sb_write(
	struct xfs_mount	*mp,
	struct xfs_sb		*sbp)
{
	if (XFS_SB_VERSION_NUM(sbp) != XFS_SB_VERSION_5)
		return 0;

	/* XXX: For write validation, we don't need to check feature masks?? */

	/*
	/*
		 * We can't read verify the sb LSN because the read verifier is
	 * We can't read verify the sb LSN because the read verifier is called
		 * called before the log is allocated and processed. We know the
	 * before the log is allocated and processed. We know the log is set up
		 * log is set up before write verifier (!check_version) calls,
	 * before write verifier calls, so check it here.
		 * so just check it here.
	 */
	 */
	if (!xfs_log_check_lsn(mp, sbp->sb_lsn))
	if (!xfs_log_check_lsn(mp, sbp->sb_lsn))
		return -EFSCORRUPTED;
		return -EFSCORRUPTED;

	return 0;
}

/* Check the validity of the SB. */
STATIC int
xfs_validate_sb_common(
	struct xfs_mount	*mp,
	struct xfs_buf		*bp,
	struct xfs_sb		*sbp)
{
	uint32_t		agcount = 0;
	uint32_t		rem;

	if (sbp->sb_magicnum != XFS_SB_MAGIC) {
		xfs_warn(mp, "bad magic number");
		return -EWRONGFS;
	}

	if (!xfs_sb_good_version(sbp)) {
		xfs_warn(mp, "bad version");
		return -EWRONGFS;
	}
	}


	if (xfs_sb_version_has_pquotino(sbp)) {
	if (xfs_sb_version_has_pquotino(sbp)) {
@@ -321,7 +335,12 @@ xfs_mount_validate_sb(
		return -EFBIG;
		return -EFBIG;
	}
	}


	if (check_inprogress && sbp->sb_inprogress) {
	/*
	 * Don't touch the filesystem if a user tool thinks it owns the primary
	 * superblock.  mkfs doesn't clear the flag from secondary supers, so
	 * we don't check them at all.
	 */
	if (XFS_BUF_ADDR(bp) == XFS_SB_DADDR && sbp->sb_inprogress) {
		xfs_warn(mp, "Offline file system operation in progress!");
		xfs_warn(mp, "Offline file system operation in progress!");
		return -EFSCORRUPTED;
		return -EFSCORRUPTED;
	}
	}
@@ -596,29 +615,6 @@ xfs_sb_to_disk(
	}
	}
}
}


static int
xfs_sb_verify(
	struct xfs_buf	*bp,
	bool		check_version)
{
	struct xfs_mount *mp = bp->b_target->bt_mount;
	struct xfs_sb	sb;

	/*
	 * Use call variant which doesn't convert quota flags from disk 
	 * format, because xfs_mount_validate_sb checks the on-disk flags.
	 */
	__xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp), false);

	/*
	 * Only check the in progress field for the primary superblock as
	 * mkfs.xfs doesn't clear it from secondary superblocks.
	 */
	return xfs_mount_validate_sb(mp, &sb,
				     bp->b_maps[0].bm_bn == XFS_SB_DADDR,
				     check_version);
}

/*
/*
 * If the superblock has the CRC feature bit set or the CRC field is non-null,
 * If the superblock has the CRC feature bit set or the CRC field is non-null,
 * check that the CRC is valid.  We check the CRC field is non-null because a
 * check that the CRC is valid.  We check the CRC field is non-null because a
@@ -635,6 +631,7 @@ static void
xfs_sb_read_verify(
xfs_sb_read_verify(
	struct xfs_buf		*bp)
	struct xfs_buf		*bp)
{
{
	struct xfs_sb		sb;
	struct xfs_mount	*mp = bp->b_target->bt_mount;
	struct xfs_mount	*mp = bp->b_target->bt_mount;
	struct xfs_dsb		*dsb = XFS_BUF_TO_SBP(bp);
	struct xfs_dsb		*dsb = XFS_BUF_TO_SBP(bp);
	int			error;
	int			error;
@@ -657,7 +654,16 @@ xfs_sb_read_verify(
			}
			}
		}
		}
	}
	}
	error = xfs_sb_verify(bp, true);

	/*
	 * Check all the superblock fields.  Don't byteswap the xquota flags
	 * because _verify_common checks the on-disk values.
	 */
	__xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp), false);
	error = xfs_validate_sb_common(mp, bp, &sb);
	if (error)
		goto out_error;
	error = xfs_validate_sb_read(mp, &sb);


out_error:
out_error:
	if (error == -EFSCORRUPTED || error == -EFSBADCRC)
	if (error == -EFSCORRUPTED || error == -EFSBADCRC)
@@ -691,15 +697,22 @@ static void
xfs_sb_write_verify(
xfs_sb_write_verify(
	struct xfs_buf		*bp)
	struct xfs_buf		*bp)
{
{
	struct xfs_sb		sb;
	struct xfs_mount	*mp = bp->b_target->bt_mount;
	struct xfs_mount	*mp = bp->b_target->bt_mount;
	struct xfs_buf_log_item	*bip = bp->b_log_item;
	struct xfs_buf_log_item	*bip = bp->b_log_item;
	int			error;
	int			error;


	error = xfs_sb_verify(bp, false);
	/*
	if (error) {
	 * Check all the superblock fields.  Don't byteswap the xquota flags
		xfs_verifier_error(bp, error, __this_address);
	 * because _verify_common checks the on-disk values.
		return;
	 */
	}
	__xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp), false);
	error = xfs_validate_sb_common(mp, bp, &sb);
	if (error)
		goto out_error;
	error = xfs_validate_sb_write(mp, &sb);
	if (error)
		goto out_error;


	if (!xfs_sb_version_hascrc(&mp->m_sb))
	if (!xfs_sb_version_hascrc(&mp->m_sb))
		return;
		return;
@@ -708,6 +721,10 @@ xfs_sb_write_verify(
		XFS_BUF_TO_SBP(bp)->sb_lsn = cpu_to_be64(bip->bli_item.li_lsn);
		XFS_BUF_TO_SBP(bp)->sb_lsn = cpu_to_be64(bip->bli_item.li_lsn);


	xfs_buf_update_cksum(bp, XFS_SB_CRC_OFF);
	xfs_buf_update_cksum(bp, XFS_SB_CRC_OFF);
	return;

out_error:
	xfs_verifier_error(bp, error, __this_address);
}
}


const struct xfs_buf_ops xfs_sb_buf_ops = {
const struct xfs_buf_ops xfs_sb_buf_ops = {