Skip to content

Commit 27afc71

Browse files
ethanwu-synogregkh
authored andcommitted
btrfs: backref, use correct count to resolve normal data refs
commit b25b0b8 upstream. With the following patches: - btrfs: backref, only collect file extent items matching backref offset - btrfs: backref, not adding refs from shared block when resolving normal backref - btrfs: backref, only search backref entries from leaves of the same root we only collect the normal data refs we want, so the imprecise upper bound total_refs of that EXTENT_ITEM could now be changed to the count of the normal backref entry we want to search. Background and how the patches fit together: Btrfs has two types of data backref. For BTRFS_EXTENT_DATA_REF_KEY type of backref, we don't have the exact block number. Therefore, we need to call resolve_indirect_refs. It uses btrfs_search_slot to locate the leaf block. Then we need to walk through the leaves to search for the EXTENT_DATA items that have disk bytenr matching the extent item (add_all_parents). When resolving indirect refs, we could take entries that don't belong to the backref entry we are searching for right now. For that reason when searching backref entry, we always use total refs of that EXTENT_ITEM rather than individual count. For example: item 11 key (40831553536 EXTENT_ITEM 4194304) itemoff 15460 itemsize extent refs 24 gen 7302 flags DATA shared data backref parent 394985472 count 10 #1 extent data backref root 257 objectid 260 offset 1048576 count 3 #2 extent data backref root 256 objectid 260 offset 65536 count 6 #3 extent data backref root 257 objectid 260 offset 65536 count 5 #4 For example, when searching backref entry #4, we'll use total_refs 24, a very loose loop ending condition, instead of total_refs = 5. But using total_refs = 24 is not accurate. Sometimes, we'll never find all the refs from specific root. As a result, the loop keeps on going until we reach the end of that inode. The first 3 patches, handle 3 different types refs we might encounter. These refs do not belong to the normal backref we are searching, and hence need to be skipped. This patch changes the total_refs to correct number so that we could end loop as soon as we find all the refs we want. btrfs send uses backref to find possible clone sources, the following is a simple test to compare the results with and without this patch: $ btrfs subvolume create /sub1 $ for i in `seq 1 163840`; do dd if=/dev/zero of=/sub1/file bs=64K count=1 seek=$((i-1)) conv=notrunc oflag=direct done $ btrfs subvolume snapshot /sub1 /sub2 $ for i in `seq 1 163840`; do dd if=/dev/zero of=/sub1/file bs=4K count=1 seek=$(((i-1)*16+10)) conv=notrunc oflag=direct done $ btrfs subvolume snapshot -r /sub1 /snap1 $ time btrfs send /snap1 | btrfs receive /volume2 Without this patch: real 69m48.124s user 0m50.199s sys 70m15.600s With this patch: real 1m59.683s user 0m35.421s sys 2m42.684s Reviewed-by: Josef Bacik <josef@toxicpanda.com> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: ethanwu <ethanwu@synology.com> [ add patchset cover letter with background and numbers ] Signed-off-by: David Sterba <dsterba@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 66bcf5f commit 27afc71

File tree

1 file changed

+11
-18
lines changed

1 file changed

+11
-18
lines changed

fs/btrfs/backref.c

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
415415
struct ulist *parents,
416416
struct preftrees *preftrees, struct prelim_ref *ref,
417417
int level, u64 time_seq, const u64 *extent_item_pos,
418-
u64 total_refs, bool ignore_offset)
418+
bool ignore_offset)
419419
{
420420
int ret = 0;
421421
int slot;
@@ -457,7 +457,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
457457
ret = btrfs_next_old_leaf(root, path, time_seq);
458458
}
459459

460-
while (!ret && count < total_refs) {
460+
while (!ret && count < ref->count) {
461461
eb = path->nodes[0];
462462
slot = path->slots[0];
463463

@@ -534,8 +534,7 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
534534
struct btrfs_path *path, u64 time_seq,
535535
struct preftrees *preftrees,
536536
struct prelim_ref *ref, struct ulist *parents,
537-
const u64 *extent_item_pos, u64 total_refs,
538-
bool ignore_offset)
537+
const u64 *extent_item_pos, bool ignore_offset)
539538
{
540539
struct btrfs_root *root;
541540
struct btrfs_key root_key;
@@ -627,7 +626,7 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
627626
}
628627

