mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 22:54:05 +08:00
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:
parent
fec40e220f
commit
e992ae8afd
@ -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;
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user