Skip to content

Commit 19b546d

Browse files
adam900710kdave
authored andcommitted
btrfs: relocation: Use btrfs_find_all_leafs to locate data extent parent tree leaves
In relocation, we need to locate all parent tree leaves referring to one data extent, thus we have a complex mechanism to iterate throught extent tree and subvolume trees to locate the related leaves. However this is already done in backref.c, we have btrfs_find_all_leafs(), which can return a ulist containing all leaves referring to that data extent. Use btrfs_find_all_leafs() to replace find_data_references(). There is a special handling for v1 space cache data extents, where we need to delete the v1 space cache data extents, to avoid those data extents to hang the data relocation. In this patch, the special handling is done by re-iterating the root tree leaf. Although it's a little less efficient than the old handling, considering we can reuse a lot of code, it should be acceptable. Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent b39c8f5 commit 19b546d

File tree

3 files changed

+60
-264
lines changed

3 files changed

+60
-264
lines changed

fs/btrfs/backref.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,10 +1409,10 @@ static void free_leaf_list(struct ulist *blocks)
14091409
*
14101410
* returns 0 on success, <0 on error
14111411
*/
1412-
static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
1413-
struct btrfs_fs_info *fs_info, u64 bytenr,
1414-
u64 time_seq, struct ulist **leafs,
1415-
const u64 *extent_item_pos, bool ignore_offset)
1412+
int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
1413+
struct btrfs_fs_info *fs_info, u64 bytenr,
1414+
u64 time_seq, struct ulist **leafs,
1415+
const u64 *extent_item_pos, bool ignore_offset)
14161416
{
14171417
int ret;
14181418

fs/btrfs/backref.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
4040

4141
int paths_from_inode(u64 inum, struct inode_fs_paths *ipath);
4242

43+
int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
44+
struct btrfs_fs_info *fs_info, u64 bytenr,
45+
u64 time_seq, struct ulist **leafs,
46+
const u64 *extent_item_pos, bool ignore_offset);
4347
int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
4448
struct btrfs_fs_info *fs_info, u64 bytenr,
4549
u64 time_seq, struct ulist **roots, bool ignore_offset);

fs/btrfs/relocation.c

Lines changed: 52 additions & 260 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "print-tree.h"
2424
#include "delalloc-space.h"
2525
#include "block-group.h"
26+
#include "backref.h"
2627

