linux-xfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] xfs: tidy up corruption reporting
@ 2019-11-03 22:23 Darrick J. Wong
  2019-11-03 22:23 ` [PATCH 1/3] xfs: relax shortform directory size checks Darrick J. Wong
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Darrick J. Wong @ 2019-11-03 22:23 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs

Hi all,

Linus requested that I audit the XFS code base to make sure that we
always log something to dmesg when returning EFSCORRUPTED or EFSBADCRC
to userspace.  These patches are the results of that audit.

The first three patches start by refactoring a few helper methods so
that in the third patch we always report something to dmesg whenever we
decide to return EFSCORRUPTED.

If you're going to start using this mess, you probably ought to just
pull from my git trees, which are linked below.

This has been lightly tested with fstests.  Enjoy!
Comments and questions are, as always, welcome.

--D

kernel git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=report-corruption

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/3] xfs: relax shortform directory size checks
  2019-11-03 22:23 [PATCH 0/3] xfs: tidy up corruption reporting Darrick J. Wong
@ 2019-11-03 22:23 ` Darrick J. Wong
  2019-11-04 15:22   ` Carlos Maiolino
  2019-11-04 19:23   ` Christoph Hellwig
  2019-11-03 22:23 ` [PATCH 2/3] xfs: constify the buffer pointer arguments to error functions Darrick J. Wong
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 12+ messages in thread
From: Darrick J. Wong @ 2019-11-03 22:23 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs

From: Darrick J. Wong <darrick.wong@oracle.com>

Each of the four functions that operate on shortform directories checks
that the directory's di_size is at least as large as the shortform
directory header.  This is now checked by the inode fork verifiers
(di_size is used to allocate if_bytes, and if_bytes is checked against
the header structure size) so we can turn these checks into ASSERTions.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_dir2_block.c |    8 +-------
 fs/xfs/libxfs/xfs_dir2_sf.c    |   32 ++++----------------------------
 2 files changed, 5 insertions(+), 35 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 49e4bc39e7bb..e1afa35141c5 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -1073,13 +1073,7 @@ xfs_dir2_sf_to_block(
 	mp = dp->i_mount;
 	ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK);
 	ASSERT(ifp->if_flags & XFS_IFINLINE);
-	/*
-	 * Bomb out if the shortform directory is way too short.
-	 */
-	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-		ASSERT(XFS_FORCED_SHUTDOWN(mp));
-		return -EIO;
-	}
+	ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
 
 	oldsfp = (xfs_dir2_sf_hdr_t *)ifp->if_u1.if_data;
 
diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index ae16ca7c422a..d6b164a2fe57 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -277,13 +277,7 @@ xfs_dir2_sf_addname(
 	ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT);
 	dp = args->dp;
 	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-	/*
-	 * Make sure the shortform value has some of its header.
-	 */
-	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-		return -EIO;
-	}
+	ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
 	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
 	ASSERT(dp->i_df.if_u1.if_data != NULL);
 	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
@@ -793,13 +787,7 @@ xfs_dir2_sf_lookup(
 	dp = args->dp;
 
 	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-	/*
-	 * Bail out if the directory is way too short.
-	 */
-	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-		return -EIO;
-	}
+	ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
 	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
 	ASSERT(dp->i_df.if_u1.if_data != NULL);
 	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
@@ -879,13 +867,7 @@ xfs_dir2_sf_removename(
 
 	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
 	oldsize = (int)dp->i_d.di_size;
-	/*
-	 * Bail out if the directory is way too short.
-	 */
-	if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-		return -EIO;
-	}
+	ASSERT(oldsize >= offsetof(struct xfs_dir2_sf_hdr, parent));
 	ASSERT(dp->i_df.if_bytes == oldsize);
 	ASSERT(dp->i_df.if_u1.if_data != NULL);
 	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
@@ -963,13 +945,7 @@ xfs_dir2_sf_replace(
 	dp = args->dp;
 
 	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-	/*
-	 * Bail out if the shortform directory is way too small.
-	 */
-	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-		return -EIO;
-	}
+	ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
 	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
 	ASSERT(dp->i_df.if_u1.if_data != NULL);
 	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/3] xfs: constify the buffer pointer arguments to error functions
  2019-11-03 22:23 [PATCH 0/3] xfs: tidy up corruption reporting Darrick J. Wong
  2019-11-03 22:23 ` [PATCH 1/3] xfs: relax shortform directory size checks Darrick J. Wong
