Re: [PATCH 3/3] xfs: always log corruption errors

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, Nov 03, 2019 at 02:24:02PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
> 
> Make sure we log something to dmesg whenever we return -EFSCORRUPTED up
> the call stack.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>

Reviewed-by: Carlos Maiolino <cmaiolino@xxxxxxxxxx>

> ---
>  fs/xfs/libxfs/xfs_alloc.c      |    9 +++++++--
>  fs/xfs/libxfs/xfs_attr_leaf.c  |   12 +++++++++---
>  fs/xfs/libxfs/xfs_bmap.c       |    8 +++++++-
>  fs/xfs/libxfs/xfs_btree.c      |    5 ++++-
>  fs/xfs/libxfs/xfs_da_btree.c   |   24 ++++++++++++++++++------
>  fs/xfs/libxfs/xfs_dir2.c       |    4 +++-
>  fs/xfs/libxfs/xfs_dir2_leaf.c  |    4 +++-
>  fs/xfs/libxfs/xfs_dir2_node.c  |   12 +++++++++---
>  fs/xfs/libxfs/xfs_inode_fork.c |    6 ++++++
>  fs/xfs/libxfs/xfs_refcount.c   |    4 +++-
>  fs/xfs/libxfs/xfs_rtbitmap.c   |    6 ++++--
>  fs/xfs/xfs_acl.c               |   15 ++++++++++++---
>  fs/xfs/xfs_attr_inactive.c     |    6 +++++-
>  fs/xfs/xfs_attr_list.c         |    5 ++++-
>  fs/xfs/xfs_bmap_item.c         |    3 ++-
>  fs/xfs/xfs_error.c             |   21 +++++++++++++++++++++
>  fs/xfs/xfs_error.h             |    1 +
>  fs/xfs/xfs_extfree_item.c      |    3 ++-
>  fs/xfs/xfs_inode.c             |   15 ++++++++++++---
>  fs/xfs/xfs_inode_item.c        |    5 ++++-
>  fs/xfs/xfs_iops.c              |   10 +++++++---
>  fs/xfs/xfs_log_recover.c       |   23 ++++++++++++++++++-----
>  fs/xfs/xfs_qm.c                |   13 +++++++++++--
>  fs/xfs/xfs_refcount_item.c     |    3 ++-
>  fs/xfs/xfs_rmap_item.c         |    7 +++++--
>  25 files changed, 179 insertions(+), 45 deletions(-)
> 
> 
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index b8d48d5fa6a5..f7a4b54c5bc2 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -702,8 +702,10 @@ xfs_alloc_update_counters(
>  
>  	xfs_trans_agblocks_delta(tp, len);
>  	if (unlikely(be32_to_cpu(agf->agf_freeblks) >
> -		     be32_to_cpu(agf->agf_length)))
> +		     be32_to_cpu(agf->agf_length))) {
> +		xfs_buf_corruption_error(agbp);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS);
>  	return 0;
> @@ -1048,6 +1050,7 @@ xfs_alloc_ag_vextent_small(
>  
>  		bp = xfs_btree_get_bufs(args->mp, args->tp, args->agno, fbno);
>  		if (!bp) {
> +			XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, args->mp);
>  			error = -EFSCORRUPTED;
>  			goto error;
>  		}
> @@ -2215,8 +2218,10 @@ xfs_free_agfl_block(
>  		return error;
>  
>  	bp = xfs_btree_get_bufs(tp->t_mountp, tp, agno, agbno);
> -	if (!bp)
> +	if (!bp) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, tp->t_mountp);
>  		return -EFSCORRUPTED;
> +	}
>  	xfs_trans_binval(tp, bp);
>  
>  	return 0;
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 56e62b3d9bb7..dca8840496ea 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2346,8 +2346,10 @@ xfs_attr3_leaf_lookup_int(
>  	leaf = bp->b_addr;
>  	xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf);
>  	entries = xfs_attr3_leaf_entryp(leaf);
> -	if (ichdr.count >= args->geo->blksize / 8)
> +	if (ichdr.count >= args->geo->blksize / 8) {
> +		xfs_buf_corruption_error(bp);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	/*
>  	 * Binary search.  (note: small blocks will skip this loop)
> @@ -2363,10 +2365,14 @@ xfs_attr3_leaf_lookup_int(
>  		else
>  			break;
>  	}
> -	if (!(probe >= 0 && (!ichdr.count || probe < ichdr.count)))
> +	if (!(probe >= 0 && (!ichdr.count || probe < ichdr.count))) {
> +		xfs_buf_corruption_error(bp);
>  		return -EFSCORRUPTED;
> -	if (!(span <= 4 || be32_to_cpu(entry->hashval) == hashval))
> +	}
> +	if (!(span <= 4 || be32_to_cpu(entry->hashval) == hashval)) {
> +		xfs_buf_corruption_error(bp);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	/*
>  	 * Since we may have duplicate hashval's, find the first matching
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index bbabbb41e9d8..64f623d07f82 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -730,6 +730,7 @@ xfs_bmap_extents_to_btree(
>  	xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
>  	abp = xfs_btree_get_bufl(mp, tp, args.fsbno);
>  	if (!abp) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
>  		error = -EFSCORRUPTED;
>  		goto out_unreserve_dquot;
>  	}
> @@ -1085,6 +1086,7 @@ xfs_bmap_add_attrfork(
>  	if (XFS_IFORK_Q(ip))
>  		goto trans_cancel;
>  	if (ip->i_d.di_anextents != 0) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
>  		error = -EFSCORRUPTED;
>  		goto trans_cancel;
>  	}
> @@ -1338,6 +1340,7 @@ xfs_bmap_last_before(
>  	case XFS_DINODE_FMT_EXTENTS:
>  		break;
>  	default:
> +		ASSERT(0);
>  		return -EFSCORRUPTED;
>  	}
>  
> @@ -1438,8 +1441,10 @@ xfs_bmap_last_offset(
>  		return 0;
>  
>  	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
> -	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
> +	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) {
> +		ASSERT(0);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty);
>  	if (error || is_empty)
> @@ -5830,6 +5835,7 @@ xfs_bmap_insert_extents(
>  				del_cursor);
>  
>  	if (stop_fsb >= got.br_startoff + got.br_blockcount) {
> +		ASSERT(0);
>  		error = -EFSCORRUPTED;
>  		goto del_cursor;
>  	}
> diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
> index 4fd89c80c821..98843f1258b8 100644
> --- a/fs/xfs/libxfs/xfs_btree.c
> +++ b/fs/xfs/libxfs/xfs_btree.c
> @@ -1820,6 +1820,7 @@ xfs_btree_lookup_get_block(
>  
>  out_bad:
>  	*blkp = NULL;
> +	xfs_buf_corruption_error(bp);
>  	xfs_trans_brelse(cur->bc_tp, bp);
>  	return -EFSCORRUPTED;
>  }
> @@ -1867,8 +1868,10 @@ xfs_btree_lookup(
>  	XFS_BTREE_STATS_INC(cur, lookup);
>  
>  	/* No such thing as a zero-level tree. */
> -	if (cur->bc_nlevels == 0)
> +	if (cur->bc_nlevels == 0) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, cur->bc_mp);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	block = NULL;
>  	keyno = 0;
> diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
> index 4fd1223c1bd5..1e2dc65adeb8 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.c
> +++ b/fs/xfs/libxfs/xfs_da_btree.c
> @@ -504,6 +504,7 @@ xfs_da3_split(
>  	node = oldblk->bp->b_addr;
>  	if (node->hdr.info.forw) {
>  		if (be32_to_cpu(node->hdr.info.forw) != addblk->blkno) {
> +			xfs_buf_corruption_error(oldblk->bp);
>  			error = -EFSCORRUPTED;
>  			goto out;
>  		}
> @@ -516,6 +517,7 @@ xfs_da3_split(
>  	node = oldblk->bp->b_addr;
>  	if (node->hdr.info.back) {
>  		if (be32_to_cpu(node->hdr.info.back) != addblk->blkno) {
> +			xfs_buf_corruption_error(oldblk->bp);
>  			error = -EFSCORRUPTED;
>  			goto out;
>  		}
> @@ -1541,8 +1543,10 @@ xfs_da3_node_lookup_int(
>  			break;
>  		}
>  
> -		if (magic != XFS_DA_NODE_MAGIC && magic != XFS_DA3_NODE_MAGIC)
> +		if (magic != XFS_DA_NODE_MAGIC && magic != XFS_DA3_NODE_MAGIC) {
> +			xfs_buf_corruption_error(blk->bp);
>  			return -EFSCORRUPTED;
> +		}
>  
>  		blk->magic = XFS_DA_NODE_MAGIC;
>  
> @@ -1554,15 +1558,18 @@ xfs_da3_node_lookup_int(
>  		btree = dp->d_ops->node_tree_p(node);
>  
>  		/* Tree taller than we can handle; bail out! */
> -		if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
> +		if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
> +			xfs_buf_corruption_error(blk->bp);
>  			return -EFSCORRUPTED;
> +		}
>  
>  		/* Check the level from the root. */
>  		if (blkno == args->geo->leafblk)
>  			expected_level = nodehdr.level - 1;
> -		else if (expected_level != nodehdr.level)
> +		else if (expected_level != nodehdr.level) {
> +			xfs_buf_corruption_error(blk->bp);
>  			return -EFSCORRUPTED;
> -		else
> +		} else
>  			expected_level--;
>  
>  		max = nodehdr.count;
> @@ -1612,12 +1619,17 @@ xfs_da3_node_lookup_int(
>  		}
>  
>  		/* We can't point back to the root. */
> -		if (blkno == args->geo->leafblk)
> +		if (blkno == args->geo->leafblk) {
> +			XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW,
> +					dp->i_mount);
>  			return -EFSCORRUPTED;
> +		}
>  	}
>  
> -	if (expected_level != 0)
> +	if (expected_level != 0) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, dp->i_mount);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	/*
>  	 * A leaf block that ends in the hashval that we are interested in
> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
> index 867c5dee0751..452d04ae10ce 100644
> --- a/fs/xfs/libxfs/xfs_dir2.c
> +++ b/fs/xfs/libxfs/xfs_dir2.c
> @@ -600,8 +600,10 @@ xfs_dir2_isblock(
>  	if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
>  		return rval;
>  	rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
> -	if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize)
> +	if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, args->dp->i_mount);
>  		return -EFSCORRUPTED;
> +	}
>  	*vp = rval;
>  	return 0;
>  }
> diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
> index a53e4585a2f3..388b5da12228 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -1343,8 +1343,10 @@ xfs_dir2_leaf_removename(
>  	oldbest = be16_to_cpu(bf[0].length);
>  	ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
>  	bestsp = xfs_dir2_leaf_bests_p(ltp);
> -	if (be16_to_cpu(bestsp[db]) != oldbest)
> +	if (be16_to_cpu(bestsp[db]) != oldbest) {
> +		xfs_buf_corruption_error(lbp);
>  		return -EFSCORRUPTED;
> +	}
>  	/*
>  	 * Mark the former data entry unused.
>  	 */
> diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
> index 705c4f562758..72d7ed17eef5 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -373,8 +373,10 @@ xfs_dir2_leaf_to_node(
>  	leaf = lbp->b_addr;
>  	ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
>  	if (be32_to_cpu(ltp->bestcount) >
> -				(uint)dp->i_d.di_size / args->geo->blksize)
> +				(uint)dp->i_d.di_size / args->geo->blksize) {
> +		xfs_buf_corruption_error(lbp);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	/*
>  	 * Copy freespace entries from the leaf block to the new block.
> @@ -445,8 +447,10 @@ xfs_dir2_leafn_add(
>  	 * Quick check just to make sure we are not going to index
>  	 * into other peoples memory
>  	 */
> -	if (index < 0)
> +	if (index < 0) {
> +		xfs_buf_corruption_error(bp);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	/*
>  	 * If there are already the maximum number of leaf entries in
> @@ -739,8 +743,10 @@ xfs_dir2_leafn_lookup_for_entry(
>  	ents = dp->d_ops->leaf_ents_p(leaf);
>  
>  	xfs_dir3_leaf_check(dp, bp);
> -	if (leafhdr.count <= 0)
> +	if (leafhdr.count <= 0) {
> +		xfs_buf_corruption_error(bp);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	/*
>  	 * Look up the hash value in the leaf entries.
> diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
> index 8fdd0424070e..15d6f947620f 100644
> --- a/fs/xfs/libxfs/xfs_inode_fork.c
> +++ b/fs/xfs/libxfs/xfs_inode_fork.c
> @@ -75,11 +75,15 @@ xfs_iformat_fork(
>  			error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
>  			break;
>  		default:
> +			xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__,
> +					dip, sizeof(*dip), __this_address);
>  			return -EFSCORRUPTED;
>  		}
>  		break;
>  
>  	default:
> +		xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
> +				sizeof(*dip), __this_address);
>  		return -EFSCORRUPTED;
>  	}
>  	if (error)
> @@ -110,6 +114,8 @@ xfs_iformat_fork(
>  		error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK);
>  		break;
>  	default:
> +		xfs_inode_verifier_error(ip, error, __func__, dip,
> +				sizeof(*dip), __this_address);
>  		error = -EFSCORRUPTED;
>  		break;
>  	}
> diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
> index 9a7fadb1361c..78236bd6c64f 100644
> --- a/fs/xfs/libxfs/xfs_refcount.c
> +++ b/fs/xfs/libxfs/xfs_refcount.c
> @@ -1591,8 +1591,10 @@ xfs_refcount_recover_extent(
>  	struct list_head		*debris = priv;
>  	struct xfs_refcount_recovery	*rr;
>  
> -	if (be32_to_cpu(rec->refc.rc_refcount) != 1)
> +	if (be32_to_cpu(rec->refc.rc_refcount) != 1) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, cur->bc_mp);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	rr = kmem_alloc(sizeof(struct xfs_refcount_recovery), 0);
>  	xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec);
> diff --git a/fs/xfs/libxfs/xfs_rtbitmap.c b/fs/xfs/libxfs/xfs_rtbitmap.c
> index 8ea1efc97b41..d8aaa1de921c 100644
> --- a/fs/xfs/libxfs/xfs_rtbitmap.c
> +++ b/fs/xfs/libxfs/xfs_rtbitmap.c
> @@ -15,7 +15,7 @@
>  #include "xfs_bmap.h"
>  #include "xfs_trans.h"
>  #include "xfs_rtalloc.h"
> -
> +#include "xfs_error.h"
>  
>  /*
>   * Realtime allocator bitmap functions shared with userspace.
> @@ -70,8 +70,10 @@ xfs_rtbuf_get(
>  	if (error)
>  		return error;
>  
> -	if (nmap == 0 || !xfs_bmap_is_real_extent(&map))
> +	if (nmap == 0 || !xfs_bmap_is_real_extent(&map)) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	ASSERT(map.br_startblock != NULLFSBLOCK);
>  	error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
> index 96d7071cfa46..3f2292c7835c 100644
> --- a/fs/xfs/xfs_acl.c
> +++ b/fs/xfs/xfs_acl.c
> @@ -12,6 +12,7 @@
>  #include "xfs_inode.h"
>  #include "xfs_attr.h"
>  #include "xfs_trace.h"
> +#include "xfs_error.h"
>  #include <linux/posix_acl_xattr.h>
>  
>  
> @@ -23,6 +24,7 @@
>  
>  STATIC struct posix_acl *
>  xfs_acl_from_disk(
> +	struct xfs_mount	*mp,
>  	const struct xfs_acl	*aclp,
>  	int			len,
>  	int			max_entries)
> @@ -32,11 +34,18 @@ xfs_acl_from_disk(
>  	const struct xfs_acl_entry *ace;
>  	unsigned int count, i;
>  
> -	if (len < sizeof(*aclp))
> +	if (len < sizeof(*aclp)) {
> +		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, aclp,
> +				len);
>  		return ERR_PTR(-EFSCORRUPTED);
> +	}
> +
>  	count = be32_to_cpu(aclp->acl_cnt);
> -	if (count > max_entries || XFS_ACL_SIZE(count) != len)
> +	if (count > max_entries || XFS_ACL_SIZE(count) != len) {
> +		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, aclp,
> +				len);
>  		return ERR_PTR(-EFSCORRUPTED);
> +	}
>  
>  	acl = posix_acl_alloc(count, GFP_KERNEL);
>  	if (!acl)
> @@ -145,7 +154,7 @@ xfs_get_acl(struct inode *inode, int type)
>  		if (error != -ENOATTR)
>  			acl = ERR_PTR(error);
>  	} else  {
> -		acl = xfs_acl_from_disk(xfs_acl, len,
> +		acl = xfs_acl_from_disk(ip->i_mount, xfs_acl, len,
>  					XFS_ACL_MAX_ENTRIES(ip->i_mount));
>  		kmem_free(xfs_acl);
>  	}
> diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
> index f83f11d929e4..43ae392992e7 100644
> --- a/fs/xfs/xfs_attr_inactive.c
> +++ b/fs/xfs/xfs_attr_inactive.c
> @@ -22,6 +22,7 @@
>  #include "xfs_attr_leaf.h"
>  #include "xfs_quota.h"
>  #include "xfs_dir2.h"
> +#include "xfs_error.h"
>  
>  /*
>   * Look at all the extents for this logical region,
> @@ -209,6 +210,7 @@ xfs_attr3_node_inactive(
>  	 */
>  	if (level > XFS_DA_NODE_MAXDEPTH) {
>  		xfs_trans_brelse(*trans, bp);	/* no locks for later trans */
> +		xfs_buf_corruption_error(bp);
>  		return -EFSCORRUPTED;
>  	}
>  
> @@ -258,8 +260,9 @@ xfs_attr3_node_inactive(
>  			error = xfs_attr3_leaf_inactive(trans, dp, child_bp);
>  			break;
>  		default:
> -			error = -EFSCORRUPTED;
> +			xfs_buf_corruption_error(child_bp);
>  			xfs_trans_brelse(*trans, child_bp);
> +			error = -EFSCORRUPTED;
>  			break;
>  		}
>  		if (error)
> @@ -342,6 +345,7 @@ xfs_attr3_root_inactive(
>  		break;
>  	default:
>  		error = -EFSCORRUPTED;
> +		xfs_buf_corruption_error(bp);
>  		xfs_trans_brelse(*trans, bp);
>  		break;
>  	}
> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> index c02f22d50e45..64f6ceba9254 100644
> --- a/fs/xfs/xfs_attr_list.c
> +++ b/fs/xfs/xfs_attr_list.c
> @@ -269,8 +269,10 @@ xfs_attr_node_list_lookup(
>  			return 0;
>  
>  		/* We can't point back to the root. */
> -		if (cursor->blkno == 0)
> +		if (cursor->blkno == 0) {
> +			XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
>  			return -EFSCORRUPTED;
> +		}
>  	}
>  
>  	if (expected_level != 0)
> @@ -280,6 +282,7 @@ xfs_attr_node_list_lookup(
>  	return 0;
>  
>  out_corruptbuf:
> +	xfs_buf_corruption_error(bp);
>  	xfs_trans_brelse(tp, bp);
>  	return -EFSCORRUPTED;
>  }
> diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c
> index 83d24e983d4c..26c87fd9ac9f 100644
> --- a/fs/xfs/xfs_bmap_item.c
> +++ b/fs/xfs/xfs_bmap_item.c
> @@ -21,7 +21,7 @@
>  #include "xfs_icache.h"
>  #include "xfs_bmap_btree.h"
>  #include "xfs_trans_space.h"
> -
> +#include "xfs_error.h"
>  
>  kmem_zone_t	*xfs_bui_zone;
>  kmem_zone_t	*xfs_bud_zone;
> @@ -525,6 +525,7 @@ xfs_bui_recover(
>  		type = bui_type;
>  		break;
>  	default:
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
>  		error = -EFSCORRUPTED;
>  		goto err_inode;
>  	}
> diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
> index 0b156cc88108..d8cdb27fe6ed 100644
> --- a/fs/xfs/xfs_error.c
> +++ b/fs/xfs/xfs_error.c
> @@ -341,6 +341,27 @@ xfs_corruption_error(
>  	xfs_alert(mp, "Corruption detected. Unmount and run xfs_repair");
>  }
>  
> +/*
> + * Complain about the kinds of metadata corruption that we can't detect from a
> + * verifier, such as incorrect inter-block relationship data.  Does not set
> + * bp->b_error.
> + */
> +void
> +xfs_buf_corruption_error(
> +	struct xfs_buf		*bp)
> +{
> +	struct xfs_mount	*mp = bp->b_mount;
> +
> +	xfs_alert_tag(mp, XFS_PTAG_VERIFIER_ERROR,
> +		  "Metadata corruption detected at %pS, %s block 0x%llx",
> +		  __return_address, bp->b_ops->name, bp->b_bn);
> +
> +	xfs_alert(mp, "Unmount and run xfs_repair");
> +
> +	if (xfs_error_level >= XFS_ERRLEVEL_HIGH)
> +		xfs_stack_trace();
> +}
> +
>  /*
>   * Warnings specifically for verifier errors.  Differentiate CRC vs. invalid
>   * values, and omit the stack trace unless the error level is tuned high.
> diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h
> index e6a22cfb542f..c319379f7d1a 100644
> --- a/fs/xfs/xfs_error.h
> +++ b/fs/xfs/xfs_error.h
> @@ -15,6 +15,7 @@ extern void xfs_corruption_error(const char *tag, int level,
>  			struct xfs_mount *mp, const void *buf, size_t bufsize,
>  			const char *filename, int linenum,
>  			xfs_failaddr_t failaddr);
> +void xfs_buf_corruption_error(struct xfs_buf *bp);
>  extern void xfs_buf_verifier_error(struct xfs_buf *bp, int error,
>  			const char *name, const void *buf, size_t bufsz,
>  			xfs_failaddr_t failaddr);
> diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
> index e44efc41a041..a6f6acc8fbb7 100644
> --- a/fs/xfs/xfs_extfree_item.c
> +++ b/fs/xfs/xfs_extfree_item.c
> @@ -21,7 +21,7 @@
>  #include "xfs_alloc.h"
>  #include "xfs_bmap.h"
>  #include "xfs_trace.h"
> -
> +#include "xfs_error.h"
>  
>  kmem_zone_t	*xfs_efi_zone;
>  kmem_zone_t	*xfs_efd_zone;
> @@ -228,6 +228,7 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
>  		}
>  		return 0;
>  	}
> +	XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
>  	return -EFSCORRUPTED;
>  }
>  
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index e9e4f444f8ce..a92d4521748d 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2136,8 +2136,10 @@ xfs_iunlink_update_bucket(
>  	 * passed in because either we're adding or removing ourselves from the
>  	 * head of the list.
>  	 */
> -	if (old_value == new_agino)
> +	if (old_value == new_agino) {
> +		xfs_buf_corruption_error(agibp);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	agi->agi_unlinked[bucket_index] = cpu_to_be32(new_agino);
>  	offset = offsetof(struct xfs_agi, agi_unlinked) +
> @@ -2200,6 +2202,8 @@ xfs_iunlink_update_inode(
>  	/* Make sure the old pointer isn't garbage. */
>  	old_value = be32_to_cpu(dip->di_next_unlinked);
>  	if (!xfs_verify_agino_or_null(mp, agno, old_value)) {
> +		xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
> +				sizeof(*dip), __this_address);
>  		error = -EFSCORRUPTED;
>  		goto out;
>  	}
> @@ -2211,8 +2215,11 @@ xfs_iunlink_update_inode(
>  	 */
>  	*old_next_agino = old_value;
>  	if (old_value == next_agino) {
> -		if (next_agino != NULLAGINO)
> +		if (next_agino != NULLAGINO) {
> +			xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__,
> +					dip, sizeof(*dip), __this_address);
>  			error = -EFSCORRUPTED;
> +		}
>  		goto out;
>  	}
>  
> @@ -2263,8 +2270,10 @@ xfs_iunlink(
>  	 */
>  	next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
>  	if (next_agino == agino ||
> -	    !xfs_verify_agino_or_null(mp, agno, next_agino))
> +	    !xfs_verify_agino_or_null(mp, agno, next_agino)) {
> +		xfs_buf_corruption_error(agibp);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	if (next_agino != NULLAGINO) {
>  		struct xfs_perag	*pag;
> diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
> index bb8f076805b9..726aa3bfd6e8 100644
> --- a/fs/xfs/xfs_inode_item.c
> +++ b/fs/xfs/xfs_inode_item.c
> @@ -17,6 +17,7 @@
>  #include "xfs_trans_priv.h"
>  #include "xfs_buf_item.h"
>  #include "xfs_log.h"
> +#include "xfs_error.h"
>  
>  #include <linux/iversion.h>
>  
> @@ -828,8 +829,10 @@ xfs_inode_item_format_convert(
>  {
>  	struct xfs_inode_log_format_32	*in_f32 = buf->i_addr;
>  
> -	if (buf->i_len != sizeof(*in_f32))
> +	if (buf->i_len != sizeof(*in_f32)) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	in_f->ilf_type = in_f32->ilf_type;
>  	in_f->ilf_size = in_f32->ilf_size;
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 18e45e3a3f9f..4c7962ccb0c4 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -20,6 +20,7 @@
>  #include "xfs_symlink.h"
>  #include "xfs_dir2.h"
>  #include "xfs_iomap.h"
> +#include "xfs_error.h"
>  
>  #include <linux/xattr.h>
>  #include <linux/posix_acl.h>
> @@ -470,17 +471,20 @@ xfs_vn_get_link_inline(
>  	struct inode		*inode,
>  	struct delayed_call	*done)
>  {
> +	struct xfs_inode	*ip = XFS_I(inode);
>  	char			*link;
>  
> -	ASSERT(XFS_I(inode)->i_df.if_flags & XFS_IFINLINE);
> +	ASSERT(ip->i_df.if_flags & XFS_IFINLINE);
>  
>  	/*
>  	 * The VFS crashes on a NULL pointer, so return -EFSCORRUPTED if
>  	 * if_data is junk.
>  	 */
> -	link = XFS_I(inode)->i_df.if_u1.if_data;
> -	if (!link)
> +	link = ip->i_df.if_u1.if_data;
> +	if (!link) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, ip->i_mount);
>  		return ERR_PTR(-EFSCORRUPTED);
> +	}
>  	return link;
>  }
>  
> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
> index c1a514ffff55..648d5ecafd91 100644
> --- a/fs/xfs/xfs_log_recover.c
> +++ b/fs/xfs/xfs_log_recover.c
> @@ -3537,6 +3537,7 @@ xfs_cui_copy_format(
>  		memcpy(dst_cui_fmt, src_cui_fmt, len);
>  		return 0;
>  	}
> +	XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
>  	return -EFSCORRUPTED;
>  }
>  
> @@ -3601,8 +3602,10 @@ xlog_recover_cud_pass2(
>  	struct xfs_ail			*ailp = log->l_ailp;
>  
>  	cud_formatp = item->ri_buf[0].i_addr;
> -	if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format))
> +	if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format)) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
>  		return -EFSCORRUPTED;
> +	}
>  	cui_id = cud_formatp->cud_cui_id;
>  
>  	/*
> @@ -3654,6 +3657,7 @@ xfs_bui_copy_format(
>  		memcpy(dst_bui_fmt, src_bui_fmt, len);
>  		return 0;
>  	}
> +	XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
>  	return -EFSCORRUPTED;
>  }
>  
> @@ -3677,8 +3681,10 @@ xlog_recover_bui_pass2(
>  
>  	bui_formatp = item->ri_buf[0].i_addr;
>  
> -	if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS)
> +	if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
>  		return -EFSCORRUPTED;
> +	}
>  	buip = xfs_bui_init(mp);
>  	error = xfs_bui_copy_format(&item->ri_buf[0], &buip->bui_format);
>  	if (error) {
> @@ -3720,8 +3726,10 @@ xlog_recover_bud_pass2(
>  	struct xfs_ail			*ailp = log->l_ailp;
>  
>  	bud_formatp = item->ri_buf[0].i_addr;
> -	if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format))
> +	if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format)) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
>  		return -EFSCORRUPTED;
> +	}
>  	bui_id = bud_formatp->bud_bui_id;
>  
>  	/*
> @@ -5172,8 +5180,10 @@ xlog_recover_process(
>  		 * If the filesystem is CRC enabled, this mismatch becomes a
>  		 * fatal log corruption failure.
>  		 */
> -		if (xfs_sb_version_hascrc(&log->l_mp->m_sb))
> +		if (xfs_sb_version_hascrc(&log->l_mp->m_sb)) {
> +			XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
>  			return -EFSCORRUPTED;
> +		}
>  	}
>  
>  	xlog_unpack_data(rhead, dp, log);
> @@ -5296,8 +5306,11 @@ xlog_do_recovery_pass(
>  		"invalid iclog size (%d bytes), using lsunit (%d bytes)",
>  					 h_size, log->l_mp->m_logbsize);
>  				h_size = log->l_mp->m_logbsize;
> -			} else
> +			} else {
> +				XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW,
> +						log->l_mp);
>  				return -EFSCORRUPTED;
> +			}
>  		}
>  
>  		if ((be32_to_cpu(rhead->h_version) & XLOG_VERSION_2) &&
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index ecd8ce152ab1..66ea8e4fca86 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -22,6 +22,7 @@
>  #include "xfs_qm.h"
>  #include "xfs_trace.h"
>  #include "xfs_icache.h"
> +#include "xfs_error.h"
>  
>  /*
>   * The global quota manager. There is only one of these for the entire
> @@ -754,11 +755,19 @@ xfs_qm_qino_alloc(
>  		if ((flags & XFS_QMOPT_PQUOTA) &&
>  			     (mp->m_sb.sb_gquotino != NULLFSINO)) {
>  			ino = mp->m_sb.sb_gquotino;
> -			ASSERT(mp->m_sb.sb_pquotino == NULLFSINO);
> +			if (mp->m_sb.sb_pquotino != NULLFSINO) {
> +				XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW,
> +						mp);
> +				return -EFSCORRUPTED;
> +			}
>  		} else if ((flags & XFS_QMOPT_GQUOTA) &&
>  			     (mp->m_sb.sb_pquotino != NULLFSINO)) {
>  			ino = mp->m_sb.sb_pquotino;
> -			ASSERT(mp->m_sb.sb_gquotino == NULLFSINO);
> +			if (mp->m_sb.sb_gquotino != NULLFSINO) {
> +				XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW,
> +						mp);
> +				return -EFSCORRUPTED;
> +			}
>  		}
>  		if (ino != NULLFSINO) {
>  			error = xfs_iget(mp, NULL, ino, 0, 0, ip);
> diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c
> index 2328268e6245..576f59fe370e 100644
> --- a/fs/xfs/xfs_refcount_item.c
> +++ b/fs/xfs/xfs_refcount_item.c
> @@ -17,7 +17,7 @@
>  #include "xfs_refcount_item.h"
>  #include "xfs_log.h"
>  #include "xfs_refcount.h"
> -
> +#include "xfs_error.h"
>  
>  kmem_zone_t	*xfs_cui_zone;
>  kmem_zone_t	*xfs_cud_zone;
> @@ -536,6 +536,7 @@ xfs_cui_recover(
>  			type = refc_type;
>  			break;
>  		default:
> +			XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
>  			error = -EFSCORRUPTED;
>  			goto abort_error;
>  		}
> diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c
> index 8939e0ea09cd..1d72e4b3ebf1 100644
> --- a/fs/xfs/xfs_rmap_item.c
> +++ b/fs/xfs/xfs_rmap_item.c
> @@ -17,7 +17,7 @@
>  #include "xfs_rmap_item.h"
>  #include "xfs_log.h"
>  #include "xfs_rmap.h"
> -
> +#include "xfs_error.h"
>  
>  kmem_zone_t	*xfs_rui_zone;
>  kmem_zone_t	*xfs_rud_zone;
> @@ -171,8 +171,10 @@ xfs_rui_copy_format(
>  	src_rui_fmt = buf->i_addr;
>  	len = xfs_rui_log_format_sizeof(src_rui_fmt->rui_nextents);
>  
> -	if (buf->i_len != len)
> +	if (buf->i_len != len) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	memcpy(dst_rui_fmt, src_rui_fmt, len);
>  	return 0;
> @@ -581,6 +583,7 @@ xfs_rui_recover(
>  			type = XFS_RMAP_FREE;
>  			break;
>  		default:
> +			XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
>  			error = -EFSCORRUPTED;
>  			goto abort_error;
>  		}
> 

-- 
Carlos





[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux