diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
| -rw-r--r-- | fs/btrfs/extent-tree.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0236de711989..1204c8ef6f32 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -7466,6 +7466,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7466 | int err = 0; | 7466 | int err = 0; |
| 7467 | int ret; | 7467 | int ret; |
| 7468 | int level; | 7468 | int level; |
| 7469 | bool root_dropped = false; | ||
| 7469 | 7470 | ||
| 7470 | path = btrfs_alloc_path(); | 7471 | path = btrfs_alloc_path(); |
| 7471 | if (!path) { | 7472 | if (!path) { |
| @@ -7523,6 +7524,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7523 | while (1) { | 7524 | while (1) { |
| 7524 | btrfs_tree_lock(path->nodes[level]); | 7525 | btrfs_tree_lock(path->nodes[level]); |
| 7525 | btrfs_set_lock_blocking(path->nodes[level]); | 7526 | btrfs_set_lock_blocking(path->nodes[level]); |
| 7527 | path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; | ||
| 7526 | 7528 | ||
| 7527 | ret = btrfs_lookup_extent_info(trans, root, | 7529 | ret = btrfs_lookup_extent_info(trans, root, |
| 7528 | path->nodes[level]->start, | 7530 | path->nodes[level]->start, |
| @@ -7538,6 +7540,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7538 | break; | 7540 | break; |
| 7539 | 7541 | ||
| 7540 | btrfs_tree_unlock(path->nodes[level]); | 7542 | btrfs_tree_unlock(path->nodes[level]); |
| 7543 | path->locks[level] = 0; | ||
| 7541 | WARN_ON(wc->refs[level] != 1); | 7544 | WARN_ON(wc->refs[level] != 1); |
| 7542 | level--; | 7545 | level--; |
| 7543 | } | 7546 | } |
| @@ -7552,11 +7555,6 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7552 | wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root); | 7555 | wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root); |
| 7553 | 7556 | ||
| 7554 | while (1) { | 7557 | while (1) { |
| 7555 | if (!for_reloc && btrfs_need_cleaner_sleep(root)) { | ||
| 7556 | pr_debug("btrfs: drop snapshot early exit\n"); | ||
| 7557 | err = -EAGAIN; | ||
| 7558 | goto out_end_trans; | ||
| 7559 | } | ||
| 7560 | 7558 | ||
| 7561 | ret = walk_down_tree(trans, root, path, wc); | 7559 | ret = walk_down_tree(trans, root, path, wc); |
| 7562 | if (ret < 0) { | 7560 | if (ret < 0) { |
| @@ -7584,7 +7582,8 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7584 | } | 7582 | } |
| 7585 | 7583 | ||
| 7586 | BUG_ON(wc->level == 0); | 7584 | BUG_ON(wc->level == 0); |
| 7587 | if (btrfs_should_end_transaction(trans, tree_root)) { | 7585 | if (btrfs_should_end_transaction(trans, tree_root) || |
| 7586 | (!for_reloc && btrfs_need_cleaner_sleep(root))) { | ||
| 7588 | ret = btrfs_update_root(trans, tree_root, | 7587 | ret = btrfs_update_root(trans, tree_root, |
| 7589 | &root->root_key, | 7588 | &root->root_key, |
| 7590 | root_item); | 7589 | root_item); |
| @@ -7595,6 +7594,12 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7595 | } | 7594 | } |
| 7596 | 7595 | ||
| 7597 | btrfs_end_transaction_throttle(trans, tree_root); | 7596 | btrfs_end_transaction_throttle(trans, tree_root); |
| 7597 | if (!for_reloc && btrfs_need_cleaner_sleep(root)) { | ||
| 7598 | pr_debug("btrfs: drop snapshot early exit\n"); | ||
| 7599 | err = -EAGAIN; | ||
| 7600 | goto out_free; | ||
| 7601 | } | ||
| 7602 | |||
| 7598 | trans = btrfs_start_transaction(tree_root, 0); | 7603 | trans = btrfs_start_transaction(tree_root, 0); |
| 7599 | if (IS_ERR(trans)) { | 7604 | if (IS_ERR(trans)) { |
| 7600 | err = PTR_ERR(trans); | 7605 | err = PTR_ERR(trans); |
| @@ -7639,12 +7644,22 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 7639 | free_extent_buffer(root->commit_root); | 7644 | free_extent_buffer(root->commit_root); |
| 7640 | btrfs_put_fs_root(root); | 7645 | btrfs_put_fs_root(root); |
| 7641 | } | 7646 | } |
| 7647 | root_dropped = true; | ||
| 7642 | out_end_trans: | 7648 | out_end_trans: |
| 7643 | btrfs_end_transaction_throttle(trans, tree_root); | 7649 | btrfs_end_transaction_throttle(trans, tree_root); |
| 7644 | out_free: | 7650 | out_free: |
| 7645 | kfree(wc); | 7651 | kfree(wc); |
| 7646 | btrfs_free_path(path); | 7652 | btrfs_free_path(path); |
| 7647 | out: | 7653 | out: |
| 7654 | /* | ||
| 7655 | * So if we need to stop dropping the snapshot for whatever reason we | ||
| 7656 | * need to make sure to add it back to the dead root list so that we | ||
| 7657 | * keep trying to do the work later. This also cleans up roots if we | ||
| 7658 | * don't have it in the radix (like when we recover after a power fail | ||
| 7659 | * or unmount) so we don't leak memory. | ||
| 7660 | */ | ||
| 7661 | if (root_dropped == false) | ||
| 7662 | btrfs_add_dead_root(root); | ||
| 7648 | if (err) | 7663 | if (err) |
| 7649 | btrfs_std_error(root->fs_info, err); | 7664 | btrfs_std_error(root->fs_info, err); |
| 7650 | return err; | 7665 | return err; |