@ 2019-11-03 22:23 ` Darrick J. Wong
  2019-11-04 15:44   ` Carlos Maiolino
  2019-11-04 19:25   ` Christoph Hellwig
  2019-11-03 22:24 ` [PATCH 3/3] xfs: always log corruption errors Darrick J. Wong
  2019-11-04 15:22 ` [PATCH 0/3] xfs: tidy up corruption reporting Christoph Hellwig
  3 siblings, 2 replies; 12+ messages in thread
From: Darrick J. Wong @ 2019-11-03 22:23 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs

From: Darrick J. Wong <darrick.wong@oracle.com>

Some of the xfs error message functions take a pointer to a buffer that
will be dumped to the system log.  The logging functions don't change
the contents, so constify all the parameters.  This enables the next
patch to ensure that we log bad metadata when we encounter it.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/xfs_error.c   |    6 +++---
 fs/xfs/xfs_error.h   |    6 +++---
 fs/xfs/xfs_message.c |    2 +-
 fs/xfs/xfs_message.h |    2 +-
 4 files changed, 8 insertions(+), 8 deletions(-)


diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index 849fd4476950..0b156cc88108 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -329,7 +329,7 @@ xfs_corruption_error(
 	const char		*tag,
 	int			level,
 	struct xfs_mount	*mp,
-	void			*buf,
+	const void		*buf,
 	size_t			bufsize,
 	const char		*filename,
 	int			linenum,
@@ -350,7 +350,7 @@ xfs_buf_verifier_error(
 	struct xfs_buf		*bp,
 	int			error,
 	const char		*name,
-	void			*buf,
+	const void		*buf,
 	size_t			bufsz,
 	xfs_failaddr_t		failaddr)
 {
@@ -402,7 +402,7 @@ xfs_inode_verifier_error(
 	struct xfs_inode	*ip,
 	int			error,
 	const char		*name,
-	void			*buf,
+	const void		*buf,
 	size_t			bufsz,
 	xfs_failaddr_t		failaddr)
 {
diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h
index 602aa7d62b66..e6a22cfb542f 100644
--- a/fs/xfs/xfs_error.h
+++ b/fs/xfs/xfs_error.h
@@ -12,16 +12,16 @@ extern void xfs_error_report(const char *tag, int level, struct xfs_mount *mp,
 			const char *filename, int linenum,
 			xfs_failaddr_t failaddr);
 extern void xfs_corruption_error(const char *tag, int level,
-			struct xfs_mount *mp, void *buf, size_t bufsize,
+			struct xfs_mount *mp, const void *buf, size_t bufsize,
 			const char *filename, int linenum,
 			xfs_failaddr_t failaddr);
 extern void xfs_buf_verifier_error(struct xfs_buf *bp, int error,
-			const char *name, void *buf, size_t bufsz,
+			const char *name, const void *buf, size_t bufsz,
 			xfs_failaddr_t failaddr);
 extern void xfs_verifier_error(struct xfs_buf *bp, int error,
 			xfs_failaddr_t failaddr);
 extern void xfs_inode_verifier_error(struct xfs_inode *ip, int error,
-			const char *name, void *buf, size_t bufsz,
+			const char *name, const void *buf, size_t bufsz,
 			xfs_failaddr_t failaddr);
 
 #define	XFS_ERROR_REPORT(e, lvl, mp)	\
diff --git a/fs/xfs/xfs_message.c b/fs/xfs/xfs_message.c
index 9804efe525a9..c57e8ad39712 100644
--- a/fs/xfs/xfs_message.c
+++ b/fs/xfs/xfs_message.c
@@ -105,7 +105,7 @@ assfail(char *expr, char *file, int line)
 }
 
 void
-xfs_hex_dump(void *p, int length)
+xfs_hex_dump(const void *p, int length)
 {
 	print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_OFFSET, 16, 1, p, length, 1);
 }
diff --git a/fs/xfs/xfs_message.h b/fs/xfs/xfs_message.h
index 34447dca97d1..7f040b04b739 100644
--- a/fs/xfs/xfs_message.h
+++ b/fs/xfs/xfs_message.h
@@ -60,6 +60,6 @@ do {									\
 extern void assfail(char *expr, char *f, int l);
 extern void asswarn(char *expr, char *f, int l);
 
-extern void xfs_hex_dump(void *p, int length);
+extern void xfs_hex_dump(const void *p, int length);
 
 #endif	/* __XFS_MESSAGE_H */


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/3] xfs: always log corruption errors
  2019-11-03 22:23 [PATCH 0/3] xfs: tidy up corruption reporting Darrick J. Wong
  2019-11-03 22:23 ` [PATCH 1/3] xfs: relax shortform directory size checks Darrick J. Wong
  2019-11-03 22:23 ` [PATCH 2/3] xfs: constify the buffer pointer arguments to error functions Darrick J. Wong
@ 2019-11-03 22:24 ` Darrick J. Wong
  2019-11-04 15:44   ` Carlos Maiolino
  2019-11-04 19:26   ` Christoph Hellwig
  2019-11-04 15:22 ` [PATCH 0/3] xfs: tidy up corruption reporting Christoph Hellwig
  3 siblings, 2 replies; 12+ messages in thread
From: Darrick J. Wong @ 2019-11-03 22:24 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs

From: Darrick J. Wong <darrick.wong@oracle.com>

Make sure we log something to dmesg whenever we return -EFSCORRUPTED up
the call stack.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 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;
 		}


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/3] xfs: tidy up corruption reporting
  2019-11-03 22:23 [PATCH 0/3] xfs: tidy up corruption reporting Darrick J. Wong
                   ` (2 preceding siblings ...)
  2019-11-03 22:24 ` [PATCH 3/3] xfs: always log corruption errors Darrick J. Wong
@ 2019-11-04 15:22 ` Christoph Hellwig
  2019-11-04 16:34   ` Darrick J. Wong
  3 siblings, 1 reply; 12+ messages in thread
From: Christoph Hellwig @ 2019-11-04 15:22 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Sun, Nov 03, 2019 at 02:23:43PM -0800, Darrick J. Wong wrote:
> Hi all,
> 
> Linus requested that I audit the XFS code base to make sure that we
> always log something to dmesg when returning EFSCORRUPTED or EFSBADCRC
> to userspace.  These patches are the results of that audit.

Do you have a reference to that discussion?

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] xfs: relax shortform directory size checks
  2019-11-03 22:23 ` [PATCH 1/3] xfs: relax shortform directory size checks Darrick J. Wong
