Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 139460
b: refs/heads/master
c: 1887be6
h: refs/heads/master
v: v3
  • Loading branch information
Chris Mason committed Mar 24, 2009
1 parent d7cbfdb commit 5b5cca7
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 4 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: 44871b1b24b593996db43495cf4484cc580bdc10
refs/heads/master: 1887be66dcc3140a81d1299958a41fc0eedfa64f
18 changes: 18 additions & 0 deletions trunk/fs/btrfs/delayed-ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,24 @@ int btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
return 0;
}

/*
* this does a simple search for the head node for a given extent.
* It must be called with the delayed ref spinlock held, and it returns
* the head node if any where found, or NULL if not.
*/
struct btrfs_delayed_ref_head *
btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr)
{
struct btrfs_delayed_ref_node *ref;
struct btrfs_delayed_ref_root *delayed_refs;

delayed_refs = &trans->transaction->delayed_refs;
ref = tree_search(&delayed_refs->root, bytenr, (u64)-1);
if (ref)
return btrfs_delayed_node_to_head(ref);
return NULL;
}

/*
* add a delayed ref to the tree. This does all of the accounting required
* to make sure the delayed ref is eventually processed before this
Expand Down
5 changes: 2 additions & 3 deletions trunk/fs/btrfs/delayed-ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,8 @@ int btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
u64 ref_generation, u64 owner_objectid, int action,
int pin);

struct btrfs_delayed_ref *
btrfs_find_delayed_ref(struct btrfs_trans_handle *trans, u64 bytenr,
u64 parent);
struct btrfs_delayed_ref_head *
btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr);
int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr);
int btrfs_lock_delayed_ref(struct btrfs_trans_handle *trans,
struct btrfs_delayed_ref_node *ref,
Expand Down
67 changes: 67 additions & 0 deletions trunk/fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
if (!locked_ref && count == 0)
break;

cond_resched();
spin_lock(&delayed_refs->lock);
}
if (run_all) {
Expand All @@ -1045,6 +1046,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
mutex_unlock(&head->mutex);

btrfs_put_delayed_ref(ref);
cond_resched();
goto again;
}
node = rb_next(node);
Expand Down Expand Up @@ -2361,6 +2363,68 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
owner_objectid, pin, pin == 0, refs_to_drop);
}

/*
* when we free an extent, it is possible (and likely) that we free the last
* delayed ref for that extent as well. This searches the delayed ref tree for
* a given extent, and if there are no other delayed refs to be processed, it
* removes it from the tree.
*/
static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr)
{
struct btrfs_delayed_ref_head *head;
struct btrfs_delayed_ref_root *delayed_refs;
struct btrfs_delayed_ref_node *ref;
struct rb_node *node;
int ret;

delayed_refs = &trans->transaction->delayed_refs;
spin_lock(&delayed_refs->lock);
head = btrfs_find_delayed_ref_head(trans, bytenr);
if (!head)
goto out;

node = rb_prev(&head->node.rb_node);
if (!node)
goto out;

ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);

/* there are still entries for this ref, we can't drop it */
if (ref->bytenr == bytenr)
goto out;

/*
* waiting for the lock here would deadlock. If someone else has it
* locked they are already in the process of dropping it anyway
*/
if (!mutex_trylock(&head->mutex))
goto out;

/*
* at this point we have a head with no other entries. Go
* ahead and process it.
*/
head->node.in_tree = 0;
rb_erase(&head->node.rb_node, &delayed_refs->root);
delayed_refs->num_entries--;

/*
* we don't take a ref on the node because we're removing it from the
* tree, so we just steal the ref the tree was holding.
*/
spin_unlock(&delayed_refs->lock);

ret = run_one_delayed_ref(trans, root->fs_info->tree_root,
&head->node, head->must_insert_reserved);
BUG_ON(ret);
btrfs_put_delayed_ref(&head->node);
return 0;
out:
spin_unlock(&delayed_refs->lock);
return 0;
}

int btrfs_free_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 bytenr, u64 num_bytes, u64 parent,
Expand Down Expand Up @@ -2388,6 +2452,9 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
root_objectid, ref_generation,
owner_objectid,
BTRFS_DROP_DELAYED_REF, 1);
BUG_ON(ret);
ret = check_ref_cleanup(trans, root, bytenr);
BUG_ON(ret);
}
return ret;
}
Expand Down

0 comments on commit 5b5cca7

Please sign in to comment.