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 /fs/btrfs/root-tree.c | |
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>
Diffstat (limited to 'fs/btrfs/root-tree.c')
-rw-r--r-- | fs/btrfs/root-tree.c | 27 |
1 files changed, 18 insertions, 9 deletions
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 | } |