diff options
author | Jeff Mahoney <jeffm@suse.com> | 2016-08-17 21:58:33 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2016-08-25 06:58:29 -0400 |
commit | 35bbb97fc898aeb874cb7c8b746f091caa359994 (patch) | |
tree | 4ff7e4a0ac701e26985efb0d24c0ea3665791ffc | |
parent | 187ee58c62c1d0d238d3dc4835869d33e1869906 (diff) |
btrfs: don't create or leak aliased root while cleaning up orphans
commit 909c3a22da3 (Btrfs: fix loading of orphan roots leading to BUG_ON)
avoids the BUG_ON but can add an aliased root to the dead_roots list or
leak the root.
Since we've already been loading roots into the radix tree, we should
use it before looking the root up on disk.
Cc: <stable@vger.kernel.org> # 4.5
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
-rw-r--r-- | fs/btrfs/disk-io.c | 4 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 2 | ||||
-rw-r--r-- | fs/btrfs/root-tree.c | 27 |
3 files changed, 22 insertions, 11 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 17062223fac3..edda47162752 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1624,8 +1624,8 @@ fail: | |||
1624 | return ret; | 1624 | return ret; |
1625 | } | 1625 | } |
1626 | 1626 | ||
1627 | static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, | 1627 | struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, |
1628 | u64 root_id) | 1628 | u64 root_id) |
1629 | { | 1629 | { |
1630 | struct btrfs_root *root; | 1630 | struct btrfs_root *root; |
1631 | 1631 | ||
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index c9d42c92da2b..e0efe45e5282 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -68,6 +68,8 @@ struct extent_buffer *btrfs_find_tree_block(struct btrfs_fs_info *fs_info, | |||
68 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root, | 68 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root, |
69 | struct btrfs_key *location); | 69 | struct btrfs_key *location); |
70 | int btrfs_init_fs_root(struct btrfs_root *root); | 70 | int btrfs_init_fs_root(struct btrfs_root *root); |
71 | struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, | ||
72 | u64 root_id); | ||
71 | int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info, | 73 | int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info, |
72 | struct btrfs_root *root); | 74 | struct btrfs_root *root); |
73 | void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info); | 75 | void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info); |
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 7fd7e1830cfe..091296062456 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
@@ -272,6 +272,23 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) | |||
272 | root_key.objectid = key.offset; | 272 | root_key.objectid = key.offset; |
273 | key.offset++; | 273 | key.offset++; |
274 | 274 | ||
275 | /* | ||
276 | * The root might have been inserted already, as before we look | ||
277 | * for orphan roots, log replay might have happened, which | ||
278 | * triggers a transaction commit and qgroup accounting, which | ||
279 | * in turn reads and inserts fs roots while doing backref | ||
280 | * walking. | ||
281 | */ | ||
282 | root = btrfs_lookup_fs_root(tree_root->fs_info, | ||
283 | root_key.objectid); | ||
284 | if (root) { | ||
285 | WARN_ON(!test_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, | ||
286 | &root->state)); | ||
287 | if (btrfs_root_refs(&root->root_item) == 0) | ||
288 | btrfs_add_dead_root(root); | ||
289 | continue; | ||
290 | } | ||
291 | |||
275 | root = btrfs_read_fs_root(tree_root, &root_key); | 292 | root = btrfs_read_fs_root(tree_root, &root_key); |
276 | err = PTR_ERR_OR_ZERO(root); | 293 | err = PTR_ERR_OR_ZERO(root); |
277 | if (err && err != -ENOENT) { | 294 | if (err && err != -ENOENT) { |
@@ -310,16 +327,8 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) | |||
310 | set_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state); | 327 | set_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state); |
311 | 328 | ||
312 | err = btrfs_insert_fs_root(root->fs_info, root); | 329 | err = btrfs_insert_fs_root(root->fs_info, root); |
313 | /* | ||
314 | * The root might have been inserted already, as before we look | ||
315 | * for orphan roots, log replay might have happened, which | ||
316 | * triggers a transaction commit and qgroup accounting, which | ||
317 | * in turn reads and inserts fs roots while doing backref | ||
318 | * walking. | ||
319 | */ | ||
320 | if (err == -EEXIST) | ||
321 | err = 0; | ||
322 | if (err) { | 330 | if (err) { |
331 | BUG_ON(err == -EEXIST); | ||
323 | btrfs_free_fs_root(root); | 332 | btrfs_free_fs_root(root); |
324 | break; | 333 | break; |
325 | } | 334 | } |