xfs: set and validate dir/attr block owners [v30.3 06/16]

There are a couple of significant changes that need to be made to the
 directory and xattr code before we can support online repairs of those
 data structures.
 
 The first change is because online repair is designed to use libxfs to
 create a replacement dir/xattr structure in a temporary file, and use
 atomic extent swapping to commit the corrected structure.  To avoid the
 performance hit of walking every block of the new structure to rewrite
 the owner number before the swap, we instead change libxfs to allow
 callers of the dir and xattr code the ability to set an explicit owner
 number to be written into the header fields of any new blocks that are
 created.  For regular operation this will be the directory inode number.
 
 The second change is to update the dir/xattr code to actually *check*
 the owner number in each block that is read off the disk, since we don't
 currently do that.
 
 This has been running on the djcloud for months with no problems.  Enjoy!
 
 Signed-off-by: Darrick J. Wong <djwong@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQ2qTKExjcn+O1o2YRKO3ySh0YRpgUCZh23UwAKCRBKO3ySh0YR
 po6LAQD4r4tzS1xMNW/ynLntzLNiYukkjI8uGpHw1tPpwmskKQD8Dw+bmGQPjUUR
 v62p5rUNcinvgxwdJwBcsOERGlVkIww=
 =6MPB
 -----END PGP SIGNATURE-----

Merge tag 'dirattr-validate-owners-6.10_2024-04-15' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.10-mergeA

xfs: set and validate dir/attr block owners

There are a couple of significant changes that need to be made to the
directory and xattr code before we can support online repairs of those
data structures.

The first change is because online repair is designed to use libxfs to
create a replacement dir/xattr structure in a temporary file, and use
atomic extent swapping to commit the corrected structure.  To avoid the
performance hit of walking every block of the new structure to rewrite
the owner number before the swap, we instead change libxfs to allow
callers of the dir and xattr code the ability to set an explicit owner
number to be written into the header fields of any new blocks that are
created.  For regular operation this will be the directory inode number.

The second change is to update the dir/xattr code to actually *check*
the owner number in each block that is read off the disk, since we don't
currently do that.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>

* tag 'dirattr-validate-owners-6.10_2024-04-15' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux:
  xfs: validate explicit directory free block owners
  xfs: validate explicit directory block buffer owners
  xfs: validate explicit directory data buffer owners
  xfs: validate directory leaf buffer owners
  xfs: validate dabtree node buffer owners
  xfs: validate attr remote value buffer owners
  xfs: validate attr leaf buffer owners
  xfs: reduce indenting in xfs_attr_node_list
  xfs: use the xfs_da_args owner field to set new dir/attr block owner
  xfs: add an explicit owner field to xfs_da_args
This commit is contained in:
Chandan Babu R 2024-04-16 11:48:46 +05:30
commit fb1f7c662c
23 changed files with 492 additions and 148 deletions

View File

@ -264,6 +264,8 @@ xfs_attr_get(
if (xfs_is_shutdown(args->dp->i_mount))
return -EIO;
if (!args->owner)
args->owner = args->dp->i_ino;
args->geo = args->dp->i_mount->m_attr_geo;
args->whichfork = XFS_ATTR_FORK;
args->hashval = xfs_da_hashname(args->name, args->namelen);
@ -647,8 +649,8 @@ xfs_attr_leaf_remove_attr(
int forkoff;
int error;
error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
&bp);
error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
args->blkno, &bp);
if (error)
return error;
@ -679,7 +681,7 @@ xfs_attr_leaf_shrink(
if (!xfs_attr_is_leaf(dp))
return 0;
error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);
if (error)
return error;
@ -937,6 +939,8 @@ xfs_attr_set(
if (error)
return error;
if (!args->owner)
args->owner = args->dp->i_ino;
args->geo = mp->m_attr_geo;
args->whichfork = XFS_ATTR_FORK;
args->hashval = xfs_da_hashname(args->name, args->namelen);
@ -1154,7 +1158,7 @@ xfs_attr_leaf_try_add(
struct xfs_buf *bp;
int error;
error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);
if (error)
return error;
@ -1202,7 +1206,7 @@ xfs_attr_leaf_hasname(
{
int error = 0;
error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp);
error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, bp);
if (error)
return error;

View File

@ -388,6 +388,27 @@ xfs_attr3_leaf_verify(
return NULL;
}
xfs_failaddr_t
xfs_attr3_leaf_header_check(
struct xfs_buf *bp,
xfs_ino_t owner)
{
struct xfs_mount *mp = bp->b_mount;
if (xfs_has_crc(mp)) {
struct xfs_attr3_leafblock *hdr3 = bp->b_addr;
if (hdr3->hdr.info.hdr.magic !=
cpu_to_be16(XFS_ATTR3_LEAF_MAGIC))
return __this_address;
if (be64_to_cpu(hdr3->hdr.info.owner) != owner)
return __this_address;
}
return NULL;
}
static void
xfs_attr3_leaf_write_verify(
struct xfs_buf *bp)
@ -448,16 +469,30 @@ int
xfs_attr3_leaf_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_ino_t owner,
xfs_dablk_t bno,
struct xfs_buf **bpp)
{
xfs_failaddr_t fa;
int err;
err = xfs_da_read_buf(tp, dp, bno, 0, bpp, XFS_ATTR_FORK,
&xfs_attr3_leaf_buf_ops);
if (!err && tp && *bpp)
if (err || !(*bpp))
return err;
fa = xfs_attr3_leaf_header_check(*bpp, owner);
if (fa) {
__xfs_buf_mark_corrupt(*bpp, fa);
xfs_trans_brelse(tp, *bpp);
*bpp = NULL;
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
return -EFSCORRUPTED;
}
if (tp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF);
return err;
return 0;
}
/*========================================================================
@ -904,6 +939,7 @@ xfs_attr_shortform_to_leaf(
nargs.whichfork = XFS_ATTR_FORK;
nargs.trans = args->trans;
nargs.op_flags = XFS_DA_OP_OKNOENT;
nargs.owner = args->owner;
sfe = xfs_attr_sf_firstentry(sf);
for (i = 0; i < sf->count; i++) {
@ -1106,6 +1142,7 @@ xfs_attr3_leaf_to_shortform(
nargs.whichfork = XFS_ATTR_FORK;
nargs.trans = args->trans;
nargs.op_flags = XFS_DA_OP_OKNOENT;
nargs.owner = args->owner;
for (i = 0; i < ichdr.count; entry++, i++) {
if (entry->flags & XFS_ATTR_INCOMPLETE)
@ -1158,7 +1195,7 @@ xfs_attr3_leaf_to_node(
error = xfs_da_grow_inode(args, &blkno);
if (error)
goto out;
error = xfs_attr3_leaf_read(args->trans, dp, 0, &bp1);
error = xfs_attr3_leaf_read(args->trans, dp, args->owner, 0, &bp1);
if (error)
goto out;
@ -1237,7 +1274,7 @@ xfs_attr3_leaf_create(
ichdr.magic = XFS_ATTR3_LEAF_MAGIC;
hdr3->blkno = cpu_to_be64(xfs_buf_daddr(bp));
hdr3->owner = cpu_to_be64(dp->i_ino);
hdr3->owner = cpu_to_be64(args->owner);
uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
@ -1993,7 +2030,7 @@ xfs_attr3_leaf_toosmall(
if (blkno == 0)
continue;
error = xfs_attr3_leaf_read(state->args->trans, state->args->dp,
blkno, &bp);
state->args->owner, blkno, &bp);
if (error)
return error;
@ -2715,7 +2752,8 @@ xfs_attr3_leaf_clearflag(
/*
* Set up the operation.
*/
error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
args->blkno, &bp);
if (error)
return error;
@ -2779,7 +2817,8 @@ xfs_attr3_leaf_setflag(
/*
* Set up the operation.
*/
error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
args->blkno, &bp);
if (error)
return error;
@ -2838,7 +2877,8 @@ xfs_attr3_leaf_flipflags(
/*
* Read the block containing the "old" attr
*/
error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp1);
error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
args->blkno, &bp1);
if (error)
return error;
@ -2846,8 +2886,8 @@ xfs_attr3_leaf_flipflags(
* Read the block containing the "new" attr, if it is different
*/
if (args->blkno2 != args->blkno) {
error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
&bp2);
error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
args->blkno2, &bp2);
if (error)
return error;
} else {

View File

@ -98,12 +98,14 @@ int xfs_attr_leaf_order(struct xfs_buf *leaf1_bp,
struct xfs_buf *leaf2_bp);
int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int *local);
int xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t bno, struct xfs_buf **bpp);
xfs_ino_t owner, xfs_dablk_t bno, struct xfs_buf **bpp);
void xfs_attr3_leaf_hdr_from_disk(struct xfs_da_geometry *geo,
struct xfs_attr3_icleaf_hdr *to,
struct xfs_attr_leafblock *from);
void xfs_attr3_leaf_hdr_to_disk(struct xfs_da_geometry *geo,
struct xfs_attr_leafblock *to,
struct xfs_attr3_icleaf_hdr *from);
xfs_failaddr_t xfs_attr3_leaf_header_check(struct xfs_buf *bp,
xfs_ino_t owner);
#endif /* __XFS_ATTR_LEAF_H__ */

