Skip to content

Commit bbdaacd

Browse files
ethanwu-synoksacilotto
authored andcommitted
btrfs: backref, don't add refs from shared block when resolving normal backref
BugLink: https://bugs.launchpad.net/bugs/1916061 commit ed58f2e upstream. All references from the block of SHARED_DATA_REF belong to that shared block backref. For example: item 11 key (40831553536 EXTENT_ITEM 4194304) itemoff 15460 itemsize 95 extent refs 24 gen 7302 flags DATA extent data backref root 257 objectid 260 offset 65536 count 5 extent data backref root 258 objectid 265 offset 0 count 9 shared data backref parent 394985472 count 10 Block 394985472 might be leaf from root 257, and the item obejctid and (file_pos - file_extent_item::offset) in that leaf just happens to be 260 and 65536 which is equal to the first extent data backref entry. Before this patch, when we resolve backref: root 257 objectid 260 offset 65536 we will add those refs in block 394985472 and wrongly treat those as the refs we want. Fix this by checking if the leaf we are processing is shared data backref, if so, just skip this leaf. Shared data refs added into preftrees.direct have all entry value = 0 (root_id = 0, key = NULL, level = 0) except parent entry. Other refs from indirect tree will have key value and root id != 0, and these values won't be changed when their parent is resolved and added to preftrees.direct. Therefore, we could reuse the preftrees.direct and search ref with all values = 0 except parent is set to avoid getting those resolved refs block. Reviewed-by: Josef Bacik <josef@toxicpanda.com> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: ethanwu <ethanwu@synology.com> Signed-off-by: David Sterba <dsterba@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Kamal Mostafa <kamal@canonical.com> Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
1 parent b42e2ae commit bbdaacd

File tree

1 file changed

+52
-9
lines changed

1 file changed

+52
-9
lines changed

fs/btrfs/backref.c

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,34 @@ static int add_indirect_ref(const struct btrfs_fs_info *fs_info,
386386
wanted_disk_byte, count, sc, gfp_mask);
387387
}
388388

389+
static int is_shared_data_backref(struct preftrees *preftrees, u64 bytenr)
390+
{
391+
struct rb_node **p = &preftrees->direct.root.rb_root.rb_node;
392+
struct rb_node *parent = NULL;
393+
struct prelim_ref *ref = NULL;
394+
struct prelim_ref target = {0};
395+
int result;
396+
397+
target.parent = bytenr;
398+
399+
while (*p) {
400+
parent = *p;
401+
ref = rb_entry(parent, struct prelim_ref, rbnode);
402+
result = prelim_ref_compare(ref, &target);
403+
404+
if (result < 0)
405+
p = &(*p)->rb_left;
406+
else if (result > 0)
407+
p = &(*p)->rb_right;
408+
else
409+
return 1;
410+
}
411+
return 0;
412+
}
413+
389414
static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
390-
struct ulist *parents, struct prelim_ref *ref,
415+
struct ulist *parents,
416+
struct preftrees *preftrees, struct prelim_ref *ref,
391417
int level, u64 time_seq, const u64 *extent_item_pos,
392418
u64 total_refs, bool ignore_offset)
393419
{
@@ -412,11 +438,16 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
412438
}
413439

414440
/*
415-
* We normally enter this function with the path already pointing to
416-
* the first item to check. But sometimes, we may enter it with
417-
* slot==nritems. In that case, go to the next leaf before we continue.
441+
* 1. We normally enter this function with the path already pointing to
442+
* the first item to check. But sometimes, we may enter it with
443+
* slot == nritems.
444+
* 2. We are searching for normal backref but bytenr of this leaf
445+
* matches shared data backref
446+
* For these cases, go to the next leaf before we continue.
418447
*/
419-
if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
448+
eb = path->nodes[0];
449+
if (path->slots[0] >= btrfs_header_nritems(eb) ||
450+
is_shared_data_backref(preftrees, eb->start)) {
420451
if (time_seq == SEQ_LAST)
421452
ret = btrfs_next_leaf(root, path);
422453
else
@@ -433,6 +464,17 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
433464
key.type != BTRFS_EXTENT_DATA_KEY)
434465
break;
435466

467+
/*
468+
* We are searching for normal backref but bytenr of this leaf
469+
* matches shared data backref.
470+
*/
471+
if (slot == 0 && is_shared_data_backref(preftrees, eb->start)) {
472+
if (time_seq == SEQ_LAST)
473+
ret = btrfs_next_leaf(root, path);
474+
else
475+
ret = btrfs_next_old_leaf(root, path, time_seq);
476+
continue;
477+
}
436478
fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
437479
disk_byte = btrfs_file_extent_disk_bytenr(eb, fi);
438480
data_offset = btrfs_file_extent_offset(eb, fi);
@@ -484,6 +526,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
484526
*/
485527
static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
486528
struct btrfs_path *path, u64 time_seq,
529+
struct preftrees *preftrees,
487530
struct prelim_ref *ref, struct ulist *parents,
488531
const u64 *extent_item_pos, u64 total_refs,
489532
bool ignore_offset)
@@ -577,8 +620,8 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
577620
eb = path->nodes[level];
578621
}
579622

580-
ret = add_all_parents(root, path, parents, ref, level, time_seq,
581-
extent_item_pos, total_refs, ignore_offset);
623+
ret = add_all_parents(root, path, parents, preftrees, ref, level,
624+
time_seq, extent_item_pos, total_refs, ignore_offset);
582625
out:
583626
path->lowest_level = 0;
584627
btrfs_release_path(path);
@@ -656,8 +699,8 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
656699
ret = BACKREF_FOUND_SHARED;
657700
goto out;
658701
}
659-
err = resolve_indirect_ref(fs_info, path, time_seq, ref,
660-
parents, extent_item_pos,
702+
err = resolve_indirect_ref(fs_info, path, time_seq, preftrees,
703+
ref, parents, extent_item_pos,
661704
total_refs, ignore_offset);
662705
/*
663706
* we can only tolerate ENOENT,otherwise,we should catch error

0 commit comments

Comments
 (0)