@ 2019-11-04 15:22   ` Carlos Maiolino
  2019-11-04 19:23   ` Christoph Hellwig
  1 sibling, 0 replies; 12+ messages in thread
From: Carlos Maiolino @ 2019-11-04 15:22 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Sun, Nov 03, 2019 at 02:23:49PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Each of the four functions that operate on shortform directories checks
> that the directory's di_size is at least as large as the shortform
> directory header.  This is now checked by the inode fork verifiers
> (di_size is used to allocate if_bytes, and if_bytes is checked against
> the header structure size) so we can turn these checks into ASSERTions.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>

Looks good:

Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>


> ---
>  fs/xfs/libxfs/xfs_dir2_block.c |    8 +-------
>  fs/xfs/libxfs/xfs_dir2_sf.c    |   32 ++++----------------------------
>  2 files changed, 5 insertions(+), 35 deletions(-)
> 
> 
> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index 49e4bc39e7bb..e1afa35141c5 100644
> --- a/fs/xfs/libxfs/xfs_dir2_block.c
> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> @@ -1073,13 +1073,7 @@ xfs_dir2_sf_to_block(
>  	mp = dp->i_mount;
>  	ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK);
>  	ASSERT(ifp->if_flags & XFS_IFINLINE);
> -	/*
> -	 * Bomb out if the shortform directory is way too short.
> -	 */
> -	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
> -		ASSERT(XFS_FORCED_SHUTDOWN(mp));
> -		return -EIO;
> -	}
> +	ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
>  
>  	oldsfp = (xfs_dir2_sf_hdr_t *)ifp->if_u1.if_data;
>  
> diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
> index ae16ca7c422a..d6b164a2fe57 100644
> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
> @@ -277,13 +277,7 @@ xfs_dir2_sf_addname(
>  	ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT);
>  	dp = args->dp;
>  	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
> -	/*
> -	 * Make sure the shortform value has some of its header.
> -	 */
> -	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
> -		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
> -		return -EIO;
> -	}
> +	ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
>  	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
>  	ASSERT(dp->i_df.if_u1.if_data != NULL);
>  	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
> @@ -793,13 +787,7 @@ xfs_dir2_sf_lookup(
>  	dp = args->dp;
>  
>  	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
> -	/*
> -	 * Bail out if the directory is way too short.
> -	 */
> -	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
> -		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
> -		return -EIO;
> -	}
> +	ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
>  	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
>  	ASSERT(dp->i_df.if_u1.if_data != NULL);
>  	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
> @@ -879,13 +867,7 @@ xfs_dir2_sf_removename(
>  
>  	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
>  	oldsize = (int)dp->i_d.di_size;
> -	/*
> -	 * Bail out if the directory is way too short.
> -	 */
> -	if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) {
> -		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
> -		return -EIO;
> -	}
> +	ASSERT(oldsize >= offsetof(struct xfs_dir2_sf_hdr, parent));
>  	ASSERT(dp->i_df.if_bytes == oldsize);
>  	ASSERT(dp->i_df.if_u1.if_data != NULL);
>  	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
> @@ -963,13 +945,7 @@ xfs_dir2_sf_replace(
>  	dp = args->dp;
>  
>  	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
> -	/*
> -	 * Bail out if the shortform directory is way too small.
> -	 */
> -	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
> -		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
> -		return -EIO;
> -	}
> +	ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
>  	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
>  	ASSERT(dp->i_df.if_u1.if_data != NULL);
>  	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
> 

