Skip to content

Commit

Permalink
Btrfs: fix locking in btrfs_destroy_delayed_refs
Browse files Browse the repository at this point in the history
The transaction abort stuff was throwing warnings from the list debugging
code because we do a list_del_init outside of the delayed_refs spin lock.
The delayed refs locking makes baby Jesus cry so it's not hard to get wrong,
but we need to take the ref head mutex to make sure it's not being processed
currently, and so if it is we need to drop the spin lock and then take and
drop the mutex and do the search again.  If we can take the mutex then we
can safely remove the head from the list and carry on.  Now when the
transaction aborts I don't get the list debugging warnings.  Thanks,

Signed-off-by: Josef Bacik <josef@redhat.com>
  • Loading branch information
Josef Bacik authored and Chris Mason committed Jun 15, 2012
1 parent beb42dd commit b939d1a
Showing 1 changed file with 17 additions and 13 deletions.
30 changes: 17 additions & 13 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -3400,39 +3400,43 @@ int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,

delayed_refs = &trans->delayed_refs;

again:
spin_lock(&delayed_refs->lock);
if (delayed_refs->num_entries == 0) {
spin_unlock(&delayed_refs->lock);
printk(KERN_INFO "delayed_refs has NO entry\n");
return ret;
}

node = rb_first(&delayed_refs->root);
while (node) {
while ((node = rb_first(&delayed_refs->root)) != NULL) {
ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
node = rb_next(node);

ref->in_tree = 0;
rb_erase(&ref->rb_node, &delayed_refs->root);
delayed_refs->num_entries--;

atomic_set(&ref->refs, 1);
if (btrfs_delayed_ref_is_head(ref)) {
struct btrfs_delayed_ref_head *head;

head = btrfs_delayed_node_to_head(ref);
spin_unlock(&delayed_refs->lock);
mutex_lock(&head->mutex);
if (!mutex_trylock(&head->mutex)) {
atomic_inc(&ref->refs);
spin_unlock(&delayed_refs->lock);

/* Need to wait for the delayed ref to run */
mutex_lock(&head->mutex);
mutex_unlock(&head->mutex);
btrfs_put_delayed_ref(ref);

continue;
}

kfree(head->extent_op);
delayed_refs->num_heads--;
if (list_empty(&head->cluster))
delayed_refs->num_heads_ready--;
list_del_init(&head->cluster);
mutex_unlock(&head->mutex);
btrfs_put_delayed_ref(ref);
goto again;
}
ref->in_tree = 0;
rb_erase(&ref->rb_node, &delayed_refs->root);
delayed_refs->num_entries--;

spin_unlock(&delayed_refs->lock);
btrfs_put_delayed_ref(ref);

Expand Down

0 comments on commit b939d1a

Please sign in to comment.