X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=backref.c;h=27309e07a1e99d07faff8d36e7fb3092616d17e0;hb=2c2db167c79bee6c0ce88f55f964135908654f74;hp=127951c5d3f9d13586a2af38d61b1b655d805879;hpb=3ae36b3b0f13326df8b38ff4a4df1ce47fccd417;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/backref.c b/backref.c index 127951c..27309e0 100644 --- a/backref.c +++ b/backref.c @@ -130,13 +130,22 @@ struct __prelim_ref { u64 wanted_disk_byte; }; +static struct __prelim_ref *list_first_pref(struct list_head *head) +{ + return list_first_entry(head, struct __prelim_ref, list); +} + struct pref_state { struct list_head pending; + struct list_head pending_missing_keys; + struct list_head pending_indirect_refs; }; static void init_pref_state(struct pref_state *prefstate) { INIT_LIST_HEAD(&prefstate->pending); + INIT_LIST_HEAD(&prefstate->pending_missing_keys); + INIT_LIST_HEAD(&prefstate->pending_indirect_refs); } /* @@ -183,7 +192,7 @@ static int __add_prelim_ref(struct pref_state *prefstate, u64 root_id, u64 parent, u64 wanted_disk_byte, int count, gfp_t gfp_mask) { - struct list_head *head = &prefstate->pending; + struct list_head *head; struct __prelim_ref *ref; if (root_id == BTRFS_DATA_RELOC_TREE_OBJECTID) @@ -194,16 +203,23 @@ static int __add_prelim_ref(struct pref_state *prefstate, u64 root_id, return -ENOMEM; ref->root_id = root_id; - if (key) + if (key) { ref->key_for_search = *key; - else + head = &prefstate->pending; + } else if (parent) { memset(&ref->key_for_search, 0, sizeof(ref->key_for_search)); + head = &prefstate->pending; + } else { + memset(&ref->key_for_search, 0, sizeof(ref->key_for_search)); + head = &prefstate->pending_missing_keys; + } ref->inode_list = NULL; ref->level = level; ref->count = count; ref->parent = parent; ref->wanted_disk_byte = wanted_disk_byte; + list_add_tail(&ref->list, head); return 0; @@ -359,11 +375,10 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 time_seq, const u64 *extent_item_pos, u64 total_refs) { - struct list_head *head = &prefstate->pending; + struct list_head *head = &prefstate->pending_indirect_refs; int err; int ret = 0; struct __prelim_ref *ref; - struct __prelim_ref *ref_safe; struct __prelim_ref *new_ref; struct ulist *parents; struct ulist_node *node; @@ -373,16 +388,11 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, if (!parents) return -ENOMEM; - /* - * _safe allows us to insert directly after the current item without - * iterating over the newly inserted items. - * we're also allowed to re-assign ref during iteration. - */ - list_for_each_entry_safe(ref, ref_safe, head, list) { - if (ref->parent) /* already direct */ - continue; - if (ref->count == 0) - continue; + while (!list_empty(head)) { + ref = list_first_pref(head); + list_move(&ref->list, &prefstate->pending); + ASSERT(!ref->parent); /* already direct */ + ASSERT(ref->count); err = __resolve_indirect_ref(fs_info, path, time_seq, ref, parents, extent_item_pos, total_refs); @@ -415,7 +425,7 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, new_ref->parent = node->val; new_ref->inode_list = (struct extent_inode_elem *) (uintptr_t)node->aux; - list_add(&new_ref->list, &ref->list); + list_add_tail(&new_ref->list, &prefstate->pending); } ulist_reinit(parents); } @@ -449,18 +459,16 @@ static inline int ref_for_same_block(struct __prelim_ref *ref1, static int __add_missing_keys(struct btrfs_fs_info *fs_info, struct pref_state *prefstate) { - struct list_head *head = &prefstate->pending; - struct list_head *pos; struct extent_buffer *eb; - list_for_each(pos, head) { + while (!list_empty(&prefstate->pending_missing_keys)) { struct __prelim_ref *ref; - ref = list_entry(pos, struct __prelim_ref, list); - if (ref->parent) - continue; - if (ref->key_for_search.type) - continue; + ref = list_first_pref(&prefstate->pending_missing_keys); + + ASSERT(ref->root_id); + ASSERT(!ref->parent); + ASSERT(!ref->key_for_search.type); BUG_ON(!ref->wanted_disk_byte); eb = read_tree_block(fs_info, ref->wanted_disk_byte, 0); if (!extent_buffer_uptodate(eb)) { @@ -472,6 +480,7 @@ 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); } return 0; } @@ -802,9 +811,11 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, __merge_refs(&prefstate, 2); + BUG_ON(!list_empty(&prefstate.pending_missing_keys)); + BUG_ON(!list_empty(&prefstate.pending_indirect_refs)); + while (!list_empty(&prefstate.pending)) { - ref = list_first_entry(&prefstate.pending, - struct __prelim_ref, list); + ref = list_first_pref(&prefstate.pending); WARN_ON(ref->count < 0); if (roots && ref->count && ref->root_id && ref->parent == 0) { /* no parent == root of tree */ @@ -854,8 +865,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, out: btrfs_free_path(path); while (!list_empty(&prefstate.pending)) { - ref = list_first_entry(&prefstate.pending, - struct __prelim_ref, list); + ref = list_first_pref(&prefstate.pending); list_del(&ref->list); kfree(ref); }