btrfs-progs: backref: push state tracking into a helper structure

Eventually, we'll have several lists and trees, as well as some statistics.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
master
Jeff Mahoney 2017-07-25 16:51:35 -04:00 committed by David Sterba
parent a5ce5d2198
commit 3ae36b3b0f
1 changed files with 45 additions and 30 deletions

View File

@ -130,6 +130,15 @@ struct __prelim_ref {
u64 wanted_disk_byte; u64 wanted_disk_byte;
}; };
struct pref_state {
struct list_head pending;
};
static void init_pref_state(struct pref_state *prefstate)
{
INIT_LIST_HEAD(&prefstate->pending);
}
/* /*
* the rules for all callers of this function are: * the rules for all callers of this function are:
* - obtaining the parent is the goal * - obtaining the parent is the goal
@ -169,11 +178,12 @@ struct __prelim_ref {
* block might help in merging entries to gain some speed. * block might help in merging entries to gain some speed.
*/ */
static int __add_prelim_ref(struct list_head *head, u64 root_id, static int __add_prelim_ref(struct pref_state *prefstate, u64 root_id,
struct btrfs_key *key, int level, struct btrfs_key *key, int level,
u64 parent, u64 wanted_disk_byte, int count, u64 parent, u64 wanted_disk_byte, int count,
gfp_t gfp_mask) gfp_t gfp_mask)
{ {
struct list_head *head = &prefstate->pending;
struct __prelim_ref *ref; struct __prelim_ref *ref;
if (root_id == BTRFS_DATA_RELOC_TREE_OBJECTID) if (root_id == BTRFS_DATA_RELOC_TREE_OBJECTID)
@ -345,10 +355,11 @@ out:
* resolve all indirect backrefs from the list * resolve all indirect backrefs from the list
*/ */
static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
struct pref_state *prefstate,
struct btrfs_path *path, u64 time_seq, struct btrfs_path *path, u64 time_seq,
struct list_head *head,
const u64 *extent_item_pos, u64 total_refs) const u64 *extent_item_pos, u64 total_refs)
{ {
struct list_head *head = &prefstate->pending;
int err; int err;
int ret = 0; int ret = 0;
struct __prelim_ref *ref; struct __prelim_ref *ref;
@ -436,8 +447,9 @@ static inline int ref_for_same_block(struct __prelim_ref *ref1,
* read tree blocks and add keys where required. * read tree blocks and add keys where required.
*/ */
static int __add_missing_keys(struct btrfs_fs_info *fs_info, static int __add_missing_keys(struct btrfs_fs_info *fs_info,
struct list_head *head) struct pref_state *prefstate)
{ {
struct list_head *head = &prefstate->pending;
struct list_head *pos; struct list_head *pos;
struct extent_buffer *eb; struct extent_buffer *eb;
@ -474,8 +486,9 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info,
* having a parent). * having a parent).
* mode = 2: merge identical parents * mode = 2: merge identical parents
*/ */
static void __merge_refs(struct list_head *head, int mode) static void __merge_refs(struct pref_state *prefstate, int mode)
{ {
struct list_head *head = &prefstate->pending;
struct list_head *pos1; struct list_head *pos1;
list_for_each(pos1, head) { list_for_each(pos1, head) {
@ -526,9 +539,9 @@ static void __merge_refs(struct list_head *head, int mode)
* add all inline backrefs for bytenr to the list * add all inline backrefs for bytenr to the list
*/ */
static int __add_inline_refs(struct btrfs_fs_info *fs_info, static int __add_inline_refs(struct btrfs_fs_info *fs_info,
struct pref_state *prefstate,
struct btrfs_path *path, u64 bytenr, struct btrfs_path *path, u64 bytenr,
int *info_level, struct list_head *prefs, int *info_level, u64 *total_refs)
u64 *total_refs)
{ {
int ret = 0; int ret = 0;
int slot; int slot;
@ -540,7 +553,6 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
struct btrfs_extent_item *ei; struct btrfs_extent_item *ei;
u64 flags; u64 flags;
u64 item_size; u64 item_size;
/* /*
* enumerate all inline refs * enumerate all inline refs
*/ */
@ -583,7 +595,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
switch (type) { switch (type) {
case BTRFS_SHARED_BLOCK_REF_KEY: case BTRFS_SHARED_BLOCK_REF_KEY:
ret = __add_prelim_ref(prefs, 0, NULL, ret = __add_prelim_ref(prefstate, 0, NULL,
*info_level + 1, offset, *info_level + 1, offset,
bytenr, 1, GFP_NOFS); bytenr, 1, GFP_NOFS);
break; break;
@ -593,12 +605,12 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
sdref = (struct btrfs_shared_data_ref *)(iref + 1); sdref = (struct btrfs_shared_data_ref *)(iref + 1);
count = btrfs_shared_data_ref_count(leaf, sdref); count = btrfs_shared_data_ref_count(leaf, sdref);
ret = __add_prelim_ref(prefs, 0, NULL, 0, offset, ret = __add_prelim_ref(prefstate, 0, NULL, 0, offset,
bytenr, count, GFP_NOFS); bytenr, count, GFP_NOFS);
break; break;
} }
case BTRFS_TREE_BLOCK_REF_KEY: case BTRFS_TREE_BLOCK_REF_KEY:
ret = __add_prelim_ref(prefs, offset, NULL, ret = __add_prelim_ref(prefstate, offset, NULL,
*info_level + 1, 0, *info_level + 1, 0,
bytenr, 1, GFP_NOFS); bytenr, 1, GFP_NOFS);
break; break;
@ -614,7 +626,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
key.type = BTRFS_EXTENT_DATA_KEY; key.type = BTRFS_EXTENT_DATA_KEY;
key.offset = btrfs_extent_data_ref_offset(leaf, dref); key.offset = btrfs_extent_data_ref_offset(leaf, dref);
root = btrfs_extent_data_ref_root(leaf, dref); root = btrfs_extent_data_ref_root(leaf, dref);
ret = __add_prelim_ref(prefs, root, &key, 0, 0, ret = __add_prelim_ref(prefstate, root, &key, 0, 0,
bytenr, count, GFP_NOFS); bytenr, count, GFP_NOFS);
break; break;
} }
@ -633,8 +645,9 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
* add all non-inline backrefs for bytenr to the list * add all non-inline backrefs for bytenr to the list
*/ */
static int __add_keyed_refs(struct btrfs_fs_info *fs_info, static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
struct pref_state *prefstate,
struct btrfs_path *path, u64 bytenr, struct btrfs_path *path, u64 bytenr,
int info_level, struct list_head *prefs) int info_level)
{ {
struct btrfs_root *extent_root = fs_info->extent_root; struct btrfs_root *extent_root = fs_info->extent_root;
int ret; int ret;
@ -664,7 +677,7 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
switch (key.type) { switch (key.type) {
case BTRFS_SHARED_BLOCK_REF_KEY: case BTRFS_SHARED_BLOCK_REF_KEY:
ret = __add_prelim_ref(prefs, 0, NULL, ret = __add_prelim_ref(prefstate, 0, NULL,
info_level + 1, key.offset, info_level + 1, key.offset,
bytenr, 1, GFP_NOFS); bytenr, 1, GFP_NOFS);
break; break;
@ -675,12 +688,12 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
sdref = btrfs_item_ptr(leaf, slot, sdref = btrfs_item_ptr(leaf, slot,
struct btrfs_shared_data_ref); struct btrfs_shared_data_ref);
count = btrfs_shared_data_ref_count(leaf, sdref); count = btrfs_shared_data_ref_count(leaf, sdref);
ret = __add_prelim_ref(prefs, 0, NULL, 0, key.offset, ret = __add_prelim_ref(prefstate, 0, NULL, 0, key.offset,
bytenr, count, GFP_NOFS); bytenr, count, GFP_NOFS);
break; break;
} }
case BTRFS_TREE_BLOCK_REF_KEY: case BTRFS_TREE_BLOCK_REF_KEY:
ret = __add_prelim_ref(prefs, key.offset, NULL, ret = __add_prelim_ref(prefstate, key.offset, NULL,
info_level + 1, 0, info_level + 1, 0,
bytenr, 1, GFP_NOFS); bytenr, 1, GFP_NOFS);
break; break;
@ -697,7 +710,7 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
key.type = BTRFS_EXTENT_DATA_KEY; key.type = BTRFS_EXTENT_DATA_KEY;
key.offset = btrfs_extent_data_ref_offset(leaf, dref); key.offset = btrfs_extent_data_ref_offset(leaf, dref);
root = btrfs_extent_data_ref_root(leaf, dref); root = btrfs_extent_data_ref_root(leaf, dref);
ret = __add_prelim_ref(prefs, root, &key, 0, 0, ret = __add_prelim_ref(prefstate, root, &key, 0, 0,
bytenr, count, GFP_NOFS); bytenr, count, GFP_NOFS);
break; break;
} }
@ -729,12 +742,12 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
struct btrfs_path *path; struct btrfs_path *path;
int info_level = 0; int info_level = 0;
int ret; int ret;
struct list_head prefs; struct pref_state prefstate;
struct __prelim_ref *ref; struct __prelim_ref *ref;
struct extent_inode_elem *eie = NULL; struct extent_inode_elem *eie = NULL;
u64 total_refs = 0; u64 total_refs = 0;
INIT_LIST_HEAD(&prefs); init_pref_state(&prefstate);
key.objectid = bytenr; key.objectid = bytenr;
key.offset = (u64)-1; key.offset = (u64)-1;
@ -763,34 +776,35 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
if (key.objectid == bytenr && if (key.objectid == bytenr &&
(key.type == BTRFS_EXTENT_ITEM_KEY || (key.type == BTRFS_EXTENT_ITEM_KEY ||
key.type == BTRFS_METADATA_ITEM_KEY)) { key.type == BTRFS_METADATA_ITEM_KEY)) {
ret = __add_inline_refs(fs_info, path, bytenr, ret = __add_inline_refs(fs_info, &prefstate, path,
&info_level, &prefs, bytenr, &info_level,
&total_refs); &total_refs);
if (ret) if (ret)
goto out; goto out;
ret = __add_keyed_refs(fs_info, path, bytenr, ret = __add_keyed_refs(fs_info, &prefstate, path,
info_level, &prefs); bytenr, info_level);
if (ret) if (ret)
goto out; goto out;
} }
} }
btrfs_release_path(path); btrfs_release_path(path);
ret = __add_missing_keys(fs_info, &prefs); ret = __add_missing_keys(fs_info, &prefstate);
if (ret) if (ret)
goto out; goto out;
__merge_refs(&prefs, 1); __merge_refs(&prefstate, 1);
ret = __resolve_indirect_refs(fs_info, path, time_seq, &prefs, ret = __resolve_indirect_refs(fs_info, &prefstate, path, time_seq,
extent_item_pos, total_refs); extent_item_pos, total_refs);
if (ret) if (ret)
goto out; goto out;
__merge_refs(&prefs, 2); __merge_refs(&prefstate, 2);
while (!list_empty(&prefs)) { while (!list_empty(&prefstate.pending)) {
ref = list_first_entry(&prefs, struct __prelim_ref, list); ref = list_first_entry(&prefstate.pending,
struct __prelim_ref, list);
WARN_ON(ref->count < 0); WARN_ON(ref->count < 0);
if (roots && ref->count && ref->root_id && ref->parent == 0) { if (roots && ref->count && ref->root_id && ref->parent == 0) {
/* no parent == root of tree */ /* no parent == root of tree */
@ -839,8 +853,9 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
out: out:
btrfs_free_path(path); btrfs_free_path(path);
while (!list_empty(&prefs)) { while (!list_empty(&prefstate.pending)) {
ref = list_first_entry(&prefs, struct __prelim_ref, list); ref = list_first_entry(&prefstate.pending,
struct __prelim_ref, list);
list_del(&ref->list); list_del(&ref->list);
kfree(ref); kfree(ref);
} }