-- 
Carlos


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] xfs: constify the buffer pointer arguments to error functions
  2019-11-03 22:23 ` [PATCH 2/3] xfs: constify the buffer pointer arguments to error functions Darrick J. Wong
@ 2019-11-04 15:44   ` Carlos Maiolino
  2019-11-04 19:25   ` Christoph Hellwig
  1 sibling, 0 replies; 12+ messages in thread
From: Carlos Maiolino @ 2019-11-04 15:44 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Sun, Nov 03, 2019 at 02:23:55PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Some of the xfs error message functions take a pointer to a buffer that
> will be dumped to the system log.  The logging functions don't change
> the contents, so constify all the parameters.  This enables the next
> patch to ensure that we log bad metadata when we encounter it.
> 

Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>

> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/xfs_error.c   |    6 +++---
>  fs/xfs/xfs_error.h   |    6 +++---
>  fs/xfs/xfs_message.c |    2 +-
>  fs/xfs/xfs_message.h |    2 +-
>  4 files changed, 8 insertions(+), 8 deletions(-)
> 
> 
> diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
> index 849fd4476950..0b156cc88108 100644
> --- a/fs/xfs/xfs_error.c
> +++ b/fs/xfs/xfs_error.c
> @@ -329,7 +329,7 @@ xfs_corruption_error(
>  	const char		*tag,
>  	int			level,
>  	struct xfs_mount	*mp,
> -	void			*buf,
> +	const void		*buf,
>  	size_t			bufsize,
>  	const char		*filename,
>  	int			linenum,
> @@ -350,7 +350,7 @@ xfs_buf_verifier_error(
>  	struct xfs_buf		*bp,
>  	int			error,
>  	const char		*name,
> -	void			*buf,
> +	const void		*buf,
>  	size_t			bufsz,
>  	xfs_failaddr_t		failaddr)
>  {
> @@ -402,7 +402,7 @@ xfs_inode_verifier_error(
>  	struct xfs_inode	*ip,
>  	int			error,
>  	const char		*name,
> -	void			*buf,
> +	const void		*buf,
>  	size_t			bufsz,
>  	xfs_failaddr_t		failaddr)
>  {
> diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h
> index 602aa7d62b66..e6a22cfb542f 100644
> --- a/fs/xfs/xfs_error.h
> +++ b/fs/xfs/xfs_error.h
> @@ -12,16 +12,16 @@ extern void xfs_error_report(const char *tag, int level, struct xfs_mount *mp,
>  			const char *filename, int linenum,
>  			xfs_failaddr_t failaddr);
>  extern void xfs_corruption_error(const char *tag, int level,
> -			struct xfs_mount *mp, void *buf, size_t bufsize,
> +			struct xfs_mount *mp, const void *buf, size_t bufsize,
>  			const char *filename, int linenum,
>  			xfs_failaddr_t failaddr);
>  extern void xfs_buf_verifier_error(struct xfs_buf *bp, int error,
> -			const char *name, void *buf, size_t bufsz,
> +			const char *name, const void *buf, size_t bufsz,
>  			xfs_failaddr_t failaddr);
>  extern void xfs_verifier_error(struct xfs_buf *bp, int error,
>  			xfs_failaddr_t failaddr);
>  extern void xfs_inode_verifier_error(struct xfs_inode *ip, int error,
> -			const char *name, void *buf, size_t bufsz,
> +			const char *name, const void *buf, size_t bufsz,
>  			xfs_failaddr_t failaddr);
>  
>  #define	XFS_ERROR_REPORT(e, lvl, mp)	\
> diff --git a/fs/xfs/xfs_message.c b/fs/xfs/xfs_message.c
> index 9804efe525a9..c57e8ad39712 100644
> --- a/fs/xfs/xfs_message.c
> +++ b/fs/xfs/xfs_message.c
> @@ -105,7 +105,7 @@ assfail(char *expr, char *file, int line)
>  }
>  
>  void
> -xfs_hex_dump(void *p, int length)
> +xfs_hex_dump(const void *p, int length)
>  {
>  	print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_OFFSET, 16, 1, p, length, 1);
>  }
> diff --git a/fs/xfs/xfs_message.h b/fs/xfs/xfs_message.h
> index 34447dca97d1..7f040b04b739 100644
> --- a/fs/xfs/xfs_message.h
> +++ b/fs/xfs/xfs_message.h
> @@ -60,6 +60,6 @@ do {									\
>  extern void assfail(char *expr, char *f, int l);
>  extern void asswarn(char *expr, char *f, int l);
>  
> -extern void xfs_hex_dump(void *p, int length);
> +extern void xfs_hex_dump(const void *p, int length);
>  
>  #endif	/* __XFS_MESSAGE_H */
> 

-- 
Carlos


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/3] xfs: always log corruption errors
  2019-11-03 22:24 ` [PATCH 3/3] xfs: always log corruption errors Darrick J. Wong
