xfs: refactor btree owner change into a separate visit-blocks function

Refactor the btree_change_owner function into a more generic apparatus
which visits all blocks in a btree.  We'll use this in a subsequent
patch for counting btree blocks for AG reservations.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
Darrick J. Wong 2016-08-03 11:10:55 +10:00 committed by Dave Chinner
parent 105f7d83db
commit 28a89567b8
2 changed files with 96 additions and 50 deletions

View File

@ -4328,6 +4328,81 @@ xfs_btree_get_rec(
return 0;
}
/* Visit a block in a btree. */
STATIC int
xfs_btree_visit_block(
struct xfs_btree_cur *cur,
int level,
xfs_btree_visit_blocks_fn fn,
void *data)
{
struct xfs_btree_block *block;
struct xfs_buf *bp;
union xfs_btree_ptr rptr;
int error;
/* do right sibling readahead */
xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA);
block = xfs_btree_get_block(cur, level, &bp);
/* process the block */
error = fn(cur, level, data);
if (error)
return error;
/* now read rh sibling block for next iteration */
xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB);
if (xfs_btree_ptr_is_null(cur, &rptr))
return -ENOENT;
return xfs_btree_lookup_get_block(cur, level, &rptr, &block);
}
/* Visit every block in a btree. */
int
xfs_btree_visit_blocks(
struct xfs_btree_cur *cur,
xfs_btree_visit_blocks_fn fn,
void *data)
{
union xfs_btree_ptr lptr;
int level;
struct xfs_btree_block *block = NULL;
int error = 0;
cur->bc_ops->init_ptr_from_cur(cur, &lptr);
/* for each level */
for (level = cur->bc_nlevels - 1; level >= 0; level--) {
/* grab the left hand block */
error = xfs_btree_lookup_get_block(cur, level, &lptr, &block);
if (error)
return error;
/* readahead the left most block for the next level down */
if (level > 0) {
union xfs_btree_ptr *ptr;
ptr = xfs_btree_ptr_addr(cur, 1, block);
xfs_btree_readahead_ptr(cur, ptr, 1);
/* save for the next iteration of the loop */
lptr = *ptr;
}
/* for each buffer in the level */
do {
error = xfs_btree_visit_block(cur, level, fn, data);
} while (!error);
if (error != -ENOENT)
return error;
}
return 0;
}
/*
* Change the owner of a btree.
*
@ -4352,26 +4427,27 @@ xfs_btree_get_rec(
* just queue the modified buffer as delayed write buffer so the transaction
* recovery completion writes the changes to disk.
*/
struct xfs_btree_block_change_owner_info {
__uint64_t new_owner;
struct list_head *buffer_list;
};
static int
xfs_btree_block_change_owner(
struct xfs_btree_cur *cur,
int level,
__uint64_t new_owner,
struct list_head *buffer_list)
void *data)
{
struct xfs_btree_block_change_owner_info *bbcoi = data;
struct xfs_btree_block *block;
struct xfs_buf *bp;
union xfs_btree_ptr rptr;
/* do right sibling readahead */
xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA);
/* modify the owner */
block = xfs_btree_get_block(cur, level, &bp);
if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
block->bb_u.l.bb_owner = cpu_to_be64(new_owner);
block->bb_u.l.bb_owner = cpu_to_be64(bbcoi->new_owner);
else
block->bb_u.s.bb_owner = cpu_to_be32(new_owner);
block->bb_u.s.bb_owner = cpu_to_be32(bbcoi->new_owner);
/*
* If the block is a root block hosted in an inode, we might not have a
@ -4385,19 +4461,14 @@ xfs_btree_block_change_owner(
xfs_trans_ordered_buf(cur->bc_tp, bp);
xfs_btree_log_block(cur, bp, XFS_BB_OWNER);
} else {
xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_delwri_queue(bp, bbcoi->buffer_list);
}
} else {
ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
ASSERT(level == cur->bc_nlevels - 1);
}
/* now read rh sibling block for next iteration */
xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB);
if (xfs_btree_ptr_is_null(cur, &rptr))
return -ENOENT;
return xfs_btree_lookup_get_block(cur, level, &rptr, &block);
return 0;
}
int
@ -4406,43 +4477,13 @@ xfs_btree_change_owner(
__uint64_t new_owner,
struct list_head *buffer_list)
{
union xfs_btree_ptr lptr;
int level;
struct xfs_btree_block *block = NULL;
int error = 0;
struct xfs_btree_block_change_owner_info bbcoi;
cur->bc_ops->init_ptr_from_cur(cur, &lptr);
bbcoi.new_owner = new_owner;
bbcoi.buffer_list = buffer_list;
/* for each level */
for (level = cur->bc_nlevels - 1; level >= 0; level--) {
/* grab the left hand block */
error = xfs_btree_lookup_get_block(cur, level, &lptr, &block);
if (error)
return error;
/* readahead the left most block for the next level down */
if (level > 0) {
union xfs_btree_ptr *ptr;
ptr = xfs_btree_ptr_addr(cur, 1, block);
xfs_btree_readahead_ptr(cur, ptr, 1);
/* save for the next iteration of the loop */
lptr = *ptr;
}
/* for each buffer in the level */
do {
error = xfs_btree_block_change_owner(cur, level,
new_owner,
buffer_list);
} while (!error);
if (error != -ENOENT)
return error;
}
return 0;
return xfs_btree_visit_blocks(cur, xfs_btree_block_change_owner,
&bbcoi);
}
/**

View File

@ -536,4 +536,9 @@ int xfs_btree_query_range(struct xfs_btree_cur *cur,
union xfs_btree_irec *low_rec, union xfs_btree_irec *high_rec,
xfs_btree_query_range_fn fn, void *priv);
typedef int (*xfs_btree_visit_blocks_fn)(struct xfs_btree_cur *cur, int level,
void *data);
int xfs_btree_visit_blocks(struct xfs_btree_cur *cur,
xfs_btree_visit_blocks_fn fn, void *data);
#endif /* __XFS_BTREE_H__ */