diff options
author | Qu Wenruo <wqu@suse.com> | 2018-07-03 17:10:07 +0800 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2018-08-06 13:12:42 +0200 |
commit | 389305b2aa68723c754f88d9dbd268a400e10664 (patch) | |
tree | 85dd721ee6bc9443517796cfdb208cc6b0e7916c /fs/btrfs/relocation.c | |
parent | ba480dd4db9f1798541eb2d1c423fc95feee8d36 (diff) | |
download | linux-stable-389305b2aa68723c754f88d9dbd268a400e10664.tar.gz linux-stable-389305b2aa68723c754f88d9dbd268a400e10664.tar.bz2 linux-stable-389305b2aa68723c754f88d9dbd268a400e10664.zip |
btrfs: relocation: Only remove reloc rb_trees if reloc control has been initialized
Invalid reloc tree can cause kernel NULL pointer dereference when btrfs
does some cleanup of the reloc roots.
It turns out that fs_info::reloc_ctl can be NULL in
btrfs_recover_relocation() as we allocate relocation control after all
reloc roots have been verified.
So when we hit: note, we haven't called set_reloc_control() thus
fs_info::reloc_ctl is still NULL.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=199833
Reported-by: Xu Wen <wen.xu@gatech.edu>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Tested-by: Gu Jinxiang <gujx@cn.fujitsu.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/relocation.c')
-rw-r--r-- | fs/btrfs/relocation.c | 23 |
1 files changed, 12 insertions, 11 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 229f721cbde9..b98d7a594542 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -1281,18 +1281,19 @@ static void __del_reloc_root(struct btrfs_root *root) struct mapping_node *node = NULL; struct reloc_control *rc = fs_info->reloc_ctl; - spin_lock(&rc->reloc_root_tree.lock); - rb_node = tree_search(&rc->reloc_root_tree.rb_root, - root->node->start); - if (rb_node) { - node = rb_entry(rb_node, struct mapping_node, rb_node); - rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); + if (rc) { + spin_lock(&rc->reloc_root_tree.lock); + rb_node = tree_search(&rc->reloc_root_tree.rb_root, + root->node->start); + if (rb_node) { + node = rb_entry(rb_node, struct mapping_node, rb_node); + rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); + } + spin_unlock(&rc->reloc_root_tree.lock); + if (!node) + return; + BUG_ON((struct btrfs_root *)node->data != root); } - spin_unlock(&rc->reloc_root_tree.lock); - - if (!node) - return; - BUG_ON((struct btrfs_root *)node->data != root); spin_lock(&fs_info->trans_lock); list_del_init(&root->root_list); |