@ 2019-11-04 15:44   ` Carlos Maiolino
  2019-11-04 19:26   ` Christoph Hellwig
  1 sibling, 0 replies; 12+ messages in thread
From: Carlos Maiolino @ 2019-11-04 15:44 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

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

Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>

> ---
>  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


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/3] xfs: tidy up corruption reporting
  2019-11-04 15:22 ` [PATCH 0/3] xfs: tidy up corruption reporting Christoph Hellwig
@ 2019-11-04 16:34   ` Darrick J. Wong
  0 siblings, 0 replies; 12+ messages in thread
From: Darrick J. Wong @ 2019-11-04 16:34 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-xfs

On Mon, Nov 04, 2019 at 07:22:22AM -0800, Christoph Hellwig wrote:
> On Sun, Nov 03, 2019 at 02:23:43PM -0800, Darrick J. Wong wrote:
> > Hi all,
> > 
> > Linus requested that I audit the XFS code base to make sure that we
> > always log something to dmesg when returning EFSCORRUPTED or EFSBADCRC
> > to userspace.  These patches are the results of that audit.
> 
> Do you have a reference to that discussion?

https://lore.kernel.org/linux-xfs/CAHk-=wiHuHLK49LKQhtERXaq0OYUnug4DJZFLPq9RHEG2Cm+bQ@mail.gmail.com/

