Skip to content

Commit

Permalink
xfs: always log corruption errors
Browse files Browse the repository at this point in the history
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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
  • Loading branch information
Darrick J. Wong committed Nov 4, 2019
1 parent d243b89 commit a5155b8
Showing 25 changed files with 179 additions and 45 deletions.
9 changes: 7 additions & 2 deletions fs/xfs/libxfs/xfs_alloc.c
Original file line number Diff line number Diff line change
@@ -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;
12 changes: 9 additions & 3 deletions fs/xfs/libxfs/xfs_attr_leaf.c
Original file line number Diff line number Diff line change
@@ -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
8 changes: 7 additions & 1 deletion fs/xfs/libxfs/xfs_bmap.c
Original file line number Diff line number Diff line change
@@ -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;
}
5 changes: 4 additions & 1 deletion fs/xfs/libxfs/xfs_btree.c
Original file line number Diff line number Diff line change
@@ -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;
24 changes: 18 additions & 6 deletions fs/xfs/libxfs/xfs_da_btree.c
Original file line number Diff line number Diff line change
@@ -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
4 changes: 3 additions & 1 deletion fs/xfs/libxfs/xfs_dir2.c
Original file line number Diff line number Diff line change
@@ -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;
}
4 changes: 3 additions & 1 deletion fs/xfs/libxfs/xfs_dir2_leaf.c
Original file line number Diff line number Diff line change
@@ -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.
*/
12 changes: 9 additions & 3 deletions fs/xfs/libxfs/xfs_dir2_node.c
Original file line number Diff line number Diff line change
@@ -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.
6 changes: 6 additions & 0 deletions fs/xfs/libxfs/xfs_inode_fork.c
Original file line number Diff line number Diff line change
@@ -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;
}
4 changes: 3 additions & 1 deletion fs/xfs/libxfs/xfs_refcount.c
Original file line number Diff line number Diff line change
@@ -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);
6 changes: 4 additions & 2 deletions fs/xfs/libxfs/xfs_rtbitmap.c
Original file line number Diff line number Diff line change
@@ -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,
15 changes: 12 additions & 3 deletions fs/xfs/xfs_acl.c
Original file line number Diff line number Diff line change
@@ -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);
}
6 changes: 5 additions & 1 deletion fs/xfs/xfs_attr_inactive.c
Original file line number Diff line number Diff line change
@@ -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;
}
Loading

0 comments on commit a5155b8

Please sign in to comment.