summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2013-08-11 15:33:54 -0700
committerOlof Johansson <olof@lixom.net>2013-08-11 15:33:54 -0700
commit4ddbed9618724d52a7a79c1e10ef5adb46fcccf7 (patch)
treeffe64efb333d7dcdb5b2cf43ffef97b25261702c /fs/btrfs/extent-tree.c
parent16649596d701c0f4f767bbcad7da4d6343ba8a9e (diff)
parentfa8c5a811e0e7c3e1c49b2e58fcb4db549b5719a (diff)
Merge tag 'boards-3.12' of git://git.infradead.org/linux-mvebu into next/boards
From Jason Cooper: mvebu boards changes for v3.12 - convert kirkwood, dove, orion5x to DT init of mv643xx_eth - _lots_ of board code removal :) - convert kirkwood, dove and orion5x to DT init of clocksource and irqchip * tag 'boards-3.12' of git://git.infradead.org/linux-mvebu: ARM: plat-orion: add reg offset to DT irq driver stub ARM: kirkwood: remove obsolete SDIO clock gate workaround ARM: kirkwood: convert to DT irqchip and clocksource ARM: dove: convert to DT irqchip and clocksource ARM: orion5x: update intc device tree node to new reg layout ARM: kirkwood: move device tree nodes to DT irqchip and clocksource ARM: dove: move device tree nodes to DT irqchip and clocksource ARM: orion5x: remove legacy mv643xx_eth board setup ARM: kirkwood: remove legacy clk alias for mv643xx_eth ARM: kirkwood: remove redundant DT board files ARM: dove: remove legacy mv643xx_eth setup ARM: orion5x: add gigabit ethernet and mvmdio device tree nodes ARM: kirkwood: add gigabit ethernet and mvmdio device tree nodes ARM: dove: add gigabit ethernet and mvmdio device tree nodes + Linux 3.11-rc2 Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c27
1 files changed, 21 insertions, 6 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 0236de71198..1204c8ef6f3 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,
int err = 0;
int ret;
int level;
+ bool root_dropped = false;
path = btrfs_alloc_path();
if (!path) {
@@ -7523,6 +7524,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
while (1) {
btrfs_tree_lock(path->nodes[level]);
btrfs_set_lock_blocking(path->nodes[level]);
+ path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING;
ret = btrfs_lookup_extent_info(trans, root,
path->nodes[level]->start,
@@ -7538,6 +7540,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
break;
btrfs_tree_unlock(path->nodes[level]);
+ path->locks[level] = 0;
WARN_ON(wc->refs[level] != 1);
level--;
}
@@ -7552,11 +7555,6 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root);
while (1) {
- if (!for_reloc && btrfs_need_cleaner_sleep(root)) {
- pr_debug("btrfs: drop snapshot early exit\n");
- err = -EAGAIN;
- goto out_end_trans;
- }
ret = walk_down_tree(trans, root, path, wc);
if (ret < 0) {
@@ -7584,7 +7582,8 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
}
BUG_ON(wc->level == 0);
- if (btrfs_should_end_transaction(trans, tree_root)) {
+ if (btrfs_should_end_transaction(trans, tree_root) ||
+ (!for_reloc && btrfs_need_cleaner_sleep(root))) {
ret = btrfs_update_root(trans, tree_root,
&root->root_key,
root_item);
@@ -7595,6 +7594,12 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
}
btrfs_end_transaction_throttle(trans, tree_root);
+ if (!for_reloc && btrfs_need_cleaner_sleep(root)) {
+ pr_debug("btrfs: drop snapshot early exit\n");
+ err = -EAGAIN;
+ goto out_free;
+ }
+
trans = btrfs_start_transaction(tree_root, 0);
if (IS_ERR(trans)) {
err = PTR_ERR(trans);
@@ -7639,12 +7644,22 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
free_extent_buffer(root->commit_root);
btrfs_put_fs_root(root);
}
+ root_dropped = true;
out_end_trans:
btrfs_end_transaction_throttle(trans, tree_root);
out_free:
kfree(wc);
btrfs_free_path(path);
out:
+ /*
+ * So if we need to stop dropping the snapshot for whatever reason we
+ * need to make sure to add it back to the dead root list so that we
+ * keep trying to do the work later. This also cleans up roots if we
+ * don't have it in the radix (like when we recover after a power fail
+ * or unmount) so we don't leak memory.
+ */
+ if (root_dropped == false)
+ btrfs_add_dead_root(root);
if (err)
btrfs_std_error(root->fs_info, err);
return err;