xfs: refactor xfs_iread_extents to use xfs_btree_visit_blocks

xfs_iread_extents open-codes everything in xfs_btree_visit_blocks, so
refactor the btree helper to be able to iterate only the records on
level 0, then port iread_extents to use it.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Darrick J. Wong 2019-10-28 16:12:35 -07:00
parent fec40e220f
commit e992ae8afd
4 changed files with 96 additions and 119 deletions

View File

@ -1155,6 +1155,65 @@ trans_cancel:
* Internal and external extent tree search functions.
*/
struct xfs_iread_state {
struct xfs_iext_cursor icur;
xfs_extnum_t loaded;
};
/* Stuff every bmbt record from this block into the incore extent map. */
static int
xfs_iread_bmbt_block(
struct xfs_btree_cur *cur,
int level,
void *priv)
{
struct xfs_iread_state *ir = priv;
struct xfs_mount *mp = cur->bc_mp;
struct xfs_inode *ip = cur->bc_private.b.ip;
struct xfs_btree_block *block;
struct xfs_buf *bp;
struct xfs_bmbt_rec *frp;
xfs_extnum_t num_recs;
xfs_extnum_t j;
int whichfork = cur->bc_private.b.whichfork;
block = xfs_btree_get_block(cur, level, &bp);
/* Abort if we find more records than nextents. */
num_recs = xfs_btree_get_numrecs(block);
if (unlikely(ir->loaded + num_recs >
XFS_IFORK_NEXTENTS(ip, whichfork))) {
xfs_warn(ip->i_mount, "corrupt dinode %llu, (btree extents).",
(unsigned long long)ip->i_ino);
xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, block,
sizeof(*block), __this_address);
return -EFSCORRUPTED;
}
/* Copy records into the incore cache. */
frp = XFS_BMBT_REC_ADDR(mp, block, 1);
for (j = 0; j < num_recs; j++, frp++, ir->loaded++) {
struct xfs_bmbt_irec new;
xfs_failaddr_t fa;
xfs_bmbt_disk_get_all(frp, &new);
fa = xfs_bmap_validate_extent(ip, whichfork, &new);
if (fa) {
xfs_inode_verifier_error(ip, -EFSCORRUPTED,
"xfs_iread_extents(2)", frp,
sizeof(*frp), fa);
return -EFSCORRUPTED;
}
xfs_iext_insert(ip, &ir->icur, &new,
xfs_bmap_fork_to_state(whichfork));
trace_xfs_read_extent(ip, &ir->icur,
xfs_bmap_fork_to_state(whichfork), _THIS_IP_);
xfs_iext_next(XFS_IFORK_PTR(ip, whichfork), &ir->icur);
}
return 0;
}
/*
* Read in extents from a btree-format inode.
*/
@ -1164,134 +1223,38 @@ xfs_iread_extents(
struct xfs_inode *ip,
int whichfork)
{
struct xfs_mount *mp = ip->i_mount;
int state = xfs_bmap_fork_to_state(whichfork);
struct xfs_iread_state ir;
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
xfs_extnum_t nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
struct xfs_btree_block *block = ifp->if_broot;
struct xfs_iext_cursor icur;
struct xfs_bmbt_irec new;
xfs_fsblock_t bno;
struct xfs_buf *bp;
xfs_extnum_t i, j;
int level;
__be64 *pp;
struct xfs_mount *mp = ip->i_mount;
struct xfs_btree_cur *cur;
int error;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
return -EFSCORRUPTED;
}
/*
* Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
*/
level = be16_to_cpu(block->bb_level);
if (unlikely(level == 0)) {
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
return -EFSCORRUPTED;
}
pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
bno = be64_to_cpu(*pp);
/*
* Go down the tree until leaf level is reached, following the first
* pointer (leftmost) at each level.
*/
while (level-- > 0) {
error = xfs_btree_read_bufl(mp, tp, bno, &bp,
XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops);
if (error)
goto out;
block = XFS_BUF_TO_BLOCK(bp);
if (level == 0)
break;
pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
bno = be64_to_cpu(*pp);
XFS_WANT_CORRUPTED_GOTO(mp,
xfs_verify_fsbno(mp, bno), out_brelse);
xfs_trans_brelse(tp, bp);
}
/*
* Here with bp and block set to the leftmost leaf node in the tree.
*/
i = 0;
xfs_iext_first(ifp, &icur);
/*
* Loop over all leaf nodes. Copy information to the extent records.
*/
for (;;) {
xfs_bmbt_rec_t *frp;
xfs_fsblock_t nextbno;
xfs_extnum_t num_recs;
num_recs = xfs_btree_get_numrecs(block);
if (unlikely(i + num_recs > nextents)) {
xfs_warn(ip->i_mount,
"corrupt dinode %Lu, (btree extents).",
(unsigned long long) ip->i_ino);
xfs_inode_verifier_error(ip, -EFSCORRUPTED,
__func__, block, sizeof(*block),
__this_address);
error = -EFSCORRUPTED;
goto out_brelse;
}
/*
* Read-ahead the next leaf block, if any.
*/
nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
if (nextbno != NULLFSBLOCK)
xfs_btree_reada_bufl(mp, nextbno, 1,
&xfs_bmbt_buf_ops);
/*
* Copy records into the extent records.
*/
frp = XFS_BMBT_REC_ADDR(mp, block, 1);
for (j = 0; j < num_recs; j++, frp++, i++) {
xfs_failaddr_t fa;
xfs_bmbt_disk_get_all(frp, &new);
fa = xfs_bmap_validate_extent(ip, whichfork, &new);
if (fa) {
error = -EFSCORRUPTED;
xfs_inode_verifier_error(ip, error,
"xfs_iread_extents(2)",
frp, sizeof(*frp), fa);
goto out_brelse;
}
xfs_iext_insert(ip, &icur, &new, state);
trace_xfs_read_extent(ip, &icur, state, _THIS_IP_);
xfs_iext_next(ifp, &icur);
}
xfs_trans_brelse(tp, bp);
bno = nextbno;
/*
* If we've reached the end, stop.
*/
if (bno == NULLFSBLOCK)
break;
error = xfs_btree_read_bufl(mp, tp, bno, &bp,
XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops);
if (error)
goto out;
block = XFS_BUF_TO_BLOCK(bp);
}
if (i != XFS_IFORK_NEXTENTS(ip, whichfork)) {
error = -EFSCORRUPTED;
goto out;
}
ASSERT(i == xfs_iext_count(ifp));
ir.loaded = 0;
xfs_iext_first(ifp, &ir.icur);
cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
error = xfs_btree_visit_blocks(cur, xfs_iread_bmbt_block,
XFS_BTREE_VISIT_RECORDS, &ir);
xfs_btree_del_cursor(cur, error);
if (error)
goto out;
if (ir.loaded != XFS_IFORK_NEXTENTS(ip, whichfork)) {
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
error = -EFSCORRUPTED;
goto out;
}
ASSERT(ir.loaded == xfs_iext_count(ifp));
ifp->if_flags |= XFS_IFEXTENTS;
return 0;
out_brelse:
xfs_trans_brelse(tp, bp);
out:
xfs_iext_destroy(ifp);
return error;