--D

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] xfs: relax shortform directory size checks
  2019-11-03 22:23 ` [PATCH 1/3] xfs: relax shortform directory size checks Darrick J. Wong
  2019-11-04 15:22   ` Carlos Maiolino
@ 2019-11-04 19:23   ` Christoph Hellwig
  1 sibling, 0 replies; 12+ messages in thread
From: Christoph Hellwig @ 2019-11-04 19:23 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Sun, Nov 03, 2019 at 02:23:49PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Each of the four functions that operate on shortform directories checks
> that the directory's di_size is at least as large as the shortform
> directory header.  This is now checked by the inode fork verifiers
> (di_size is used to allocate if_bytes, and if_bytes is checked against
> the header structure size) so we can turn these checks into ASSERTions.

Looks fine:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] xfs: constify the buffer pointer arguments to error functions
  2019-11-03 22:23 ` [PATCH 2/3] xfs: constify the buffer pointer arguments to error functions Darrick J. Wong
  2019-11-04 15:44   ` Carlos Maiolino
@ 2019-11-04 19:25   ` Christoph Hellwig
  1 sibling, 0 replies; 12+ messages in thread
From: Christoph Hellwig @ 2019-11-04 19:25 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Sun, Nov 03, 2019 at 02:23:55PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Some of the xfs error message functions take a pointer to a buffer that
> will be dumped to the system log.  The logging functions don't change
> the contents, so constify all the parameters.  This enables the next
> patch to ensure that we log bad metadata when we encounter it.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/3] xfs: always log corruption errors
  2019-11-03 22:24 ` [PATCH 3/3] xfs: always log corruption errors Darrick J. Wong
  2019-11-04 15:44   ` Carlos Maiolino
@ 2019-11-04 19:26   ` Christoph Hellwig
  1 sibling, 0 replies; 12+ messages in thread
From: Christoph Hellwig @ 2019-11-04 19:26 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

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

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2019-11-04 19:26 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-03 22:23 [PATCH 0/3] xfs: tidy up corruption reporting Darrick J. Wong
2019-11-03 22:23 ` [PATCH 1/3] xfs: relax shortform directory size checks Darrick J. Wong
2019-11-04 15:22   ` Carlos Maiolino
2019-11-04 19:23   ` Christoph Hellwig
2019-11-03 22:23 ` [PATCH 2/3] xfs: constify the buffer pointer arguments to error functions Darrick J. Wong
2019-11-04 15:44   ` Carlos Maiolino
2019-11-04 19:25   ` Christoph Hellwig
2019-11-03 22:24 ` [PATCH 3/3] xfs: always log corruption errors Darrick J. Wong
2019-11-04 15:44   ` Carlos Maiolino
2019-11-04 19:26   ` Christoph Hellwig
2019-11-04 15:22 ` [PATCH 0/3] xfs: tidy up corruption reporting Christoph Hellwig
2019-11-04 16:34   ` Darrick J. Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).