|
@@ -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);
|
|
|
}
|
|
|
|
|
|
/**
|