629628
ret = add_all_parents(root, path, parents, preftrees, ref, level,
630-
time_seq, extent_item_pos, total_refs, ignore_offset);
629+
time_seq, extent_item_pos, ignore_offset);
631630
out:
632631
path->lowest_level = 0;
633632
btrfs_release_path(path);
@@ -661,7 +660,7 @@ unode_aux_to_inode_list(struct ulist_node *node)
661660
static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
662661
struct btrfs_path *path, u64 time_seq,
663662
struct preftrees *preftrees,
664-
const u64 *extent_item_pos, u64 total_refs,
663+
const u64 *extent_item_pos,
665664
struct share_check *sc, bool ignore_offset)
666665
{
667666
int err;
@@ -707,7 +706,7 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
707706
}
708707
err = resolve_indirect_ref(fs_info, path, time_seq, preftrees,
709708
ref, parents, extent_item_pos,
710-
total_refs, ignore_offset);
709+
ignore_offset);
711710
/*
712711
* we can only tolerate ENOENT,otherwise,we should catch error
713712
* and return directly.
@@ -810,8 +809,7 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info,
810809
*/
811810
static int add_delayed_refs(const struct btrfs_fs_info *fs_info,
812811
struct btrfs_delayed_ref_head *head, u64 seq,
813-
struct preftrees *preftrees, u64 *total_refs,
814-
struct share_check *sc)
812+
struct preftrees *preftrees, struct share_check *sc)
815813
{
816814
struct btrfs_delayed_ref_node *node;
817815
struct btrfs_delayed_extent_op *extent_op = head->extent_op;
@@ -845,7 +843,6 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info,
845843
default:
846844
BUG();
847845
}
848-
*total_refs += count;
849846
switch (node->type) {
850847
case BTRFS_TREE_BLOCK_REF_KEY: {
851848
/* NORMAL INDIRECT METADATA backref */
@@ -928,7 +925,7 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info,
928925
static int add_inline_refs(const struct btrfs_fs_info *fs_info,
929926
struct btrfs_path *path, u64 bytenr,
930927
int *info_level, struct preftrees *preftrees,
931-
u64 *total_refs, struct share_check *sc)
928+
struct share_check *sc)
932929
{
933930
int ret = 0;
934931
int slot;
@@ -952,7 +949,6 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
952949

953950
ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
954951
flags = btrfs_extent_flags(leaf, ei);
955-
*total_refs += btrfs_extent_refs(leaf, ei);
956952
btrfs_item_key_to_cpu(leaf, &found_key, slot);
957953

958954
ptr = (unsigned long)(ei + 1);
@@ -1177,8 +1173,6 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
11771173
struct prelim_ref *ref;
11781174
struct rb_node *node;
11791175
struct extent_inode_elem *eie = NULL;
1180-
/* total of both direct AND indirect refs! */
1181-
u64 total_refs = 0;
11821176
struct preftrees preftrees = {
11831177
.direct = PREFTREE_INIT,
11841178
.indirect = PREFTREE_INIT,
@@ -1247,7 +1241,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
12471241
}
12481242
spin_unlock(&delayed_refs->lock);
12491243
ret = add_delayed_refs(fs_info, head, time_seq,
1250-
&preftrees, &total_refs, sc);
1244+
&preftrees, sc);
12511245
mutex_unlock(&head->mutex);
12521246
if (ret)
12531247
goto out;
@@ -1268,8 +1262,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
12681262
(key.type == BTRFS_EXTENT_ITEM_KEY ||
12691263
key.type == BTRFS_METADATA_ITEM_KEY)) {
12701264
ret = add_inline_refs(fs_info, path, bytenr,
1271-
&info_level, &preftrees,
1272-
&total_refs, sc);
1265+
&info_level, &preftrees, sc);
12731266
if (ret)
12741267
goto out;
12751268
ret = add_keyed_refs(fs_info, path, bytenr, info_level,
@@ -1288,7 +1281,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
12881281
WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect_missing_keys.root.rb_root));
12891282

12901283
ret = resolve_indirect_refs(fs_info, path, time_seq, &preftrees,
1291-
extent_item_pos, total_refs, sc, ignore_offset);
1284+
extent_item_pos, sc, ignore_offset);
12921285
if (ret)
12931286
goto out;
12941287

0 commit comments

Comments
 (0)