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

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

xfs: have buffer verifier functions report failing address



Modify each function that checks the contents of a metadata buffer to
return the instruction address of the failing test so that we can report
more precise failure errors to the log.

Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
parent 31ca03c9
Loading
Loading
Loading
Loading
+22 −21
Original line number Diff line number Diff line
@@ -520,7 +520,7 @@ xfs_alloc_fixup_trees(
	return 0;
}

static bool
static xfs_failaddr_t
xfs_agfl_verify(
	struct xfs_buf	*bp)
{
@@ -529,9 +529,9 @@ xfs_agfl_verify(
	int		i;

	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid))
		return false;
		return __this_address;
	if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
		return false;
		return __this_address;
	/*
	 * during growfs operations, the perag is not fully initialised,
	 * so we can't use it for any useful checking. growfs ensures we can't
@@ -539,16 +539,17 @@ xfs_agfl_verify(
	 * so we can detect and avoid this problem.
	 */
	if (bp->b_pag && be32_to_cpu(agfl->agfl_seqno) != bp->b_pag->pag_agno)
		return false;
		return __this_address;

	for (i = 0; i < XFS_AGFL_SIZE(mp); i++) {
		if (be32_to_cpu(agfl->agfl_bno[i]) != NULLAGBLOCK &&
		    be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks)
			return false;
			return __this_address;
	}

	return xfs_log_check_lsn(mp,
				 be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn));
	if (!xfs_log_check_lsn(mp, be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn)))
		return __this_address;
	return NULL;
}

static void
@@ -568,7 +569,7 @@ xfs_agfl_read_verify(

	if (!xfs_buf_verify_cksum(bp, XFS_AGFL_CRC_OFF))
		xfs_verifier_error(bp, -EFSBADCRC);
	else if (!xfs_agfl_verify(bp))
	else if (xfs_agfl_verify(bp))
		xfs_verifier_error(bp, -EFSCORRUPTED);
}

@@ -583,7 +584,7 @@ xfs_agfl_write_verify(
	if (!xfs_sb_version_hascrc(&mp->m_sb))
		return;

	if (!xfs_agfl_verify(bp)) {
	if (xfs_agfl_verify(bp)) {
		xfs_verifier_error(bp, -EFSCORRUPTED);
		return;
	}
@@ -2393,7 +2394,7 @@ xfs_alloc_put_freelist(
	return 0;
}

static bool
static xfs_failaddr_t
xfs_agf_verify(
	struct xfs_mount *mp,
	struct xfs_buf	*bp)
@@ -2402,10 +2403,10 @@ xfs_agf_verify(

	if (xfs_sb_version_hascrc(&mp->m_sb)) {
		if (!uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
			return false;
			return __this_address;
		if (!xfs_log_check_lsn(mp,
				be64_to_cpu(XFS_BUF_TO_AGF(bp)->agf_lsn)))
			return false;
			return __this_address;
	}

	if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
@@ -2414,18 +2415,18 @@ xfs_agf_verify(
	      be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) &&
	      be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) &&
	      be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
		return false;
		return __this_address;

	if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) < 1 ||
	    be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) < 1 ||
	    be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS ||
	    be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
		return false;
		return __this_address;

	if (xfs_sb_version_hasrmapbt(&mp->m_sb) &&
	    (be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) < 1 ||
	     be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) > XFS_BTREE_MAXLEVELS))
		return false;
		return __this_address;

	/*
	 * during growfs operations, the perag is not fully initialised,
@@ -2434,18 +2435,18 @@ xfs_agf_verify(
	 * so we can detect and avoid this problem.
	 */
	if (bp->b_pag && be32_to_cpu(agf->agf_seqno) != bp->b_pag->pag_agno)
		return false;
		return __this_address;

	if (xfs_sb_version_haslazysbcount(&mp->m_sb) &&
	    be32_to_cpu(agf->agf_btreeblks) > be32_to_cpu(agf->agf_length))
		return false;
		return __this_address;

	if (xfs_sb_version_hasreflink(&mp->m_sb) &&
	    (be32_to_cpu(agf->agf_refcount_level) < 1 ||
	     be32_to_cpu(agf->agf_refcount_level) > XFS_BTREE_MAXLEVELS))
		return false;
		return __this_address;

	return true;;
	return NULL;

}

