From 08823f7512621e02201e41dd366af45314bc10ba Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 14 Jan 2022 08:51:19 +0800 Subject: [PATCH] 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 Signed-off-by: David Sterba --- kernel-shared/backref.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel-shared/backref.c b/kernel-shared/backref.c index 42832c48..f1a638ed 100644 --- a/kernel-shared/backref.c +++ b/kernel-shared/backref.c @@ -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; }