aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2012-05-31 11:06:33 -0400
committerChris Mason <chris.mason@oracle.com>2012-06-14 21:29:11 -0400
commitb939d1ab76b4aa816343cdbd8b44ce9929a3b9ef (patch)
tree231ff204d260f0d50b8789029937750d7d4f8952 /fs/btrfs
parentbeb42dd793193a3d4e72970bfa73cd8810f63cea (diff)
Btrfs: fix locking in btrfs_destroy_delayed_refs
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>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/disk-io.c30
1 files changed, 17 insertions, 13 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index b99d5127ba1..c79ddc75608 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3400,7 +3400,6 @@ int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
3400 3400
3401 delayed_refs = &trans->delayed_refs; 3401 delayed_refs = &trans->delayed_refs;
3402 3402
3403again:
3404 spin_lock(&delayed_refs->lock); 3403 spin_lock(&delayed_refs->lock);
3405 if (delayed_refs->num_entries == 0) { 3404 if (delayed_refs->num_entries == 0) {
3406 spin_unlock(&delayed_refs->lock); 3405 spin_unlock(&delayed_refs->lock);
@@ -3408,31 +3407,36 @@ again:
3408 return ret; 3407 return ret;
3409 } 3408 }
3410 3409
3411 node = rb_first(&delayed_refs->root); 3410 while ((node = rb_first(&delayed_refs->root)) != NULL) {
3412 while (node) {
3413 ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node); 3411 ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
3414 node = rb_next(node);
3415
3416 ref->in_tree = 0;
3417 rb_erase(&ref->rb_node, &delayed_refs->root);
3418 delayed_refs->num_entries--;
3419 3412
3420 atomic_set(&ref->refs, 1); 3413 atomic_set(&ref->refs, 1);
3421 if (btrfs_delayed_ref_is_head(ref)) { 3414 if (btrfs_delayed_ref_is_head(ref)) {
3422 struct btrfs_delayed_ref_head *head; 3415 struct btrfs_delayed_ref_head *head;
3423 3416
3424 head = btrfs_delayed_node_to_head(ref); 3417 head = btrfs_delayed_node_to_head(ref);
3425 spin_unlock(&delayed_refs->lock); 3418 if (!mutex_trylock(&head->mutex)) {
3426 mutex_lock(&head->mutex); 3419 atomic_inc(&ref->refs);
3420 spin_unlock(&delayed_refs->lock);
3421
3422 /* Need to wait for the delayed ref to run */
3423 mutex_lock(&head->mutex);
3424 mutex_unlock(&head->mutex);
3425 btrfs_put_delayed_ref(ref);
3426
3427 continue;
3428 }
3429
3427 kfree(head->extent_op); 3430 kfree(head->extent_op);
3428 delayed_refs->num_heads--; 3431 delayed_refs->num_heads--;
3429 if (list_empty(&head->cluster)) 3432 if (list_empty(&head->cluster))
3430 delayed_refs->num_heads_ready--; 3433 delayed_refs->num_heads_ready--;
3431 list_del_init(&head->cluster); 3434 list_del_init(&head->cluster);
3432 mutex_unlock(&head->mutex);
3433 btrfs_put_delayed_ref(ref);
3434 goto again;
3435 } 3435 }
3436 ref->in_tree = 0;
3437 rb_erase(&ref->rb_node, &delayed_refs->root);
3438 delayed_refs->num_entries--;
3439
3436 spin_unlock(&delayed_refs->lock); 3440 spin_unlock(&delayed_refs->lock);
3437 btrfs_put_delayed_ref(ref); 3441 btrfs_put_delayed_ref(ref);
3438 3442