diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 67 |
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 | */ | ||
2372 | static 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; | ||
2423 | out: | ||
2424 | spin_unlock(&delayed_refs->lock); | ||
2425 | return 0; | ||
2426 | } | ||
2427 | |||
2364 | int btrfs_free_extent(struct btrfs_trans_handle *trans, | 2428 | int 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 | } |