Skip to content

Commit c00869f

Browse files
Miao XieChris Mason
authored andcommitted
Btrfs: fix oops caused by the space balance and dead roots
When doing space balance and subvolume destroy at the same time, we met the following oops: kernel BUG at fs/btrfs/relocation.c:2247! RIP: 0010: [<ffffffffa04cec16>] prepare_to_merge+0x154/0x1f0 [btrfs] Call Trace: [<ffffffffa04b5ab7>] relocate_block_group+0x466/0x4e6 [btrfs] [<ffffffffa04b5c7a>] btrfs_relocate_block_group+0x143/0x275 [btrfs] [<ffffffffa0495c56>] btrfs_relocate_chunk.isra.27+0x5c/0x5a2 [btrfs] [<ffffffffa0459871>] ? btrfs_item_key_to_cpu+0x15/0x31 [btrfs] [<ffffffffa048b46a>] ? btrfs_get_token_64+0x7e/0xcd [btrfs] [<ffffffffa04a3467>] ? btrfs_tree_read_unlock_blocking+0xb2/0xb7 [btrfs] [<ffffffffa049907d>] btrfs_balance+0x9c7/0xb6f [btrfs] [<ffffffffa049ef84>] btrfs_ioctl_balance+0x234/0x2ac [btrfs] [<ffffffffa04a1e8e>] btrfs_ioctl+0xd87/0x1ef9 [btrfs] [<ffffffff81122f53>] ? path_openat+0x234/0x4db [<ffffffff813c3b78>] ? __do_page_fault+0x31d/0x391 [<ffffffff810f8ab6>] ? vma_link+0x74/0x94 [<ffffffff811250f5>] vfs_ioctl+0x1d/0x39 [<ffffffff811258c8>] do_vfs_ioctl+0x32d/0x3e2 [<ffffffff811259d4>] SyS_ioctl+0x57/0x83 [<ffffffff813c3bfa>] ? do_page_fault+0xe/0x10 [<ffffffff813c73c2>] system_call_fastpath+0x16/0x1b It is because we returned the error number if the reference of the root was 0 when doing space relocation. It was not right here, because though the root was dead(refs == 0), but the space it held still need be relocated, or we could not remove the block group. So in this case, we should return the root no matter it is dead or not. Signed-off-by: Miao Xie <[email protected]> Signed-off-by: Josef Bacik <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent 14927d9 commit c00869f

File tree

3 files changed

+17
-7
lines changed

3 files changed

+17
-7
lines changed

fs/btrfs/disk-io.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,8 +1561,9 @@ int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
15611561
return ret;
15621562
}
15631563

1564-
struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
1565-
struct btrfs_key *location)
1564+
struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
1565+
struct btrfs_key *location,
1566+
bool check_ref)
15661567
{
15671568
struct btrfs_root *root;
15681569
int ret;
@@ -1586,7 +1587,7 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
15861587
again:
15871588
root = btrfs_lookup_fs_root(fs_info, location->objectid);
15881589
if (root) {
1589-
if (btrfs_root_refs(&root->root_item) == 0)
1590+
if (check_ref && btrfs_root_refs(&root->root_item) == 0)
15901591
return ERR_PTR(-ENOENT);
15911592
return root;
15921593
}
@@ -1595,7 +1596,7 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
15951596
if (IS_ERR(root))
15961597
return root;
15971598

1598-
if (btrfs_root_refs(&root->root_item) == 0) {
1599+
if (check_ref && btrfs_root_refs(&root->root_item) == 0) {
15991600
ret = -ENOENT;
16001601
goto fail;
16011602
}

fs/btrfs/disk-io.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,17 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
6868
int btrfs_init_fs_root(struct btrfs_root *root);
6969
int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
7070
struct btrfs_root *root);
71-
struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
72-
struct btrfs_key *location);
71+
72+
struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
73+
struct btrfs_key *key,
74+
bool check_ref);
75+
static inline struct btrfs_root *
76+
btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
77+
struct btrfs_key *location)
78+
{
79+
return btrfs_get_fs_root(fs_info, location, true);
80+
}
81+
7382
int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info);
7483
void btrfs_btree_balance_dirty(struct btrfs_root *root);
7584
void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root);

fs/btrfs/relocation.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ static struct btrfs_root *read_fs_root(struct btrfs_fs_info *fs_info,
588588
else
589589
key.offset = (u64)-1;
590590

591-
return btrfs_read_fs_root_no_name(fs_info, &key);
591+
return btrfs_get_fs_root(fs_info, &key, false);
592592
}
593593

594594
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0

0 commit comments

Comments
 (0)