View File

@ -4286,6 +4286,7 @@ int
xfs_btree_visit_blocks(
struct xfs_btree_cur *cur,
xfs_btree_visit_blocks_fn fn,
unsigned int flags,
void *data)
{
union xfs_btree_ptr lptr;
@ -4311,6 +4312,11 @@ xfs_btree_visit_blocks(
/* save for the next iteration of the loop */
xfs_btree_copy_ptrs(cur, &lptr, ptr, 1);
if (!(flags & XFS_BTREE_VISIT_LEAVES))
continue;
} else if (!(flags & XFS_BTREE_VISIT_RECORDS)) {
continue;
}
/* for each buffer in the level */
@ -4413,7 +4419,7 @@ xfs_btree_change_owner(
bbcoi.buffer_list = buffer_list;
return xfs_btree_visit_blocks(cur, xfs_btree_block_change_owner,
&bbcoi);
XFS_BTREE_VISIT_ALL, &bbcoi);
}
/* Verify the v5 fields of a long-format btree block. */
@ -4865,7 +4871,7 @@ xfs_btree_count_blocks(
{
*blocks = 0;
return xfs_btree_visit_blocks(cur, xfs_btree_count_blocks_helper,
blocks);
XFS_BTREE_VISIT_ALL, blocks);
}
/* Compare two btree pointers. */

View File

@ -485,8 +485,15 @@ int xfs_btree_query_all(struct xfs_btree_cur *cur, xfs_btree_query_range_fn fn,
typedef int (*xfs_btree_visit_blocks_fn)(struct xfs_btree_cur *cur, int level,
void *data);
/* Visit record blocks. */
#define XFS_BTREE_VISIT_RECORDS (1 << 0)
/* Visit leaf blocks. */
#define XFS_BTREE_VISIT_LEAVES (1 << 1)
/* Visit all blocks. */
#define XFS_BTREE_VISIT_ALL (XFS_BTREE_VISIT_RECORDS | \
XFS_BTREE_VISIT_LEAVES)
int xfs_btree_visit_blocks(struct xfs_btree_cur *cur,
xfs_btree_visit_blocks_fn fn, void *data);
xfs_btree_visit_blocks_fn fn, unsigned int flags, void *data);
int xfs_btree_count_blocks(struct xfs_btree_cur *cur, xfs_extlen_t *blocks);

View File

@ -294,5 +294,6 @@ xfs_bitmap_set_btblocks(
struct xfs_bitmap *bitmap,
struct xfs_btree_cur *cur)
{
return xfs_btree_visit_blocks(cur, xfs_bitmap_collect_btblock, bitmap);
return xfs_btree_visit_blocks(cur, xfs_bitmap_collect_btblock,
XFS_BTREE_VISIT_ALL, bitmap);
}