2728
/*
2829
* Relocation overview
@@ -3620,31 +3621,6 @@ static int __add_tree_block(struct reloc_control *rc,
36203621
return ret;
36213622
}
36223623

3623-
/*
3624-
* helper to check if the block use full backrefs for pointers in it
3625-
*/
3626-
static int block_use_full_backref(struct reloc_control *rc,
3627-
struct extent_buffer *eb)
3628-
{
3629-
u64 flags;
3630-
int ret;
3631-
3632-
if (btrfs_header_flag(eb, BTRFS_HEADER_FLAG_RELOC) ||
3633-
btrfs_header_backref_rev(eb) < BTRFS_MIXED_BACKREF_REV)
3634-
return 1;
3635-
3636-
ret = btrfs_lookup_extent_info(NULL, rc->extent_root->fs_info,
3637-
eb->start, btrfs_header_level(eb), 1,
3638-
NULL, &flags);
3639-
BUG_ON(ret);
3640-
3641-
if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)
3642-
ret = 1;
3643-
else
3644-
ret = 0;
3645-
return ret;
3646-
}
3647-
36483624
static int delete_block_group_cache(struct btrfs_fs_info *fs_info,
36493625
struct btrfs_block_group *block_group,
36503626
struct inode *inode,
@@ -3688,174 +3664,40 @@ static int delete_block_group_cache(struct btrfs_fs_info *fs_info,
36883664
}
36893665

36903666
/*
3691-
* helper to add tree blocks for backref of type BTRFS_EXTENT_DATA_REF_KEY
3692-
* this function scans fs tree to find blocks reference the data extent
3667+
* Locate the free space cache EXTENT_DATA in root tree leaf and delete the
3668+
* cache inode, to avoid free space cache data extent blocking data relocation.
36933669
*/
3694-
static int find_data_references(struct reloc_control *rc,
3695-
struct btrfs_key *extent_key,
3696-
struct extent_buffer *leaf,
3697-
struct btrfs_extent_data_ref *ref,
3698-
struct rb_root *blocks)
3670+
static int delete_v1_space_cache(struct extent_buffer *leaf,
3671+
struct btrfs_block_group *block_group,
3672+
u64 data_bytenr)
36993673
{
3700-
struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
3701-
struct btrfs_path *path;
3702-
struct tree_block *block;
3703-
struct btrfs_root *root;
3704-
struct btrfs_file_extent_item *fi;
3705-
struct rb_node *rb_node;
3674+
u64 space_cache_ino;
3675+
struct btrfs_file_extent_item *ei;
37063676
struct btrfs_key key;
3707-
u64 ref_root;
3708-
u64 ref_objectid;
3709-
u64 ref_offset;
3710-
u32 ref_count;
3711-
u32 nritems;
3712-
int err = 0;
3713-
int added = 0;
3714-
int counted;
3677+
bool found = false;
3678+
int i;
37153679
int ret;
37163680

3717-
ref_root = btrfs_extent_data_ref_root(leaf, ref);
3718-
ref_objectid = btrfs_extent_data_ref_objectid(leaf, ref);
3719-
ref_offset = btrfs_extent_data_ref_offset(leaf, ref);
3720-
ref_count = btrfs_extent_data_ref_count(leaf, ref);
3721-
3722-
/*
3723-
* This is an extent belonging to the free space cache, lets just delete
3724-
* it and redo the search.
3725-
*/
3726-
if (ref_root == BTRFS_ROOT_TREE_OBJECTID) {
3727-
ret = delete_block_group_cache(fs_info, rc->block_group,
3728-
NULL, ref_objectid);
3729-
if (ret != -ENOENT)
3730-
return ret;
3731-
ret = 0;
3732-
}
3733-
3734-
path = btrfs_alloc_path();
3735-
if (!path)
3736-
return -ENOMEM;
3737-
path->reada = READA_FORWARD;
3738-
3739-
root = read_fs_root(fs_info, ref_root);
3740-
if (IS_ERR(root)) {
3741-
err = PTR_ERR(root);
3742-
goto out_free;
3743-
}
3744-
3745-
key.objectid = ref_objectid;
3746-
key.type = BTRFS_EXTENT_DATA_KEY;
3747-
if (ref_offset > ((u64)-1 << 32))
3748-
key.offset = 0;
3749-
else
3750-
key.offset = ref_offset;
3751-
3752-
path->search_commit_root = 1;
3753-
path->skip_locking = 1;
3754-
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
3755-
if (ret < 0) {
3756-
err = ret;
3757-
goto out;
3758-
}
3759-
3760-
leaf = path->nodes[0];
3761-
nritems = btrfs_header_nritems(leaf);
3762-
/*
3763-
* the references in tree blocks that use full backrefs
3764-
* are not counted in
3765-
*/
3766-
if (block_use_full_backref(rc, leaf))
3767-
counted = 0;
3768-
else
3769-
counted = 1;
3770-
rb_node = tree_search(blocks, leaf->start);
3771-
if (rb_node) {
3772-
if (counted)
3773-
added = 1;
3774-
else
3775-
path->slots[0] = nritems;
3776-
}
3777-
3778-
while (ref_count > 0) {
3779-
while (path->slots[0] >= nritems) {
3780-
ret = btrfs_next_leaf(root, path);
3781-
if (ret < 0) {
3782-
err = ret;
3783-
goto out;
3784-
}
3785-
if (WARN_ON(ret > 0))
3786-
goto out;
3787-
3788-
leaf = path->nodes[0];
3789-
nritems = btrfs_header_nritems(leaf);
3790-
added = 0;
3791-
3792-
if (block_use_full_backref(rc, leaf))
3793-
counted = 0;
3794-
else
3795-
counted = 1;
3796-
rb_node = tree_search(blocks, leaf->start);
3797-
if (rb_node) {
3798-
if (counted)
3799-
added = 1;
3800-
else
3801-
path->slots[0] = nritems;
3802-
}
3803-
}
3681+
if (btrfs_header_owner(leaf) != BTRFS_ROOT_TREE_OBJECTID)
3682+
return 0;
38043683

3805-
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
3806-
if (WARN_ON(key.objectid != ref_objectid ||
3807-
key.type != BTRFS_EXTENT_DATA_KEY))
3684+
for (i = 0; i < btrfs_header_nritems(leaf); i++) {
3685+
btrfs_item_key_to_cpu(leaf, &key, i);
3686+
if (key.type != BTRFS_EXTENT_DATA_KEY)
3687+
continue;
3688+
ei = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item);
3689+
if (btrfs_file_extent_type(leaf, ei) == BTRFS_FILE_EXTENT_REG &&
3690+
btrfs_file_extent_disk_bytenr(leaf, ei) == data_bytenr) {
3691+
found = true;
3692+
space_cache_ino = key.objectid;
38083693
break;
3809-
3810-
fi = btrfs_item_ptr(leaf, path->slots[0],
3811-
struct btrfs_file_extent_item);
3812-
3813-
if (btrfs_file_extent_type(leaf, fi) ==
3814-
BTRFS_FILE_EXTENT_INLINE)
3815-
goto next;
3816-
3817-
if (btrfs_file_extent_disk_bytenr(leaf, fi) !=
3818-
extent_key->objectid)
3819-
goto next;
3820-
3821-
key.offset -= btrfs_file_extent_offset(leaf, fi);
3822-
if (key.offset != ref_offset)
3823-
goto next;
3824-
3825-
if (counted)
3826-
ref_count--;
3827-
if (added)
3828-
goto next;
3829-
3830-
if (!tree_block_processed(leaf->start, rc)) {
3831-
block = kmalloc(sizeof(*block), GFP_NOFS);
3832-
if (!block) {
3833-
err = -ENOMEM;
3834-
break;
3835-
}
3836-
block->bytenr = leaf->start;
3837-
btrfs_item_key_to_cpu(leaf, &block->key, 0);
3838-
block->level = 0;
3839-
block->key_ready = 1;
3840-
rb_node = tree_insert(blocks, block->bytenr,
3841-
&block->rb_node);
3842-
if (rb_node)
3843-
backref_tree_panic(rb_node, -EEXIST,
3844-
block->bytenr);
38453694
}
3846-
if (counted)
3847-
added = 1;
3848-
else
3849-
path->slots[0] = nritems;
3850-
next:
3851-
path->slots[0]++;
3852-
38533695
}
3854-
out:
3855-
btrfs_put_root(root);
3856-
out_free:
3857-
btrfs_free_path(path);
3858-
return err;
3696+
if (!found)
3697+
return -ENOENT;
3698+
ret = delete_block_group_cache(leaf->fs_info, block_group, NULL,
3699+
space_cache_ino);
3700+
return ret;
38593701
}
38603702

38613703
/*
@@ -3867,91 +3709,41 @@ int add_data_references(struct reloc_control *rc,
38673709
struct btrfs_path *path,
38683710
struct rb_root *blocks)
38693711
{
3870-
struct btrfs_key key;
3871-
struct extent_buffer *eb;
3872-
struct btrfs_extent_data_ref *dref;
3873-
struct btrfs_extent_inline_ref *iref;
3874-
unsigned long ptr;
3875-
unsigned long end;
3876-
u32 blocksize = rc->extent_root->fs_info->nodesize;
3712+
struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
3713+
struct ulist *leaves = NULL;
3714+
struct ulist_iterator leaf_uiter;
3715+
struct ulist_node *ref_node = NULL;
3716+
const u32 blocksize = fs_info->nodesize;
38773717
int ret = 0;
3878-
int err = 0;
3879-
3880-
eb = path->nodes[0];
3881-
ptr = btrfs_item_ptr_offset(eb, path->slots[0]);
3882-
end = ptr + btrfs_item_size_nr(eb, path->slots[0]);
3883-
ptr += sizeof(struct btrfs_extent_item);
38843718

3885-
while (ptr < end) {
3886-
iref = (struct btrfs_extent_inline_ref *)ptr;
3887-
key.type = btrfs_get_extent_inline_ref_type(eb, iref,
3888-
BTRFS_REF_TYPE_DATA);
3889-
if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
3890-
key.offset = btrfs_extent_inline_ref_offset(eb, iref);
3891-
ret = __add_tree_block(rc, key.offset, blocksize,
3892-
blocks);
3893-
} else if (key.type == BTRFS_EXTENT_DATA_REF_KEY) {
3894-
dref = (struct btrfs_extent_data_ref *)(&iref->offset);
3895-
ret = find_data_references(rc, extent_key,
3896-
eb, dref, blocks);
3897-
} else {
3898-
ret = -EUCLEAN;
3899-
btrfs_err(rc->extent_root->fs_info,
3900-
"extent %llu slot %d has an invalid inline ref type",
3901-
eb->start, path->slots[0]);
3902-
}
3903-
if (ret) {
3904-
err = ret;
3905-
goto out;
3906-
}
3907-
ptr += btrfs_extent_inline_ref_size(key.type);
3908-
}
3909-
WARN_ON(ptr > end);
3719+
btrfs_release_path(path);
3720+
ret = btrfs_find_all_leafs(NULL, fs_info, extent_key->objectid,
3721+
0, &leaves, NULL, true);
3722+
if (ret < 0)
3723+
return ret;
39103724

3911-
while (1) {
3912-
cond_resched();
3913-
eb = path->nodes[0];
3914-
if (path->slots[0] >= btrfs_header_nritems(eb)) {
3915-
ret = btrfs_next_leaf(rc->extent_root, path);
3916-
if (ret < 0) {
3917-
err = ret;
3918-
break;
3919-
}
3920-
if (ret > 0)
3921-
break;
3922-
eb = path->nodes[0];
3923-
}
3725+
ULIST_ITER_INIT(&leaf_uiter);
3726+
while ((ref_node = ulist_next(leaves, &leaf_uiter))) {
3727+
struct extent_buffer *eb;
39243728

3925-
btrfs_item_key_to_cpu(eb, &key, path->slots[0]);
3926-
if (key.objectid != extent_key->objectid)
3729+
eb = read_tree_block(fs_info, ref_node->val, 0, 0, NULL);
3730+
if (IS_ERR(eb)) {
3731+
ret = PTR_ERR(eb);
39273732
break;
3928-
3929-
if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
3930-
ret = __add_tree_block(rc, key.offset, blocksize,
3931-
blocks);
3932-
} else if (key.type == BTRFS_EXTENT_DATA_REF_KEY) {
3933-
dref = btrfs_item_ptr(eb, path->slots[0],
3934-
struct btrfs_extent_data_ref);
3935-
ret = find_data_references(rc, extent_key,
3936-
eb, dref, blocks);
3937-
} else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) {
3938-
btrfs_print_v0_err(eb->fs_info);
3939-
btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL);
3940-
ret = -EINVAL;
3941-
} else {
3942-
ret = 0;
39433733
}
3944-
if (ret) {
3945-
err = ret;
3734+
ret = delete_v1_space_cache(eb, rc->block_group,
3735+
extent_key->objectid);
3736+
free_extent_buffer(eb);
3737+
if (ret < 0)
3738+
break;
3739+
ret = __add_tree_block(rc, ref_node->val, blocksize, blocks);
3740+
if (ret < 0)
39463741
break;
3947-
}
3948-
path->slots[0]++;
39493742
}
3950-
out:
3951-
btrfs_release_path(path);
3952-
if (err)
3743+
if (ret < 0)
39533744
free_block_list(blocks);
3954-
return err;
3745+
ulist_free(leaves);
3746+
return ret;
39553747
}
39563748

39573749
/*

0 commit comments

Comments
 (0)