@@ -2458,7 +2459,7 @@ xfs_agf_read_verify(
	if (xfs_sb_version_hascrc(&mp->m_sb) &&
	    !xfs_buf_verify_cksum(bp, XFS_AGF_CRC_OFF))
		xfs_verifier_error(bp, -EFSBADCRC);
	else if (XFS_TEST_ERROR(!xfs_agf_verify(mp, bp), mp,
	else if (XFS_TEST_ERROR(xfs_agf_verify(mp, bp), mp,
				XFS_ERRTAG_ALLOC_READ_AGF))
		xfs_verifier_error(bp, -EFSCORRUPTED);
}
@@ -2470,7 +2471,7 @@ xfs_agf_write_verify(
	struct xfs_mount *mp = bp->b_target->bt_mount;
	struct xfs_buf_log_item	*bip = bp->b_fspriv;

	if (!xfs_agf_verify(mp, bp)) {
	if (xfs_agf_verify(mp, bp)) {
		xfs_verifier_error(bp, -EFSCORRUPTED);
		return;
	}
+15 −12
Original line number Diff line number Diff line
@@ -307,13 +307,14 @@ xfs_cntbt_diff_two_keys(
		be32_to_cpu(k2->alloc.ar_startblock);
}

static bool
static xfs_failaddr_t
xfs_allocbt_verify(
	struct xfs_buf		*bp)
{
	struct xfs_mount	*mp = bp->b_target->bt_mount;
	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
	struct xfs_perag	*pag = bp->b_pag;
	xfs_failaddr_t		fa;
	unsigned int		level;

	/*
@@ -331,29 +332,31 @@ xfs_allocbt_verify(
	level = be16_to_cpu(block->bb_level);
	switch (block->bb_magic) {
	case cpu_to_be32(XFS_ABTB_CRC_MAGIC):
		if (!xfs_btree_sblock_v5hdr_verify(bp))
			return false;
		fa = xfs_btree_sblock_v5hdr_verify(bp);
		if (fa)
			return fa;
		/* fall through */
	case cpu_to_be32(XFS_ABTB_MAGIC):
		if (pag && pag->pagf_init) {
			if (level >= pag->pagf_levels[XFS_BTNUM_BNOi])
				return false;
				return __this_address;
		} else if (level >= mp->m_ag_maxlevels)
			return false;
			return __this_address;
		break;
	case cpu_to_be32(XFS_ABTC_CRC_MAGIC):
		if (!xfs_btree_sblock_v5hdr_verify(bp))
			return false;
		fa = xfs_btree_sblock_v5hdr_verify(bp);
		if (fa)
			return fa;
		/* fall through */
	case cpu_to_be32(XFS_ABTC_MAGIC):
		if (pag && pag->pagf_init) {
			if (level >= pag->pagf_levels[XFS_BTNUM_CNTi])
				return false;
				return __this_address;
		} else if (level >= mp->m_ag_maxlevels)
			return false;
			return __this_address;
		break;
	default:
		return false;
		return __this_address;
	}

	return xfs_btree_sblock_verify(bp, mp->m_alloc_mxr[level != 0]);
@@ -365,7 +368,7 @@ xfs_allocbt_read_verify(
{
	if (!xfs_btree_sblock_verify_crc(bp))
		xfs_verifier_error(bp, -EFSBADCRC);
	else if (!xfs_allocbt_verify(bp))
	else if (xfs_allocbt_verify(bp))
		xfs_verifier_error(bp, -EFSCORRUPTED);

	if (bp->b_error)
@@ -376,7 +379,7 @@ static void
xfs_allocbt_write_verify(
	struct xfs_buf	*bp)
{
	if (!xfs_allocbt_verify(bp)) {
	if (xfs_allocbt_verify(bp)) {
		trace_xfs_btree_corrupt(bp, _RET_IP_);
		xfs_verifier_error(bp, -EFSCORRUPTED);
		return;
+10 −10
Original line number Diff line number Diff line
@@ -247,7 +247,7 @@ xfs_attr3_leaf_hdr_to_disk(
	}
}

static bool
static xfs_failaddr_t
xfs_attr3_leaf_verify(
	struct xfs_buf		*bp)
{
@@ -262,17 +262,17 @@ xfs_attr3_leaf_verify(
		struct xfs_da3_node_hdr *hdr3 = bp->b_addr;

		if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC)
			return false;
			return __this_address;

		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
			return false;
			return __this_address;
		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
			return false;
			return __this_address;
		if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->info.lsn)))
			return false;
			return __this_address;
	} else {
		if (ichdr.magic != XFS_ATTR_LEAF_MAGIC)
			return false;
			return __this_address;
	}
	/*
	 * In recovery there is a transient state where count == 0 is valid
@@ -280,12 +280,12 @@ xfs_attr3_leaf_verify(
	 * if the attr didn't fit in shortform.
	 */
	if (pag && pag->pagf_init && ichdr.count == 0)
		return false;
		return __this_address;

	/* XXX: need to range check rest of attr header values */
	/* XXX: hash order check? */

	return true;
	return NULL;
}

static void
@@ -296,7 +296,7 @@ xfs_attr3_leaf_write_verify(
	struct xfs_buf_log_item	*bip = bp->b_fspriv;
	struct xfs_attr3_leaf_hdr *hdr3 = bp->b_addr;

	if (!xfs_attr3_leaf_verify(bp)) {
	if (xfs_attr3_leaf_verify(bp)) {
		xfs_verifier_error(bp, -EFSCORRUPTED);
		return;
	}
@@ -325,7 +325,7 @@ xfs_attr3_leaf_read_verify(
	if (xfs_sb_version_hascrc(&mp->m_sb) &&
	     !xfs_buf_verify_cksum(bp, XFS_ATTR3_LEAF_CRC_OFF))
		xfs_verifier_error(bp, -EFSBADCRC);
	else if (!xfs_attr3_leaf_verify(bp))
	else if (xfs_attr3_leaf_verify(bp))
		xfs_verifier_error(bp, -EFSCORRUPTED);
}

+18 −18
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ xfs_attr3_rmt_blocks(
 * does CRC, location and bounds checking, the unpacking function checks the
 * attribute parameters and owner.
 */
static bool
static xfs_failaddr_t
xfs_attr3_rmt_hdr_ok(
	void			*ptr,
	xfs_ino_t		ino,
@@ -76,19 +76,19 @@ xfs_attr3_rmt_hdr_ok(
	struct xfs_attr3_rmt_hdr *rmt = ptr;

	if (bno != be64_to_cpu(rmt->rm_blkno))
		return false;
		return __this_address;
	if (offset != be32_to_cpu(rmt->rm_offset))
		return false;
		return __this_address;
	if (size != be32_to_cpu(rmt->rm_bytes))
		return false;
		return __this_address;
	if (ino != be64_to_cpu(rmt->rm_owner))
		return false;
		return __this_address;

	/* ok */
	return true;
	return NULL;
}

static bool
static xfs_failaddr_t
xfs_attr3_rmt_verify(
	struct xfs_mount	*mp,
	void			*ptr,
@@ -98,22 +98,22 @@ xfs_attr3_rmt_verify(
	struct xfs_attr3_rmt_hdr *rmt = ptr;

	if (!xfs_sb_version_hascrc(&mp->m_sb))
		return false;
		return __this_address;
	if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
		return false;
		return __this_address;
	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
		return false;
		return __this_address;
	if (be64_to_cpu(rmt->rm_blkno) != bno)
		return false;
		return __this_address;
	if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
		return false;
		return __this_address;
	if (be32_to_cpu(rmt->rm_offset) +
				be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
		return false;
		return __this_address;
	if (rmt->rm_owner == 0)
		return false;
		return __this_address;

	return true;
	return NULL;
}

static void
@@ -140,7 +140,7 @@ xfs_attr3_rmt_read_verify(
			xfs_verifier_error(bp, -EFSBADCRC);
			return;
		}
		if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
		if (xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
			xfs_verifier_error(bp, -EFSCORRUPTED);
			return;
		}
@@ -175,7 +175,7 @@ xfs_attr3_rmt_write_verify(
	while (len > 0) {
		struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;

		if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
		if (xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
			xfs_verifier_error(bp, -EFSCORRUPTED);
			return;
		}
@@ -267,7 +267,7 @@ xfs_attr_rmtval_copyout(
		byte_cnt = min(*valuelen, byte_cnt);

		if (xfs_sb_version_hascrc(&mp->m_sb)) {
			if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset,
			if (xfs_attr3_rmt_hdr_ok(src, ino, *offset,
						  byte_cnt, bno)) {
				xfs_alert(mp,
"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
+9 −7
Original line number Diff line number Diff line
@@ -425,12 +425,13 @@ xfs_bmbt_diff_two_keys(
			  be64_to_cpu(k2->bmbt.br_startoff);
}

static bool
static xfs_failaddr_t
xfs_bmbt_verify(
	struct xfs_buf		*bp)
{
	struct xfs_mount	*mp = bp->b_target->bt_mount;
	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
	xfs_failaddr_t		fa;
	unsigned int		level;

	switch (block->bb_magic) {
@@ -439,13 +440,14 @@ xfs_bmbt_verify(
		 * XXX: need a better way of verifying the owner here. Right now
		 * just make sure there has been one set.
		 */
		if (!xfs_btree_lblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN))
			return false;
		fa = xfs_btree_lblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN);
		if (fa)
			return fa;
		/* fall through */
	case cpu_to_be32(XFS_BMAP_MAGIC):
		break;
	default:
		return false;
		return __this_address;
	}

	/*
@@ -457,7 +459,7 @@ xfs_bmbt_verify(
	 */
	level = be16_to_cpu(block->bb_level);
	if (level > max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1]))
		return false;
		return __this_address;

	return xfs_btree_lblock_verify(bp, mp->m_bmap_dmxr[level != 0]);
}
@@ -468,7 +470,7 @@ xfs_bmbt_read_verify(
{
	if (!xfs_btree_lblock_verify_crc(bp))
		xfs_verifier_error(bp, -EFSBADCRC);
	else if (!xfs_bmbt_verify(bp))
	else if (xfs_bmbt_verify(bp))
		xfs_verifier_error(bp, -EFSCORRUPTED);

	if (bp->b_error)
@@ -479,7 +481,7 @@ static void
xfs_bmbt_write_verify(
	struct xfs_buf	*bp)
{
	if (!xfs_bmbt_verify(bp)) {
	if (xfs_bmbt_verify(bp)) {
		trace_xfs_btree_corrupt(bp, _RET_IP_);
		xfs_verifier_error(bp, -EFSCORRUPTED);
		return;
Loading