OSDN Git Service

Btrfs: fix null pointer dereference on compressed write path error
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / fs / btrfs / relocation.c
index b4ca545..d6ccfb3 100644 (file)
@@ -921,9 +921,16 @@ again:
                        path2->slots[level]--;
 
                eb = path2->nodes[level];
-               WARN_ON(btrfs_node_blockptr(eb, path2->slots[level]) !=
-                       cur->bytenr);
-
+               if (btrfs_node_blockptr(eb, path2->slots[level]) !=
+                   cur->bytenr) {
+                       btrfs_err(root->fs_info,
+       "couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)",
+                                 cur->bytenr, level - 1, root->objectid,
+                                 node_key->objectid, node_key->type,
+                                 node_key->offset);
+                       err = -ENOENT;
+                       goto out;
+               }
                lower = cur;
                need_check = true;
                for (; level < BTRFS_MAX_LEVEL; level++) {
@@ -1311,18 +1318,19 @@ static void __del_reloc_root(struct btrfs_root *root)
        struct mapping_node *node = NULL;
        struct reloc_control *rc = root->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 && root->node) {
+               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(&root->fs_info->trans_lock);
        list_del_init(&root->root_list);
@@ -2344,6 +2352,10 @@ void free_reloc_roots(struct list_head *list)
                reloc_root = list_entry(list->next, struct btrfs_root,
                                        root_list);
                __del_reloc_root(reloc_root);
+               free_extent_buffer(reloc_root->node);
+               free_extent_buffer(reloc_root->commit_root);
+               reloc_root->node = NULL;
+               reloc_root->commit_root = NULL;
        }
 }
 
@@ -2676,11 +2688,15 @@ static int do_relocation(struct btrfs_trans_handle *trans,
 
                if (!upper->eb) {
                        ret = btrfs_search_slot(trans, root, key, path, 0, 1);
-                       if (ret < 0) {
-                               err = ret;
+                       if (ret) {
+                               if (ret < 0)
+                                       err = ret;
+                               else
+                                       err = -ENOENT;
+
+                               btrfs_release_path(path);
                                break;
                        }
-                       BUG_ON(ret > 0);
 
                        if (!upper->eb) {
                                upper->eb = path->nodes[upper->level];