View File

@ -280,12 +280,12 @@ xfs_attr_rmtval_copyout(
struct xfs_mount *mp,
struct xfs_buf *bp,
struct xfs_inode *dp,
xfs_ino_t owner,
int *offset,
int *valuelen,
uint8_t **dst)
{
char *src = bp->b_addr;
xfs_ino_t ino = dp->i_ino;
xfs_daddr_t bno = xfs_buf_daddr(bp);
int len = BBTOB(bp->b_length);
int blksize = mp->m_attr_geo->blksize;
@ -299,11 +299,11 @@ xfs_attr_rmtval_copyout(
byte_cnt = min(*valuelen, byte_cnt);
if (xfs_has_crc(mp)) {
if (xfs_attr3_rmt_hdr_ok(src, ino, *offset,
if (xfs_attr3_rmt_hdr_ok(src, owner, *offset,
byte_cnt, bno)) {
xfs_alert(mp,
"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
bno, *offset, byte_cnt, ino);
bno, *offset, byte_cnt, owner);
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
return -EFSCORRUPTED;
}
@ -427,8 +427,7 @@ xfs_attr_rmtval_get(
return error;
error = xfs_attr_rmtval_copyout(mp, bp, args->dp,
&offset, &valuelen,
&dst);
args->owner, &offset, &valuelen, &dst);
xfs_buf_relse(bp);
if (error)
return error;
@ -522,8 +521,8 @@ xfs_attr_rmtval_set_value(
return error;
bp->b_ops = &xfs_attr3_rmt_buf_ops;
xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
&valuelen, &src);
xfs_attr_rmtval_copyin(mp, bp, args->owner, &offset, &valuelen,
&src);
error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
xfs_buf_relse(bp);

View File

@ -976,6 +976,7 @@ xfs_bmap_add_attrfork_local(
dargs.total = dargs.geo->fsbcount;
dargs.whichfork = XFS_DATA_FORK;
dargs.trans = tp;
dargs.owner = ip->i_ino;
return xfs_dir2_sf_to_block(&dargs);
}

View File

@ -252,6 +252,51 @@ xfs_da3_node_verify(
return NULL;
}
xfs_failaddr_t
xfs_da3_node_header_check(
struct xfs_buf *bp,
xfs_ino_t owner)
{
struct xfs_mount *mp = bp->b_mount;
if (xfs_has_crc(mp)) {
struct xfs_da3_blkinfo *hdr3 = bp->b_addr;
if (hdr3->hdr.magic != cpu_to_be16(XFS_DA3_NODE_MAGIC))
return __this_address;
if (be64_to_cpu(hdr3->owner) != owner)
return __this_address;
}
return NULL;
}
xfs_failaddr_t
xfs_da3_header_check(
struct xfs_buf *bp,
xfs_ino_t owner)
{
struct xfs_mount *mp = bp->b_mount;
struct xfs_da_blkinfo *hdr = bp->b_addr;
if (!xfs_has_crc(mp))
return NULL;
switch (hdr->magic) {
case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
return xfs_attr3_leaf_header_check(bp, owner);
case cpu_to_be16(XFS_DA3_NODE_MAGIC):
return xfs_da3_node_header_check(bp, owner);
case cpu_to_be16(XFS_DIR3_LEAF1_MAGIC):
case cpu_to_be16(XFS_DIR3_LEAFN_MAGIC):
return xfs_dir3_leaf_header_check(bp, owner);
}
ASSERT(0);
return NULL;
}
static void
xfs_da3_node_write_verify(
struct xfs_buf *bp)
@ -486,7 +531,7 @@ xfs_da3_node_create(
memset(hdr3, 0, sizeof(struct xfs_da3_node_hdr));
ichdr.magic = XFS_DA3_NODE_MAGIC;
hdr3->info.blkno = cpu_to_be64(xfs_buf_daddr(bp));
hdr3->info.owner = cpu_to_be64(args->dp->i_ino);
hdr3->info.owner = cpu_to_be64(args->owner);
uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid);
} else {
ichdr.magic = XFS_DA_NODE_MAGIC;
@ -1199,6 +1244,7 @@ xfs_da3_root_join(
struct xfs_da3_icnode_hdr oldroothdr;
int error;
struct xfs_inode *dp = state->args->dp;
xfs_failaddr_t fa;
trace_xfs_da_root_join(state->args);
@ -1225,6 +1271,13 @@ xfs_da3_root_join(
error = xfs_da3_node_read(args->trans, dp, child, &bp, args->whichfork);
if (error)
return error;
fa = xfs_da3_header_check(bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(args->trans, bp);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level);
/*
@ -1259,6 +1312,7 @@ xfs_da3_node_toosmall(
struct xfs_da_blkinfo *info;
xfs_dablk_t blkno;
struct xfs_buf *bp;
xfs_failaddr_t fa;
struct xfs_da3_icnode_hdr nodehdr;
int count;
int forward;
@ -1333,6 +1387,13 @@ xfs_da3_node_toosmall(
state->args->whichfork);
if (error)
return error;
fa = xfs_da3_node_header_check(bp, state->args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(state->args->trans, bp);
xfs_da_mark_sick(state->args);
return -EFSCORRUPTED;
}
node = bp->b_addr;
xfs_da3_node_hdr_from_disk(dp->i_mount, &thdr, node);
@ -1591,6 +1652,7 @@ xfs_da3_node_lookup_int(
struct xfs_da_node_entry *btree;
struct xfs_da3_icnode_hdr nodehdr;
struct xfs_da_args *args;
xfs_failaddr_t fa;
xfs_dablk_t blkno;
xfs_dahash_t hashval;
xfs_dahash_t btreehashval;
@ -1629,6 +1691,12 @@ xfs_da3_node_lookup_int(
if (magic == XFS_ATTR_LEAF_MAGIC ||
magic == XFS_ATTR3_LEAF_MAGIC) {
fa = xfs_attr3_leaf_header_check(blk->bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(blk->bp, fa);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
blk->magic = XFS_ATTR_LEAF_MAGIC;
blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
break;
@ -1636,6 +1704,12 @@ xfs_da3_node_lookup_int(
if (magic == XFS_DIR2_LEAFN_MAGIC ||
magic == XFS_DIR3_LEAFN_MAGIC) {
fa = xfs_dir3_leaf_header_check(blk->bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(blk->bp, fa);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
blk->magic = XFS_DIR2_LEAFN_MAGIC;
blk->hashval = xfs_dir2_leaf_lasthash(args->dp,
blk->bp, NULL);
@ -1648,6 +1722,13 @@ xfs_da3_node_lookup_int(
return -EFSCORRUPTED;
}
fa = xfs_da3_node_header_check(blk->bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(blk->bp, fa);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
blk->magic = XFS_DA_NODE_MAGIC;
/*
@ -1820,6 +1901,7 @@ xfs_da3_blk_link(
struct xfs_da_blkinfo *tmp_info;
struct xfs_da_args *args;
struct xfs_buf *bp;
xfs_failaddr_t fa;
int before = 0;
int error;
struct xfs_inode *dp = state->args->dp;
@ -1863,6 +1945,13 @@ xfs_da3_blk_link(
&bp, args->whichfork);
if (error)
return error;
fa = xfs_da3_header_check(bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(args->trans, bp);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
ASSERT(bp != NULL);
tmp_info = bp->b_addr;
ASSERT(tmp_info->magic == old_info->magic);
@ -1884,6 +1973,13 @@ xfs_da3_blk_link(
&bp, args->whichfork);
if (error)
return error;
fa = xfs_da3_header_check(bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(args->trans, bp);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
ASSERT(bp != NULL);
tmp_info = bp->b_addr;
ASSERT(tmp_info->magic == old_info->magic);
@ -1913,6 +2009,7 @@ xfs_da3_blk_unlink(
struct xfs_da_blkinfo *tmp_info;
struct xfs_da_args *args;
struct xfs_buf *bp;
xfs_failaddr_t fa;
int error;
/*
@ -1943,6 +2040,13 @@ xfs_da3_blk_unlink(
&bp, args->whichfork);
if (error)
return error;
fa = xfs_da3_header_check(bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(args->trans, bp);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
ASSERT(bp != NULL);
tmp_info = bp->b_addr;
ASSERT(tmp_info->magic == save_info->magic);
@ -1960,6 +2064,13 @@ xfs_da3_blk_unlink(
&bp, args->whichfork);
if (error)
return error;
fa = xfs_da3_header_check(bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(args->trans, bp);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
ASSERT(bp != NULL);
tmp_info = bp->b_addr;
ASSERT(tmp_info->magic == save_info->magic);
@ -1996,6 +2107,7 @@ xfs_da3_path_shift(
struct xfs_da_node_entry *btree;
struct xfs_da3_icnode_hdr nodehdr;
struct xfs_buf *bp;
xfs_failaddr_t fa;
xfs_dablk_t blkno = 0;
int level;
int error;
@ -2074,6 +2186,12 @@ xfs_da3_path_shift(
switch (be16_to_cpu(info->magic)) {
case XFS_DA_NODE_MAGIC:
case XFS_DA3_NODE_MAGIC:
fa = xfs_da3_node_header_check(blk->bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(blk->bp, fa);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
blk->magic = XFS_DA_NODE_MAGIC;
xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr,
bp->b_addr);
@ -2087,6 +2205,12 @@ xfs_da3_path_shift(
break;
case XFS_ATTR_LEAF_MAGIC:
case XFS_ATTR3_LEAF_MAGIC:
fa = xfs_attr3_leaf_header_check(blk->bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(blk->bp, fa);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
blk->magic = XFS_ATTR_LEAF_MAGIC;
ASSERT(level == path->active-1);
blk->index = 0;
@ -2094,6 +2218,12 @@ xfs_da3_path_shift(
break;
case XFS_DIR2_LEAFN_MAGIC:
case XFS_DIR3_LEAFN_MAGIC:
fa = xfs_dir3_leaf_header_check(blk->bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(blk->bp, fa);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
blk->magic = XFS_DIR2_LEAFN_MAGIC;
ASSERT(level == path->active-1);
blk->index = 0;
@ -2290,6 +2420,7 @@ xfs_da3_swap_lastblock(
struct xfs_buf *last_buf;
struct xfs_buf *sib_buf;
struct xfs_buf *par_buf;
xfs_failaddr_t fa;
xfs_dahash_t dead_hash;
xfs_fileoff_t lastoff;
xfs_dablk_t dead_blkno;
@ -2326,6 +2457,14 @@ xfs_da3_swap_lastblock(
error = xfs_da3_node_read(tp, dp, last_blkno, &last_buf, w);
if (error)
return error;
fa = xfs_da3_header_check(last_buf, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(last_buf, fa);
xfs_trans_brelse(tp, last_buf);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
/*
* Copy the last block into the dead buffer and log it.
*/
@ -2364,6 +2503,13 @@ xfs_da3_swap_lastblock(
error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w);
if (error)
goto done;
fa = xfs_da3_header_check(sib_buf, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(sib_buf, fa);
xfs_da_mark_sick(args);
error = -EFSCORRUPTED;
goto done;
}
sib_info = sib_buf->b_addr;
if (XFS_IS_CORRUPT(mp,
be32_to_cpu(sib_info->forw) != last_blkno ||
@ -2385,6 +2531,13 @@ xfs_da3_swap_lastblock(
error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w);
if (error)
goto done;
fa = xfs_da3_header_check(sib_buf, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(sib_buf, fa);
xfs_da_mark_sick(args);
error = -EFSCORRUPTED;
goto done;
}
sib_info = sib_buf->b_addr;
if (XFS_IS_CORRUPT(mp,
be32_to_cpu(sib_info->back) != last_blkno ||
@ -2408,6 +2561,13 @@ xfs_da3_swap_lastblock(
error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w);
if (error)
goto done;
fa = xfs_da3_node_header_check(par_buf, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(par_buf, fa);
xfs_da_mark_sick(args);
error = -EFSCORRUPTED;
goto done;
}
par_node = par_buf->b_addr;
xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node);
if (XFS_IS_CORRUPT(mp,
@ -2457,6 +2617,13 @@ xfs_da3_swap_lastblock(
error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w);
if (error)
goto done;
fa = xfs_da3_node_header_check(par_buf, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(par_buf, fa);
xfs_da_mark_sick(args);
error = -EFSCORRUPTED;
goto done;
}
par_node = par_buf->b_addr;
xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node);
if (XFS_IS_CORRUPT(mp, par_hdr.level != level)) {

View File

@ -79,6 +79,7 @@ typedef struct xfs_da_args {
int rmtvaluelen2; /* remote attr value length in bytes */
uint32_t op_flags; /* operation flags */
enum xfs_dacmp cmpresult; /* name compare result for lookups */
xfs_ino_t owner; /* inode that owns the dir/attr data */
} xfs_da_args_t;
/*
@ -235,6 +236,8 @@ void xfs_da3_node_hdr_from_disk(struct xfs_mount *mp,
struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from);
void xfs_da3_node_hdr_to_disk(struct xfs_mount *mp,
struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from);
xfs_failaddr_t xfs_da3_header_check(struct xfs_buf *bp, xfs_ino_t owner);
xfs_failaddr_t xfs_da3_node_header_check(struct xfs_buf *bp, xfs_ino_t owner);
extern struct kmem_cache *xfs_da_state_cache;

View File

@ -250,6 +250,7 @@ xfs_dir_init(
args->geo = dp->i_mount->m_dir_geo;
args->dp = dp;
args->trans = tp;
args->owner = dp->i_ino;
error = xfs_dir2_sf_create(args, pdp->i_ino);
kfree(args);
return error;
@ -295,6 +296,7 @@ xfs_dir_createname(
args->whichfork = XFS_DATA_FORK;
args->trans = tp;
args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
args->owner = dp->i_ino;
if (!inum)
args->op_flags |= XFS_DA_OP_JUSTCHECK;
@ -383,6 +385,7 @@ xfs_dir_lookup(
args->whichfork = XFS_DATA_FORK;
args->trans = tp;
args->op_flags = XFS_DA_OP_OKNOENT;
args->owner = dp->i_ino;
if (ci_name)
args->op_flags |= XFS_DA_OP_CILOOKUP;
@ -456,6 +459,7 @@ xfs_dir_removename(
args->total = total;
args->whichfork = XFS_DATA_FORK;
args->trans = tp;
args->owner = dp->i_ino;
if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
rval = xfs_dir2_sf_removename(args);
@ -517,6 +521,7 @@ xfs_dir_replace(
args->total = total;
args->whichfork = XFS_DATA_FORK;
args->trans = tp;
args->owner = dp->i_ino;
if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
rval = xfs_dir2_sf_replace(args);

View File

@ -101,6 +101,10 @@ extern struct xfs_dir2_data_free *xfs_dir2_data_freefind(
extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);
xfs_failaddr_t xfs_dir3_leaf_header_check(struct xfs_buf *bp, xfs_ino_t owner);
xfs_failaddr_t xfs_dir3_data_header_check(struct xfs_buf *bp, xfs_ino_t owner);
xfs_failaddr_t xfs_dir3_block_header_check(struct xfs_buf *bp, xfs_ino_t owner);
extern const struct xfs_buf_ops xfs_dir3_block_buf_ops;
extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops;
extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops;

View File

@ -115,17 +115,20 @@ const struct xfs_buf_ops xfs_dir3_block_buf_ops = {
.verify_struct = xfs_dir3_block_verify,
};
static xfs_failaddr_t
xfs_failaddr_t
xfs_dir3_block_header_check(
struct xfs_inode *dp,
struct xfs_buf *bp)
struct xfs_buf *bp,
xfs_ino_t owner)
{
struct xfs_mount *mp = dp->i_mount;
struct xfs_mount *mp = bp->b_mount;
if (xfs_has_crc(mp)) {
struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
if (be64_to_cpu(hdr3->owner) != dp->i_ino)
if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
return __this_address;
if (be64_to_cpu(hdr3->owner) != owner)
return __this_address;
}
@ -136,6 +139,7 @@ int
xfs_dir3_block_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_ino_t owner,
struct xfs_buf **bpp)
{
struct xfs_mount *mp = dp->i_mount;
@ -148,7 +152,7 @@ xfs_dir3_block_read(
return err;
/* Check things that we can't do in the verifier. */
fa = xfs_dir3_block_header_check(dp, *bpp);
fa = xfs_dir3_block_header_check(*bpp, owner);
if (fa) {
__xfs_buf_mark_corrupt(*bpp, fa);
xfs_trans_brelse(tp, *bpp);
@ -163,12 +167,13 @@ xfs_dir3_block_read(
static void
xfs_dir3_block_init(
struct xfs_mount *mp,
struct xfs_trans *tp,
struct xfs_buf *bp,
struct xfs_inode *dp)
struct xfs_da_args *args,
struct xfs_buf *bp)
{
struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
struct xfs_trans *tp = args->trans;
struct xfs_inode *dp = args->dp;
struct xfs_mount *mp = dp->i_mount;
struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
bp->b_ops = &xfs_dir3_block_buf_ops;
xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_BLOCK_BUF);
@ -177,7 +182,7 @@ xfs_dir3_block_init(
memset(hdr3, 0, sizeof(*hdr3));
hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
hdr3->blkno = cpu_to_be64(xfs_buf_daddr(bp));
hdr3->owner = cpu_to_be64(dp->i_ino);
hdr3->owner = cpu_to_be64(args->owner);
uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
return;
@ -382,7 +387,7 @@ xfs_dir2_block_addname(
tp = args->trans;
/* Read the (one and only) directory block into bp. */
error = xfs_dir3_block_read(tp, dp, &bp);
error = xfs_dir3_block_read(tp, dp, args->owner, &bp);
if (error)
return error;
@ -697,7 +702,7 @@ xfs_dir2_block_lookup_int(
dp = args->dp;
tp = args->trans;
error = xfs_dir3_block_read(tp, dp, &bp);
error = xfs_dir3_block_read(tp, dp, args->owner, &bp);
if (error)
return error;
@ -981,7 +986,8 @@ xfs_dir2_leaf_to_block(
* Read the data block if we don't already have it, give up if it fails.
*/
if (!dbp) {
error = xfs_dir3_data_read(tp, dp, args->geo->datablk, 0, &dbp);
error = xfs_dir3_data_read(tp, dp, args->owner,
args->geo->datablk, 0, &dbp);
if (error)
return error;
}
@ -1009,7 +1015,7 @@ xfs_dir2_leaf_to_block(
/*
* Start converting it to block form.
*/
xfs_dir3_block_init(mp, tp, dbp, dp);
xfs_dir3_block_init(args, dbp);
needlog = 1;
needscan = 0;
@ -1129,7 +1135,7 @@ xfs_dir2_sf_to_block(
error = xfs_dir3_data_init(args, blkno, &bp);
if (error)
goto out_free;
xfs_dir3_block_init(mp, tp, bp, dp);
xfs_dir3_block_init(args, bp);
hdr = bp->b_addr;
/*
@ -1169,7 +1175,7 @@ xfs_dir2_sf_to_block(
* Create entry for .
*/
dep = bp->b_addr + offset;
dep->inumber = cpu_to_be64(dp->i_ino);
dep->inumber = cpu_to_be64(args->owner);
dep->namelen = 1;
dep->name[0] = '.';
xfs_dir2_data_put_ftype(mp, dep, XFS_DIR3_FT_DIR);

View File

@ -395,17 +395,20 @@ static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = {
.verify_write = xfs_dir3_data_write_verify,
};
static xfs_failaddr_t
xfs_failaddr_t
xfs_dir3_data_header_check(
struct xfs_inode *dp,
struct xfs_buf *bp)
struct xfs_buf *bp,
xfs_ino_t owner)
{
struct xfs_mount *mp = dp->i_mount;
struct xfs_mount *mp = bp->b_mount;
if (xfs_has_crc(mp)) {
struct xfs_dir3_data_hdr *hdr3 = bp->b_addr;
if (be64_to_cpu(hdr3->hdr.owner) != dp->i_ino)
if (hdr3->hdr.magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
return __this_address;
if (be64_to_cpu(hdr3->hdr.owner) != owner)
return __this_address;
}
@ -416,6 +419,7 @@ int
xfs_dir3_data_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_ino_t owner,
xfs_dablk_t bno,
unsigned int flags,
struct xfs_buf **bpp)
@ -429,7 +433,7 @@ xfs_dir3_data_read(
return err;
/* Check things that we can't do in the verifier. */
fa = xfs_dir3_data_header_check(dp, *bpp);
fa = xfs_dir3_data_header_check(*bpp, owner);
if (fa) {
__xfs_buf_mark_corrupt(*bpp, fa);
xfs_trans_brelse(tp, *bpp);
@ -725,7 +729,7 @@ xfs_dir3_data_init(
memset(hdr3, 0, sizeof(*hdr3));
hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
hdr3->blkno = cpu_to_be64(xfs_buf_daddr(bp));
hdr3->owner = cpu_to_be64(dp->i_ino);
hdr3->owner = cpu_to_be64(args->owner);
uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
} else

View File

@ -208,6 +208,29 @@ xfs_dir3_leaf_verify(
return xfs_dir3_leaf_check_int(mp, &leafhdr, bp->b_addr, true);
}
xfs_failaddr_t
xfs_dir3_leaf_header_check(
struct xfs_buf *bp,
xfs_ino_t owner)
{
struct xfs_mount *mp = bp->b_mount;
if (xfs_has_crc(mp)) {
struct xfs_dir3_leaf *hdr3 = bp->b_addr;
if (hdr3->hdr.info.hdr.magic !=
cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) &&
hdr3->hdr.info.hdr.magic !=
cpu_to_be16(XFS_DIR3_LEAFN_MAGIC))
return __this_address;
if (be64_to_cpu(hdr3->hdr.info.owner) != owner)
return __this_address;
}
return NULL;
}
static void
xfs_dir3_leaf_read_verify(
struct xfs_buf *bp)
@ -271,32 +294,60 @@ int
xfs_dir3_leaf_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_ino_t owner,
xfs_dablk_t fbno,
struct xfs_buf **bpp)
{
xfs_failaddr_t fa;
int err;
err = xfs_da_read_buf(tp, dp, fbno, 0, bpp, XFS_DATA_FORK,
&xfs_dir3_leaf1_buf_ops);
if (!err && tp && *bpp)
if (err || !(*bpp))
return err;
fa = xfs_dir3_leaf_header_check(*bpp, owner);
if (fa) {
__xfs_buf_mark_corrupt(*bpp, fa);
xfs_trans_brelse(tp, *bpp);
*bpp = NULL;
xfs_dirattr_mark_sick(dp, XFS_DATA_FORK);
return -EFSCORRUPTED;
}
if (tp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAF1_BUF);
return err;
return 0;
}
int
xfs_dir3_leafn_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_ino_t owner,
xfs_dablk_t fbno,
struct xfs_buf **bpp)
{
xfs_failaddr_t fa;
int err;
err = xfs_da_read_buf(tp, dp, fbno, 0, bpp, XFS_DATA_FORK,
&xfs_dir3_leafn_buf_ops);
if (!err && tp && *bpp)
if (err || !(*bpp))
return err;
fa = xfs_dir3_leaf_header_check(*bpp, owner);
if (fa) {
__xfs_buf_mark_corrupt(*bpp, fa);
xfs_trans_brelse(tp, *bpp);
*bpp = NULL;
xfs_dirattr_mark_sick(dp, XFS_DATA_FORK);
return -EFSCORRUPTED;
}
if (tp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAFN_BUF);
return err;
return 0;
}
/*
@ -304,12 +355,12 @@ xfs_dir3_leafn_read(
*/
static void
xfs_dir3_leaf_init(
struct xfs_mount *mp,
struct xfs_trans *tp,
struct xfs_da_args *args,
struct xfs_buf *bp,
xfs_ino_t owner,
uint16_t type)
{
struct xfs_mount *mp = args->dp->i_mount;
struct xfs_trans *tp = args->trans;
struct xfs_dir2_leaf *leaf = bp->b_addr;
ASSERT(type == XFS_DIR2_LEAF1_MAGIC || type == XFS_DIR2_LEAFN_MAGIC);
@ -323,7 +374,7 @@ xfs_dir3_leaf_init(
? cpu_to_be16(XFS_DIR3_LEAF1_MAGIC)
: cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
leaf3->info.blkno = cpu_to_be64(xfs_buf_daddr(bp));
leaf3->info.owner = cpu_to_be64(owner);
leaf3->info.owner = cpu_to_be64(args->owner);
uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid);
} else {
memset(leaf, 0, sizeof(*leaf));
@ -356,7 +407,6 @@ xfs_dir3_leaf_get_buf(
{
struct xfs_inode *dp = args->dp;
struct xfs_trans *tp = args->trans;
struct xfs_mount *mp = dp->i_mount;
struct xfs_buf *bp;
int error;
@ -369,7 +419,7 @@ xfs_dir3_leaf_get_buf(
if (error)
return error;
xfs_dir3_leaf_init(mp, tp, bp, dp->i_ino, magic);
xfs_dir3_leaf_init(args, bp, magic);
xfs_dir3_leaf_log_header(args, bp);
if (magic == XFS_DIR2_LEAF1_MAGIC)
xfs_dir3_leaf_log_tail(args, bp);
@ -647,7 +697,8 @@ xfs_dir2_leaf_addname(
trace_xfs_dir2_leaf_addname(args);
error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, &lbp);
error = xfs_dir3_leaf_read(tp, dp, args->owner, args->geo->leafblk,
&lbp);
if (error)
return error;
@ -834,9 +885,9 @@ xfs_dir2_leaf_addname(
* Already had space in some data block.
* Just read that one in.
*/
error = xfs_dir3_data_read(tp, dp,
xfs_dir2_db_to_da(args->geo, use_block),
0, &dbp);
error = xfs_dir3_data_read(tp, dp, args->owner,
xfs_dir2_db_to_da(args->geo, use_block), 0,
&dbp);
if (error) {
xfs_trans_brelse(tp, lbp);
return error;
@ -1238,7 +1289,8 @@ xfs_dir2_leaf_lookup_int(
tp = args->trans;
mp = dp->i_mount;
error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, &lbp);
error = xfs_dir3_leaf_read(tp, dp, args->owner, args->geo->leafblk,
&lbp);
if (error)
return error;
@ -1276,9 +1328,9 @@ xfs_dir2_leaf_lookup_int(
if (newdb != curdb) {
if (dbp)
xfs_trans_brelse(tp, dbp);
error = xfs_dir3_data_read(tp, dp,
xfs_dir2_db_to_da(args->geo, newdb),
0, &dbp);
error = xfs_dir3_data_read(tp, dp, args->owner,
xfs_dir2_db_to_da(args->geo, newdb), 0,
&dbp);
if (error) {
xfs_trans_brelse(tp, lbp);
return error;
@ -1318,9 +1370,9 @@ xfs_dir2_leaf_lookup_int(
ASSERT(cidb != -1);
if (cidb != curdb) {
xfs_trans_brelse(tp, dbp);
error = xfs_dir3_data_read(tp, dp,
xfs_dir2_db_to_da(args->geo, cidb),
0, &dbp);
error = xfs_dir3_data_read(tp, dp, args->owner,
xfs_dir2_db_to_da(args->geo, cidb), 0,
&dbp);
if (error) {
xfs_trans_brelse(tp, lbp);
return error;
@ -1614,7 +1666,8 @@ xfs_dir2_leaf_trim_data(
/*
* Read the offending data block. We need its buffer.
*/
error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(geo, db), 0, &dbp);
error = xfs_dir3_data_read(tp, dp, args->owner,
xfs_dir2_db_to_da(geo, db), 0, &dbp);
if (error)
return error;
@ -1753,7 +1806,8 @@ xfs_dir2_node_to_leaf(
/*
* Read the freespace block.
*/
error = xfs_dir2_free_read(tp, dp, args->geo->freeblk, &fbp);
error = xfs_dir2_free_read(tp, dp, args->owner, args->geo->freeblk,
&fbp);
if (error)
return error;
xfs_dir2_free_hdr_from_disk(mp, &freehdr, fbp->b_addr);

View File

@ -175,11 +175,11 @@ const struct xfs_buf_ops xfs_dir3_free_buf_ops = {
/* Everything ok in the free block header? */
static xfs_failaddr_t
xfs_dir3_free_header_check(
struct xfs_inode *dp,
xfs_dablk_t fbno,
struct xfs_buf *bp)
struct xfs_buf *bp,
xfs_ino_t owner,
xfs_dablk_t fbno)
{
struct xfs_mount *mp = dp->i_mount;
struct xfs_mount *mp = bp->b_mount;
int maxbests = mp->m_dir_geo->free_max_bests;
unsigned int firstdb;
@ -195,7 +195,7 @@ xfs_dir3_free_header_check(
return __this_address;
if (be32_to_cpu(hdr3->nvalid) < be32_to_cpu(hdr3->nused))
return __this_address;
if (be64_to_cpu(hdr3->hdr.owner) != dp->i_ino)
if (be64_to_cpu(hdr3->hdr.owner) != owner)
return __this_address;
} else {
struct xfs_dir2_free_hdr *hdr = bp->b_addr;
@ -214,6 +214,7 @@ static int
__xfs_dir3_free_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_ino_t owner,
xfs_dablk_t fbno,
unsigned int flags,
struct xfs_buf **bpp)
@ -227,7 +228,7 @@ __xfs_dir3_free_read(
return err;
/* Check things that we can't do in the verifier. */
fa = xfs_dir3_free_header_check(dp, fbno, *bpp);
fa = xfs_dir3_free_header_check(*bpp, owner, fbno);
if (fa) {
__xfs_buf_mark_corrupt(*bpp, fa);
xfs_trans_brelse(tp, *bpp);
@ -299,20 +300,23 @@ int
xfs_dir2_free_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_ino_t owner,
xfs_dablk_t fbno,
struct xfs_buf **bpp)
{
return __xfs_dir3_free_read(tp, dp, fbno, 0, bpp);
return __xfs_dir3_free_read(tp, dp, owner, fbno, 0, bpp);
}
static int
xfs_dir2_free_try_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_ino_t owner,
xfs_dablk_t fbno,
struct xfs_buf **bpp)
{
return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_HOLE_OK, bpp);
return __xfs_dir3_free_read(tp, dp, owner, fbno, XFS_DABUF_MAP_HOLE_OK,
bpp);
}
static int
@ -349,7 +353,7 @@ xfs_dir3_free_get_buf(
hdr.magic = XFS_DIR3_FREE_MAGIC;
hdr3->hdr.blkno = cpu_to_be64(xfs_buf_daddr(bp));
hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
hdr3->hdr.owner = cpu_to_be64(args->owner);
uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid);
} else
hdr.magic = XFS_DIR2_FREE_MAGIC;
@ -717,7 +721,7 @@ xfs_dir2_leafn_lookup_for_addname(
if (curbp)
xfs_trans_brelse(tp, curbp);
error = xfs_dir2_free_read(tp, dp,
error = xfs_dir2_free_read(tp, dp, args->owner,
xfs_dir2_db_to_da(args->geo,
newfdb),
&curbp);
@ -863,7 +867,7 @@ xfs_dir2_leafn_lookup_for_entry(
ASSERT(state->extravalid);
curbp = state->extrablk.bp;
} else {
error = xfs_dir3_data_read(tp, dp,
error = xfs_dir3_data_read(tp, dp, args->owner,
xfs_dir2_db_to_da(args->geo,
newdb),
0, &curbp);
@ -1356,8 +1360,8 @@ xfs_dir2_leafn_remove(
* read in the free block.
*/
fdb = xfs_dir2_db_to_fdb(geo, db);
error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(geo, fdb),
&fbp);
error = xfs_dir2_free_read(tp, dp, args->owner,
xfs_dir2_db_to_da(geo, fdb), &fbp);
if (error)
return error;
free = fbp->b_addr;
@ -1562,7 +1566,8 @@ xfs_dir2_leafn_toosmall(
/*
* Read the sibling leaf block.
*/
error = xfs_dir3_leafn_read(state->args->trans, dp, blkno, &bp);
error = xfs_dir3_leafn_read(state->args->trans, dp,
state->args->owner, blkno, &bp);
if (error)
return error;
@ -1715,7 +1720,7 @@ xfs_dir2_node_add_datablk(
* that was just allocated.
*/
fbno = xfs_dir2_db_to_fdb(args->geo, *dbno);
error = xfs_dir2_free_try_read(tp, dp,
error = xfs_dir2_free_try_read(tp, dp, args->owner,
xfs_dir2_db_to_da(args->geo, fbno), &fbp);
if (error)
return error;
@ -1862,7 +1867,7 @@ xfs_dir2_node_find_freeblk(
* so this might not succeed. This should be really rare, so
* there's no reason to avoid it.
*/
error = xfs_dir2_free_try_read(tp, dp,
error = xfs_dir2_free_try_read(tp, dp, args->owner,
xfs_dir2_db_to_da(args->geo, fbno),
&fbp);
if (error)
@ -1948,9 +1953,8 @@ xfs_dir2_node_addname_int(
&freehdr, &findex);
} else {
/* Read the data block in. */
error = xfs_dir3_data_read(tp, dp,
xfs_dir2_db_to_da(args->geo, dbno),
0, &dbp);
error = xfs_dir3_data_read(tp, dp, args->owner,
xfs_dir2_db_to_da(args->geo, dbno), 0, &dbp);
}
if (error)
return error;
@ -2302,7 +2306,7 @@ xfs_dir2_node_trim_free(
/*
* Read the freespace block.
*/
error = xfs_dir2_free_try_read(tp, dp, fo, &bp);
error = xfs_dir2_free_try_read(tp, dp, args->owner, fo, &bp);
if (error)
return error;
/*

View File

@ -50,8 +50,8 @@ extern int xfs_dir_cilookup_result(struct xfs_da_args *args,
/* xfs_dir2_block.c */
extern int xfs_dir3_block_read(struct xfs_trans *tp, struct xfs_inode *dp,
struct xfs_buf **bpp);
int xfs_dir3_block_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_ino_t owner, struct xfs_buf **bpp);
extern int xfs_dir2_block_addname(struct xfs_da_args *args);
extern int xfs_dir2_block_lookup(struct xfs_da_args *args);
extern int xfs_dir2_block_removename(struct xfs_da_args *args);
@ -78,7 +78,8 @@ extern void xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp);
extern xfs_failaddr_t __xfs_dir3_data_check(struct xfs_inode *dp,
struct xfs_buf *bp);
int xfs_dir3_data_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t bno, unsigned int flags, struct xfs_buf **bpp);
xfs_ino_t owner, xfs_dablk_t bno, unsigned int flags,
struct xfs_buf **bpp);
int xfs_dir3_data_readahead(struct xfs_inode *dp, xfs_dablk_t bno,
unsigned int flags);
@ -95,9 +96,9 @@ void xfs_dir2_leaf_hdr_from_disk(struct xfs_mount *mp,
void xfs_dir2_leaf_hdr_to_disk(struct xfs_mount *mp, struct xfs_dir2_leaf *to,
struct xfs_dir3_icleaf_hdr *from);
int xfs_dir3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t fbno, struct xfs_buf **bpp);
xfs_ino_t owner, xfs_dablk_t fbno, struct xfs_buf **bpp);
int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t fbno, struct xfs_buf **bpp);
xfs_ino_t owner, xfs_dablk_t fbno, struct xfs_buf **bpp);
extern int xfs_dir2_block_to_leaf(struct xfs_da_args *args,
struct xfs_buf *dbp);
extern int xfs_dir2_leaf_addname(struct xfs_da_args *args);
@ -154,8 +155,8 @@ extern int xfs_dir2_node_removename(struct xfs_da_args *args);
extern int xfs_dir2_node_replace(struct xfs_da_args *args);
extern int xfs_dir2_node_trim_free(struct xfs_da_args *args, xfs_fileoff_t fo,
int *rvalp);
extern int xfs_dir2_free_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t fbno, struct xfs_buf **bpp);
int xfs_dir2_free_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_ino_t owner, xfs_dablk_t fbno, struct xfs_buf **bpp);
/* xfs_dir2_sf.c */
xfs_ino_t xfs_dir2_sf_get_ino(struct xfs_mount *mp, struct xfs_dir2_sf_hdr *hdr,

View File

@ -429,6 +429,7 @@ xfs_exchmaps_attr_to_sf(
.geo = tp->t_mountp->m_attr_geo,
.whichfork = XFS_ATTR_FORK,
.trans = tp,
.owner = xmi->xmi_ip2->i_ino,
};
struct xfs_buf *bp;
int forkoff;
@ -437,7 +438,8 @@ xfs_exchmaps_attr_to_sf(
if (!xfs_attr_is_leaf(xmi->xmi_ip2))
return 0;
error = xfs_attr3_leaf_read(tp, xmi->xmi_ip2, 0, &bp);
error = xfs_attr3_leaf_read(tp, xmi->xmi_ip2, xmi->xmi_ip2->i_ino, 0,
&bp);
if (error)
return error;
@ -459,6 +461,7 @@ xfs_exchmaps_dir_to_sf(
.geo = tp->t_mountp->m_dir_geo,
.whichfork = XFS_DATA_FORK,
.trans = tp,
.owner = xmi->xmi_ip2->i_ino,
};
struct xfs_dir2_sf_hdr sfh;
struct xfs_buf *bp;
@ -473,7 +476,7 @@ xfs_exchmaps_dir_to_sf(
if (!isblock)
return 0;
error = xfs_dir3_block_read(tp, xmi->xmi_ip2, &bp);
error = xfs_dir3_block_read(tp, xmi->xmi_ip2, xmi->xmi_ip2->i_ino, &bp);
if (error)
return error;

View File

@ -169,6 +169,7 @@ xchk_xattr_listent(
.hashval = xfs_da_hashname(name, namelen),
.trans = context->tp,
.valuelen = valuelen,
.owner = context->dp->i_ino,
};
struct xchk_xattr_buf *ab;
struct xchk_xattr *sx;

View File

@ -320,6 +320,7 @@ xchk_da_btree_block(
struct xfs_da3_blkinfo *hdr3;
struct xfs_da_args *dargs = &ds->dargs;
struct xfs_inode *ip = ds->dargs.dp;
xfs_failaddr_t fa;
xfs_ino_t owner;
int *pmaxrecs;
struct xfs_da3_icnode_hdr nodehdr;
@ -442,6 +443,12 @@ xchk_da_btree_block(
goto out_freebp;
}
fa = xfs_da3_header_check(blk->bp, dargs->owner);
if (fa) {
xchk_da_set_corrupt(ds, level);
goto out_freebp;
}
/*
* If we've been handed a block that is below the dabtree root, does
* its hashval match what the parent block expected to see?
@ -494,6 +501,7 @@ xchk_da_btree(
ds->dargs.whichfork = whichfork;
ds->dargs.trans = sc->tp;
ds->dargs.op_flags = XFS_DA_OP_OKNOENT;
ds->dargs.owner = sc->ip->i_ino;
ds->state = xfs_da_state_alloc(&ds->dargs);
ds->sc = sc;
ds->private = private;

View File

@ -196,8 +196,8 @@ xchk_dir_rec(
xchk_da_set_corrupt(ds, level);
goto out;
}
error = xfs_dir3_data_read(ds->dargs.trans, dp, rec_bno,
XFS_DABUF_MAP_HOLE_OK, &bp);
error = xfs_dir3_data_read(ds->dargs.trans, dp, ds->dargs.owner,
rec_bno, XFS_DABUF_MAP_HOLE_OK, &bp);
if (!xchk_fblock_process_error(ds->sc, XFS_DATA_FORK, rec_bno,
&error))
goto out;
@ -315,10 +315,11 @@ xchk_directory_data_bestfree(
/* dir block format */
if (lblk != XFS_B_TO_FSBT(mp, XFS_DIR2_DATA_OFFSET))
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
error = xfs_dir3_block_read(sc->tp, sc->ip, &bp);
error = xfs_dir3_block_read(sc->tp, sc->ip, sc->ip->i_ino, &bp);
} else {
/* dir data format */
error = xfs_dir3_data_read(sc->tp, sc->ip, lblk, 0, &bp);
error = xfs_dir3_data_read(sc->tp, sc->ip, sc->ip->i_ino, lblk,
0, &bp);
}
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
goto out;
@ -470,7 +471,7 @@ xchk_directory_leaf1_bestfree(
int error;
/* Read the free space block. */
error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, &bp);
error = xfs_dir3_leaf_read(sc->tp, sc->ip, sc->ip->i_ino, lblk, &bp);
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
return error;
xchk_buffer_recheck(sc, bp);
@ -531,10 +532,9 @@ xchk_directory_leaf1_bestfree(
/* Check all the bestfree entries. */
for (i = 0; i < bestcount; i++, bestp++) {
best = be16_to_cpu(*bestp);
error = xfs_dir3_data_read(sc->tp, sc->ip,
error = xfs_dir3_data_read(sc->tp, sc->ip, args->owner,
xfs_dir2_db_to_da(args->geo, i),
XFS_DABUF_MAP_HOLE_OK,
&dbp);
XFS_DABUF_MAP_HOLE_OK, &dbp);
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,
&error))
break;
@ -577,7 +577,7 @@ xchk_directory_free_bestfree(
int error;
/* Read the free space block */
error = xfs_dir2_free_read(sc->tp, sc->ip, lblk, &bp);
error = xfs_dir2_free_read(sc->tp, sc->ip, sc->ip->i_ino, lblk, &bp);
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
return error;
xchk_buffer_recheck(sc, bp);
@ -597,7 +597,7 @@ xchk_directory_free_bestfree(
stale++;
continue;
}
error = xfs_dir3_data_read(sc->tp, sc->ip,
error = xfs_dir3_data_read(sc->tp, sc->ip, args->owner,
(freehdr.firstdb + i) * args->geo->fsbcount,
0, &dbp);
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,
@ -621,10 +621,11 @@ xchk_directory_blocks(
{
struct xfs_bmbt_irec got;
struct xfs_da_args args = {
.dp = sc ->ip,
.dp = sc->ip,
.whichfork = XFS_DATA_FORK,
.geo = sc->mp->m_dir_geo,
.trans = sc->tp,
.owner = sc->ip->i_ino,
};
struct xfs_ifork *ifp = xfs_ifork_ptr(sc->ip, XFS_DATA_FORK);
struct xfs_mount *mp = sc->mp;

View File

@ -99,7 +99,7 @@ xchk_dir_walk_block(
unsigned int off, next_off, end;
int error;
error = xfs_dir3_block_read(sc->tp, dp, &bp);
error = xfs_dir3_block_read(sc->tp, dp, dp->i_ino, &bp);
if (error)
return error;
@ -175,7 +175,7 @@ xchk_read_leaf_dir_buf(
if (new_off > *curoff)
*curoff = new_off;
return xfs_dir3_data_read(tp, dp, map.br_startoff, 0, bpp);
return xfs_dir3_data_read(tp, dp, dp->i_ino, map.br_startoff, 0, bpp);
}
/* Call a function for every entry in a leaf directory. */
@ -273,6 +273,7 @@ xchk_dir_walk(
.dp = dp,
.geo = dp->i_mount->m_dir_geo,
.trans = sc->tp,
.owner = dp->i_ino,
};
bool isblock;
int error;
@ -324,6 +325,7 @@ xchk_dir_lookup(
.hashval = xfs_dir2_hashname(dp->i_mount, name),
.whichfork = XFS_DATA_FORK,
.op_flags = XFS_DA_OP_OKNOENT,
.owner = dp->i_ino,
};
bool isblock, isleaf;
int error;

View File

@ -540,6 +540,7 @@ xfs_attri_recover_work(
args->attr_filter = attrp->alfi_attr_filter & XFS_ATTRI_FILTER_MASK;
args->op_flags = XFS_DA_OP_RECOVERY | XFS_DA_OP_OKNOENT |
XFS_DA_OP_LOGGED;
args->owner = args->dp->i_ino;
ASSERT(xfs_sb_version_haslogxattrs(&mp->m_sb));

View File

@ -214,6 +214,7 @@ xfs_attr_node_list_lookup(
struct xfs_mount *mp = dp->i_mount;
struct xfs_trans *tp = context->tp;
struct xfs_buf *bp;
xfs_failaddr_t fa;
int i;
int error = 0;
unsigned int expected_level = 0;
@ -238,6 +239,10 @@ xfs_attr_node_list_lookup(
goto out_corruptbuf;
}
fa = xfs_da3_node_header_check(bp, dp->i_ino);
if (fa)
goto out_corruptbuf;
xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
/* Tree taller than we can handle; bail out! */
@ -273,6 +278,12 @@ xfs_attr_node_list_lookup(
}
}
fa = xfs_attr3_leaf_header_check(bp, dp->i_ino);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
goto out_releasebuf;
}
if (expected_level != 0)
goto out_corruptbuf;
@ -281,6 +292,7 @@ xfs_attr_node_list_lookup(
out_corruptbuf:
xfs_buf_mark_corrupt(bp);
out_releasebuf:
xfs_trans_brelse(tp, bp);
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
return -EFSCORRUPTED;
@ -297,6 +309,7 @@ xfs_attr_node_list(
struct xfs_buf *bp;
struct xfs_inode *dp = context->dp;
struct xfs_mount *mp = dp->i_mount;
xfs_failaddr_t fa;
int error = 0;
trace_xfs_attr_node_list(context);
@ -310,46 +323,60 @@ xfs_attr_node_list(
*/
bp = NULL;
if (cursor->blkno > 0) {
struct xfs_attr_leaf_entry *entries;
error = xfs_da3_node_read(context->tp, dp, cursor->blkno, &bp,
XFS_ATTR_FORK);
if (xfs_metadata_is_sick(error))
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
if ((error != 0) && (error != -EFSCORRUPTED))
if (error != 0 && error != -EFSCORRUPTED)
return error;
if (bp) {
struct xfs_attr_leaf_entry *entries;
if (!bp)
goto need_lookup;
node = bp->b_addr;
switch (be16_to_cpu(node->hdr.info.magic)) {
case XFS_DA_NODE_MAGIC:
case XFS_DA3_NODE_MAGIC:
node = bp->b_addr;
switch (be16_to_cpu(node->hdr.info.magic)) {
case XFS_DA_NODE_MAGIC:
case XFS_DA3_NODE_MAGIC:
trace_xfs_attr_list_wrong_blk(context);
fa = xfs_da3_node_header_check(bp, dp->i_ino);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
}
xfs_trans_brelse(context->tp, bp);
bp = NULL;
break;
case XFS_ATTR_LEAF_MAGIC:
case XFS_ATTR3_LEAF_MAGIC:
leaf = bp->b_addr;
fa = xfs_attr3_leaf_header_check(bp, dp->i_ino);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(context->tp, bp);
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
bp = NULL;
break;
}
xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo,
&leafhdr, leaf);
entries = xfs_attr3_leaf_entryp(leaf);
if (cursor->hashval > be32_to_cpu(
entries[leafhdr.count - 1].hashval)) {
trace_xfs_attr_list_wrong_blk(context);
xfs_trans_brelse(context->tp, bp);
bp = NULL;
break;
case XFS_ATTR_LEAF_MAGIC:
case XFS_ATTR3_LEAF_MAGIC:
leaf = bp->b_addr;
xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo,
&leafhdr, leaf);
entries = xfs_attr3_leaf_entryp(leaf);
if (cursor->hashval > be32_to_cpu(
entries[leafhdr.count - 1].hashval)) {
trace_xfs_attr_list_wrong_blk(context);
xfs_trans_brelse(context->tp, bp);
bp = NULL;
} else if (cursor->hashval <= be32_to_cpu(
entries[0].hashval)) {
trace_xfs_attr_list_wrong_blk(context);
xfs_trans_brelse(context->tp, bp);
bp = NULL;
}
break;
default:
} else if (cursor->hashval <= be32_to_cpu(
entries[0].hashval)) {
trace_xfs_attr_list_wrong_blk(context);
xfs_trans_brelse(context->tp, bp);
bp = NULL;
}
break;
default:
trace_xfs_attr_list_wrong_blk(context);
xfs_trans_brelse(context->tp, bp);
bp = NULL;
}
}
@ -359,6 +386,7 @@ xfs_attr_node_list(
* Note that start of node block is same as start of leaf block.
*/
if (bp == NULL) {
need_lookup:
error = xfs_attr_node_list_lookup(context, cursor, &bp);
if (error || !bp)
return error;
@ -380,8 +408,8 @@ xfs_attr_node_list(
break;
cursor->blkno = leafhdr.forw;
xfs_trans_brelse(context->tp, bp);
error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
&bp);
error = xfs_attr3_leaf_read(context->tp, dp, dp->i_ino,
cursor->blkno, &bp);
if (error)
return error;
}
@ -501,7 +529,8 @@ xfs_attr_leaf_list(
trace_xfs_attr_leaf_list(context);
context->cursor.blkno = 0;
error = xfs_attr3_leaf_read(context->tp, context->dp, 0, &bp);
error = xfs_attr3_leaf_read(context->tp, context->dp,
context->dp->i_ino, 0, &bp);
if (error)
return error;

View File

@ -157,7 +157,7 @@ xfs_dir2_block_getdents(
if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk)
return 0;
error = xfs_dir3_block_read(args->trans, dp, &bp);
error = xfs_dir3_block_read(args->trans, dp, args->owner, &bp);
if (error)
return error;
@ -282,7 +282,8 @@ xfs_dir2_leaf_readbuf(
new_off = xfs_dir2_da_to_byte(geo, map.br_startoff);
if (new_off > *cur_off)
*cur_off = new_off;
error = xfs_dir3_data_read(args->trans, dp, map.br_startoff, 0, &bp);
error = xfs_dir3_data_read(args->trans, dp, args->owner,
map.br_startoff, 0, &bp);
if (error)
goto out;
@ -532,6 +533,7 @@ xfs_readdir(
args.dp = dp;
args.geo = dp->i_mount->m_dir_geo;
args.trans = tp;
args.owner = dp->i_ino;
if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)
return xfs_dir2_sf_getdents(&args, ctx);

View File

@ -1931,6 +1931,7 @@ DECLARE_EVENT_CLASS(xfs_da_class,
__field(xfs_dahash_t, hashval)
__field(xfs_ino_t, inumber)
__field(uint32_t, op_flags)
__field(xfs_ino_t, owner)
),
TP_fast_assign(
__entry->dev = VFS_I(args->dp)->i_sb->s_dev;
@ -1941,9 +1942,10 @@ DECLARE_EVENT_CLASS(xfs_da_class,
__entry->hashval = args->hashval;
__entry->inumber = args->inumber;
__entry->op_flags = args->op_flags;
__entry->owner = args->owner;
),
TP_printk("dev %d:%d ino 0x%llx name %.*s namelen %d hashval 0x%x "
"inumber 0x%llx op_flags %s",
"inumber 0x%llx op_flags %s owner 0x%llx",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->namelen,
@ -1951,7 +1953,8 @@ DECLARE_EVENT_CLASS(xfs_da_class,
__entry->namelen,
__entry->hashval,
__entry->inumber,
__print_flags(__entry->op_flags, "|", XFS_DA_OP_FLAGS))
__print_flags(__entry->op_flags, "|", XFS_DA_OP_FLAGS),
__entry->owner)
)
#define DEFINE_DIR2_EVENT(name) \