Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 322368
b: refs/heads/master
c: ae1e206
h: refs/heads/master
v: v3
  • Loading branch information
Josef Bacik authored and Chris Mason committed Aug 28, 2012
1 parent de20621 commit c31be6f
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 28 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5a24e84c55f57cc49bd1cab531b6ef28b6b7bdaa
refs/heads/master: ae1e206b806ccc490dadff59af8a7a2477b32884
155 changes: 128 additions & 27 deletions trunk/fs/btrfs/delayed-ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,14 @@
static int comp_tree_refs(struct btrfs_delayed_tree_ref *ref2,
struct btrfs_delayed_tree_ref *ref1)
{
if (ref1->node.type == BTRFS_TREE_BLOCK_REF_KEY) {
if (ref1->root < ref2->root)
return -1;
if (ref1->root > ref2->root)
return 1;
} else {
if (ref1->parent < ref2->parent)
return -1;
if (ref1->parent > ref2->parent)
return 1;
}
if (ref1->root < ref2->root)
return -1;
if (ref1->root > ref2->root)
return 1;
if (ref1->parent < ref2->parent)
return -1;
if (ref1->parent > ref2->parent)
return 1;
return 0;
}

Expand Down Expand Up @@ -85,7 +82,8 @@ static int comp_data_refs(struct btrfs_delayed_data_ref *ref2,
* type of the delayed backrefs and content of delayed backrefs.
*/
static int comp_entry(struct btrfs_delayed_ref_node *ref2,
struct btrfs_delayed_ref_node *ref1)
struct btrfs_delayed_ref_node *ref1,
bool compare_seq)
{
if (ref1->bytenr < ref2->bytenr)
return -1;
Expand All @@ -102,10 +100,12 @@ static int comp_entry(struct btrfs_delayed_ref_node *ref2,
if (ref1->type > ref2->type)
return 1;
/* merging of sequenced refs is not allowed */
if (ref1->seq < ref2->seq)
return -1;
if (ref1->seq > ref2->seq)
return 1;
if (compare_seq) {
if (ref1->seq < ref2->seq)
return -1;
if (ref1->seq > ref2->seq)
return 1;
}
if (ref1->type == BTRFS_TREE_BLOCK_REF_KEY ||
ref1->type == BTRFS_SHARED_BLOCK_REF_KEY) {
return comp_tree_refs(btrfs_delayed_node_to_tree_ref(ref2),
Expand Down Expand Up @@ -139,7 +139,7 @@ static struct btrfs_delayed_ref_node *tree_insert(struct rb_root *root,
entry = rb_entry(parent_node, struct btrfs_delayed_ref_node,
rb_node);

cmp = comp_entry(entry, ins);
cmp = comp_entry(entry, ins, 1);
if (cmp < 0)
p = &(*p)->rb_left;
else if (cmp > 0)
Expand Down Expand Up @@ -233,6 +233,114 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
return 0;
}

static void inline drop_delayed_ref(struct btrfs_trans_handle *trans,
struct btrfs_delayed_ref_root *delayed_refs,
struct btrfs_delayed_ref_node *ref)
{
rb_erase(&ref->rb_node, &delayed_refs->root);
ref->in_tree = 0;
btrfs_put_delayed_ref(ref);
delayed_refs->num_entries--;
if (trans->delayed_ref_updates)
trans->delayed_ref_updates--;
}

static int merge_ref(struct btrfs_trans_handle *trans,
struct btrfs_delayed_ref_root *delayed_refs,
struct btrfs_delayed_ref_node *ref, u64 seq)
{
struct rb_node *node;
int merged = 0;
int mod = 0;
int done = 0;

node = rb_prev(&ref->rb_node);
while (node) {
struct btrfs_delayed_ref_node *next;

next = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
node = rb_prev(node);
if (next->bytenr != ref->bytenr)
break;
if (seq && next->seq >= seq)
break;
if (comp_entry(ref, next, 0))
continue;

if (ref->action == next->action) {
mod = next->ref_mod;
} else {
if (ref->ref_mod < next->ref_mod) {
struct btrfs_delayed_ref_node *tmp;

tmp = ref;
ref = next;
next = tmp;
done = 1;
}
mod = -next->ref_mod;
}

merged++;
drop_delayed_ref(trans, delayed_refs, next);
ref->ref_mod += mod;
if (ref->ref_mod == 0) {
drop_delayed_ref(trans, delayed_refs, ref);
break;
} else {
/*
* You can't have multiples of the same ref on a tree
* block.
*/
WARN_ON(ref->type == BTRFS_TREE_BLOCK_REF_KEY ||
ref->type == BTRFS_SHARED_BLOCK_REF_KEY);
}

if (done)
break;
node = rb_prev(&ref->rb_node);
}

return merged;
}

void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info,
struct btrfs_delayed_ref_root *delayed_refs,
struct btrfs_delayed_ref_head *head)
{
struct rb_node *node;
u64 seq = 0;

spin_lock(&fs_info->tree_mod_seq_lock);
if (!list_empty(&fs_info->tree_mod_seq_list)) {
struct seq_list *elem;

elem = list_first_entry(&fs_info->tree_mod_seq_list,
struct seq_list, list);
seq = elem->seq;
}
spin_unlock(&fs_info->tree_mod_seq_lock);

node = rb_prev(&head->node.rb_node);
while (node) {
struct btrfs_delayed_ref_node *ref;

ref = rb_entry(node, struct btrfs_delayed_ref_node,
rb_node);
if (ref->bytenr != head->node.bytenr)
break;

/* We can't merge refs that are outside of our seq count */
if (seq && ref->seq >= seq)
break;
if (merge_ref(trans, delayed_refs, ref, seq))
node = rb_prev(&head->node.rb_node);
else
node = rb_prev(node);
}
}

int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info,
struct btrfs_delayed_ref_root *delayed_refs,
u64 seq)
Expand Down Expand Up @@ -336,18 +444,11 @@ update_existing_ref(struct btrfs_trans_handle *trans,
* every changing the extent allocation tree.
*/
existing->ref_mod--;
if (existing->ref_mod == 0) {
rb_erase(&existing->rb_node,
&delayed_refs->root);
existing->in_tree = 0;
btrfs_put_delayed_ref(existing);
delayed_refs->num_entries--;
if (trans->delayed_ref_updates)
trans->delayed_ref_updates--;
} else {
if (existing->ref_mod == 0)
drop_delayed_ref(trans, delayed_refs, existing);
else
WARN_ON(existing->type == BTRFS_TREE_BLOCK_REF_KEY ||
existing->type == BTRFS_SHARED_BLOCK_REF_KEY);
}
} else {
WARN_ON(existing->type == BTRFS_TREE_BLOCK_REF_KEY ||
existing->type == BTRFS_SHARED_BLOCK_REF_KEY);
Expand Down
4 changes: 4 additions & 0 deletions trunk/fs/btrfs/delayed-ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
struct btrfs_trans_handle *trans,
u64 bytenr, u64 num_bytes,
struct btrfs_delayed_extent_op *extent_op);
void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info,
struct btrfs_delayed_ref_root *delayed_refs,
struct btrfs_delayed_ref_head *head);

struct btrfs_delayed_ref_head *
btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr);
Expand Down
10 changes: 10 additions & 0 deletions trunk/fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -2251,6 +2251,16 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
}
}

/*
* We need to try and merge add/drops of the same ref since we
* can run into issues with relocate dropping the implicit ref
* and then it being added back again before the drop can
* finish. If we merged anything we need to re-loop so we can
* get a good ref.
*/
btrfs_merge_delayed_refs(trans, fs_info, delayed_refs,
locked_ref);

/*
* locked_ref is the head node, so we have to go one
* node back for any delayed ref updates
Expand Down

0 comments on commit c31be6f

Please sign in to comment.