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

xfs: complain about bad records in query_range helpers



For every btree type except for the bmbt, refactor the code that
complains about bad records into a helper and make the ->query_range
helpers call it so that corruptions found via that avenue are logged.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
parent 69010fe3
Loading
Loading
Loading
Loading
+23 −15
Original line number Diff line number Diff line
@@ -261,6 +261,24 @@ xfs_alloc_check_irec(
	return NULL;
}

static inline int
xfs_alloc_complain_bad_rec(
	struct xfs_btree_cur		*cur,
	xfs_failaddr_t			fa,
	const struct xfs_alloc_rec_incore *irec)
{
	struct xfs_mount		*mp = cur->bc_mp;

	xfs_warn(mp,
		"%s Freespace BTree record corruption in AG %d detected at %pS!",
		cur->bc_btnum == XFS_BTNUM_BNO ? "Block" : "Size",
		cur->bc_ag.pag->pag_agno, fa);
	xfs_warn(mp,
		"start block 0x%x block count 0x%x", irec->ar_startblock,
		irec->ar_blockcount);
	return -EFSCORRUPTED;
}

/*
 * Get the data from the pointed-to record.
 */
@@ -272,8 +290,6 @@ xfs_alloc_get_rec(
	int			*stat)	/* output: success/failure */
{
	struct xfs_alloc_rec_incore irec;
	struct xfs_mount	*mp = cur->bc_mp;
	struct xfs_perag	*pag = cur->bc_ag.pag;
	union xfs_btree_rec	*rec;
	xfs_failaddr_t		fa;
	int			error;
@@ -285,21 +301,11 @@ xfs_alloc_get_rec(
	xfs_alloc_btrec_to_irec(rec, &irec);
	fa = xfs_alloc_check_irec(cur, &irec);
	if (fa)
		goto out_bad_rec;
		return xfs_alloc_complain_bad_rec(cur, fa, &irec);

	*bno = irec.ar_startblock;
	*len = irec.ar_blockcount;
	return 0;

out_bad_rec:
	xfs_warn(mp,
		"%s Freespace BTree record corruption in AG %d detected at %pS!",
		cur->bc_btnum == XFS_BTNUM_BNO ? "Block" : "Size",
		pag->pag_agno, fa);
	xfs_warn(mp,
		"start block 0x%x block count 0x%x", irec.ar_startblock,
		irec.ar_blockcount);
	return -EFSCORRUPTED;
}

/*
@@ -3692,10 +3698,12 @@ xfs_alloc_query_range_helper(
{
	struct xfs_alloc_query_range_info	*query = priv;
	struct xfs_alloc_rec_incore		irec;
	xfs_failaddr_t				fa;

	xfs_alloc_btrec_to_irec(rec, &irec);
	if (xfs_alloc_check_irec(cur, &irec) != NULL)
		return -EFSCORRUPTED;
	fa = xfs_alloc_check_irec(cur, &irec);
	if (fa)
		return xfs_alloc_complain_bad_rec(cur, fa, &irec);

	return query->fn(cur, &irec, query->priv);
}
+24 −14
Original line number Diff line number Diff line
@@ -122,6 +122,25 @@ xfs_inobt_check_irec(
	return NULL;
}

static inline int
xfs_inobt_complain_bad_rec(
	struct xfs_btree_cur		*cur,
	xfs_failaddr_t			fa,
	const struct xfs_inobt_rec_incore *irec)
{
	struct xfs_mount		*mp = cur->bc_mp;

	xfs_warn(mp,
		"%s Inode BTree record corruption in AG %d detected at %pS!",
		cur->bc_btnum == XFS_BTNUM_INO ? "Used" : "Free",
		cur->bc_ag.pag->pag_agno, fa);
	xfs_warn(mp,
"start inode 0x%x, count 0x%x, free 0x%x freemask 0x%llx, holemask 0x%x",
		irec->ir_startino, irec->ir_count, irec->ir_freecount,
		irec->ir_free, irec->ir_holemask);
	return -EFSCORRUPTED;
}

/*
 * Get the data from the pointed-to record.
 */
@@ -143,20 +162,9 @@ xfs_inobt_get_rec(
	xfs_inobt_btrec_to_irec(mp, rec, irec);
	fa = xfs_inobt_check_irec(cur, irec);
	if (fa)
		goto out_bad_rec;
		return xfs_inobt_complain_bad_rec(cur, fa, irec);

	return 0;

out_bad_rec:
	xfs_warn(mp,
		"%s Inode BTree record corruption in AG %d detected at %pS!",
		cur->bc_btnum == XFS_BTNUM_INO ? "Used" : "Free",
		cur->bc_ag.pag->pag_agno, fa);
	xfs_warn(mp,
"start inode 0x%x, count 0x%x, free 0x%x freemask 0x%llx, holemask 0x%x",
		irec->ir_startino, irec->ir_count, irec->ir_freecount,
		irec->ir_free, irec->ir_holemask);
	return -EFSCORRUPTED;
}

/*
@@ -2702,10 +2710,12 @@ xfs_ialloc_count_inodes_rec(
{
	struct xfs_inobt_rec_incore	irec;
	struct xfs_ialloc_count_inodes	*ci = priv;
	xfs_failaddr_t			fa;

	xfs_inobt_btrec_to_irec(cur->bc_mp, rec, &irec);
	if (xfs_inobt_check_irec(cur, &irec) != NULL)
		return -EFSCORRUPTED;
	fa = xfs_inobt_check_irec(cur, &irec);
	if (fa)
		return xfs_inobt_complain_bad_rec(cur, fa, &irec);

	ci->count += irec.ir_count;
	ci->freecount += irec.ir_freecount;
+19 −13
Original line number Diff line number Diff line
@@ -144,6 +144,23 @@ xfs_refcount_check_irec(
	return NULL;
}

static inline int
xfs_refcount_complain_bad_rec(
	struct xfs_btree_cur		*cur,
	xfs_failaddr_t			fa,
	const struct xfs_refcount_irec	*irec)
{
	struct xfs_mount		*mp = cur->bc_mp;

	xfs_warn(mp,
 "Refcount BTree record corruption in AG %d detected at %pS!",
				cur->bc_ag.pag->pag_agno, fa);
	xfs_warn(mp,
		"Start block 0x%x, block count 0x%x, references 0x%x",
		irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount);
	return -EFSCORRUPTED;
}

/*
 * Get the data from the pointed-to record.
 */
@@ -153,8 +170,6 @@ xfs_refcount_get_rec(
	struct xfs_refcount_irec	*irec,
	int				*stat)
{
	struct xfs_mount		*mp = cur->bc_mp;
	struct xfs_perag		*pag = cur->bc_ag.pag;
	union xfs_btree_rec		*rec;
	xfs_failaddr_t			fa;
	int				error;
@@ -166,19 +181,10 @@ xfs_refcount_get_rec(
	xfs_refcount_btrec_to_irec(rec, irec);
	fa = xfs_refcount_check_irec(cur, irec);
	if (fa)
		goto out_bad_rec;
		return xfs_refcount_complain_bad_rec(cur, fa, irec);

	trace_xfs_refcount_get(cur->bc_mp, pag->pag_agno, irec);
	trace_xfs_refcount_get(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
	return 0;

out_bad_rec:
	xfs_warn(mp,
		"Refcount BTree record corruption in AG %d detected at %pS!",
		pag->pag_agno, fa);
	xfs_warn(mp,
		"Start block 0x%x, block count 0x%x, references 0x%x",
		irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount);
	return -EFSCORRUPTED;
}

/*
+25 −15
Original line number Diff line number Diff line
@@ -235,6 +235,24 @@ xfs_rmap_check_irec(
	return NULL;
}

static inline int
xfs_rmap_complain_bad_rec(
	struct xfs_btree_cur		*cur,
	xfs_failaddr_t			fa,
	const struct xfs_rmap_irec	*irec)
{
	struct xfs_mount		*mp = cur->bc_mp;

	xfs_warn(mp,
		"Reverse Mapping BTree record corruption in AG %d detected at %pS!",
		cur->bc_ag.pag->pag_agno, fa);
	xfs_warn(mp,
		"Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
		irec->rm_owner, irec->rm_flags, irec->rm_startblock,
		irec->rm_blockcount);
	return -EFSCORRUPTED;
}

/*
 * Get the data from the pointed-to record.
 */
@@ -244,8 +262,6 @@ xfs_rmap_get_rec(
	struct xfs_rmap_irec	*irec,
	int			*stat)
{
	struct xfs_mount	*mp = cur->bc_mp;
	struct xfs_perag	*pag = cur->bc_ag.pag;
	union xfs_btree_rec	*rec;
	xfs_failaddr_t		fa;
	int			error;
@@ -258,18 +274,9 @@ xfs_rmap_get_rec(
	if (!fa)
		fa = xfs_rmap_check_irec(cur, irec);
	if (fa)
		goto out_bad_rec;
		return xfs_rmap_complain_bad_rec(cur, fa, irec);

	return 0;
out_bad_rec:
	xfs_warn(mp,
		"Reverse Mapping BTree record corruption in AG %d detected at %pS!",
		pag->pag_agno, fa);
	xfs_warn(mp,
		"Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
		irec->rm_owner, irec->rm_flags, irec->rm_startblock,
		irec->rm_blockcount);
	return -EFSCORRUPTED;
}

struct xfs_find_left_neighbor_info {
@@ -2335,10 +2342,13 @@ xfs_rmap_query_range_helper(
{
	struct xfs_rmap_query_range_info	*query = priv;
	struct xfs_rmap_irec			irec;
	xfs_failaddr_t				fa;

	if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL ||
	    xfs_rmap_check_irec(cur, &irec) != NULL)
		return -EFSCORRUPTED;
	fa = xfs_rmap_btrec_to_irec(rec, &irec);
	if (!fa)
		fa = xfs_rmap_check_irec(cur, &irec);
	if (fa)
		return xfs_rmap_complain_bad_rec(cur, fa, &irec);

	return query->fn(cur, &irec, query->priv);
}