aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/delayed-ref.c18
-rw-r--r--fs/btrfs/delayed-ref.h5
-rw-r--r--fs/btrfs/extent-tree.c67
3 files changed, 87 insertions, 3 deletions
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
index 874565a1f634..3e7eeaf86408 100644
--- a/fs/btrfs/delayed-ref.c
+++ b/fs/btrfs/delayed-ref.c
@@ -511,6 +511,24 @@ int btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
511} 511}
512 512
513/* 513/*
514 * this does a simple search for the head node for a given extent.
515 * It must be called with the delayed ref spinlock held, and it returns
516 * the head node if any where found, or NULL if not.
517 */
518struct btrfs_delayed_ref_head *
519btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr)
520{
521 struct btrfs_delayed_ref_node *ref;
522 struct btrfs_delayed_ref_root *delayed_refs;
523
524 delayed_refs = &trans->transaction->delayed_refs;
525 ref = tree_search(&delayed_refs->root, bytenr, (u64)-1);
526 if (ref)
527 return btrfs_delayed_node_to_head(ref);
528 return NULL;
529}
530
531/*
514 * add a delayed ref to the tree. This does all of the accounting required 532 * add a delayed ref to the tree. This does all of the accounting required
515 * to make sure the delayed ref is eventually processed before this 533 * to make sure the delayed ref is eventually processed before this
516 * transaction commits. 534 * transaction commits.
diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h
index 37919e5c007f..c345fee9f96b 100644
--- a/fs/btrfs/delayed-ref.h
+++ b/fs/btrfs/delayed-ref.h
@@ -137,9 +137,8 @@ int btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
137 u64 ref_generation, u64 owner_objectid, int action, 137 u64 ref_generation, u64 owner_objectid, int action,
138 int pin); 138 int pin);
139 139
140struct btrfs_delayed_ref * 140struct btrfs_delayed_ref_head *
141btrfs_find_delayed_ref(struct btrfs_trans_handle *trans, u64 bytenr, 141btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr);
142 u64 parent);
143int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr); 142int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr);
144int btrfs_lock_delayed_ref(struct btrfs_trans_handle *trans, 143int btrfs_lock_delayed_ref(struct btrfs_trans_handle *trans,
145 struct btrfs_delayed_ref_node *ref, 144 struct btrfs_delayed_ref_node *ref,
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}