btrfs-progs: backref: properly queue indirect refs

[BUG]
When calling iterate_extent_inodes() on data extents with indirect ref
(with inline or keyed EXTENT_DATA_REF_KEY), it will fail to execute the
call back function at all.

[CAUSE]
In function find_parent_nodes(), we only add the target tree block if a
backref has @parent populated.

For indirect backref like EXTENT_DATA_REF_KEY, we rely on
__resolve_indirect_ref() to get the parent leaves.

However __resolve_indirect_ref() only grabs backrefs from
&prefstate->pending_indirect_refs.

Meaning callers should queue any indirect backref to
pending_indirect_refs.

But unfortunately in __add_prelim_ref() and __add_missing_keys(), none
of them properly queue the indirect backrefs to pending_indirect_refs,
but directly to pending.

Making all indirect backrefs never got resolved, thus no callback
function executed

[FIX]
Fix __add_prelim_ref() and __add_missing_keys() to properly queue
indirect backrefs to the correct list.

Currently there is no such direct user in btrfs-progs, but later csum
tree re-initialization code will rely this to do proper csum
re-calculate (to avoid preallocated/nodatasum extents).

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2022-01-14 08:51:19 +08:00 committed by David Sterba
parent d6ee42633b
commit 90cdc23d01

View File

@ -192,7 +192,10 @@ static int __add_prelim_ref(struct pref_state *prefstate, u64 root_id,
ref->root_id = root_id;
if (key) {
ref->key_for_search = *key;
head = &prefstate->pending;
if (parent)
head = &prefstate->pending;
else
head = &prefstate->pending_indirect_refs;
} else if (parent) {
memset(&ref->key_for_search, 0, sizeof(ref->key_for_search));
head = &prefstate->pending;
@ -467,7 +470,10 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info,
else
btrfs_node_key_to_cpu(eb, &ref->key_for_search, 0);
free_extent_buffer(eb);
list_move(&ref->list, &prefstate->pending);
if (ref->parent)
list_move(&ref->list, &prefstate->pending);
else
list_move(&ref->list, &prefstate->pending_indirect_refs);
}
return 0;
}