aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 9b5da2b013e4..8471c79b0877 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1021,6 +1021,7 @@ again:
1021 if (!locked_ref && count == 0) 1021 if (!locked_ref && count == 0)
1022 break; 1022 break;
1023 1023
1024 cond_resched();
1024 spin_lock(&delayed_refs->lock); 1025 spin_lock(&delayed_refs->lock);
1025 } 1026 }
1026 if (run_all) { 1027 if (run_all) {
@@ -1045,6 +1046,7 @@ again:
1045 mutex_unlock(&head->mutex); 1046 mutex_unlock(&head->mutex);
1046 1047
1047 btrfs_put_delayed_ref(ref); 1048 btrfs_put_delayed_ref(ref);
1049 cond_resched();
1048 goto again; 1050 goto again;
1049 } 1051 }
1050 node = rb_next(node); 1052 node = rb_next(node);
@@ -2361,6 +2363,68 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
2361 owner_objectid, pin, pin == 0, refs_to_drop); 2363 owner_objectid, pin, pin == 0, refs_to_drop);
2362} 2364}
2363 2365
2366/*
2367 * when we free an extent, it is possible (and likely) that we free the last
2368 * delayed ref for that extent as well. This searches the delayed ref tree for
2369 * a given extent, and if there are no other delayed refs to be processed, it
2370 * removes it from the tree.
2371 */
2372static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
2373 struct btrfs_root *root, u64 bytenr)
2374{
2375 struct btrfs_delayed_ref_head *head;
2376 struct btrfs_delayed_ref_root *delayed_refs;
2377 struct btrfs_delayed_ref_node *ref;
2378 struct rb_node *node;
2379 int ret;
2380
2381 delayed_refs = &trans->transaction->delayed_refs;
2382 spin_lock(&delayed_refs->lock);
2383 head = btrfs_find_delayed_ref_head(trans, bytenr);
2384 if (!head)
2385 goto out;
2386
2387 node = rb_prev(&head->node.rb_node);
2388 if (!node)
2389 goto out;
2390
2391 ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
2392
2393 /* there are still entries for this ref, we can't drop it */
2394 if (ref->bytenr == bytenr)
2395 goto out;
2396
2397 /*
2398 * waiting for the lock here would deadlock. If someone else has it
2399 * locked they are already in the process of dropping it anyway
2400 */
2401 if (!mutex_trylock(&head->mutex))
2402 goto out;
2403
2404 /*
2405 * at this point we have a head with no other entries. Go
2406 * ahead and process it.
2407 */
2408 head->node.in_tree = 0;
2409 rb_erase(&head->node.rb_node, &delayed_refs->root);
2410 delayed_refs->num_entries--;
2411
2412 /*
2413 * we don't take a ref on the node because we're removing it from the
2414 * tree, so we just steal the ref the tree was holding.
2415 */
2416 spin_unlock(&delayed_refs->lock);
2417
2418 ret = run_one_delayed_ref(trans, root->fs_info->tree_root,
2419 &head->node, head->must_insert_reserved);
2420 BUG_ON(ret);
2421 btrfs_put_delayed_ref(&head->node);
2422 return 0;
2423out:
2424 spin_unlock(&delayed_refs->lock);
2425 return 0;
2426}
2427
2364int btrfs_free_extent(struct btrfs_trans_handle *trans, 2428int btrfs_free_extent(struct btrfs_trans_handle *trans,
2365 struct btrfs_root *root, 2429 struct btrfs_root *root,
2366 u64 bytenr, u64 num_bytes, u64 parent, 2430 u64 bytenr, u64 num_bytes, u64 parent,
@@ -2388,6 +2452,9 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
2388 root_objectid, ref_generation, 2452 root_objectid, ref_generation,
2389 owner_objectid, 2453 owner_objectid,
2390 BTRFS_DROP_DELAYED_REF, 1); 2454 BTRFS_DROP_DELAYED_REF, 1);
2455 BUG_ON(ret);
2456 ret = check_ref_cleanup(trans, root, bytenr);
2457 BUG_ON(ret);
2391 } 2458 }
2392 return ret; 2459 return ret;
2393} 2460}