btrfs: relocation: set trans to be NULL after ending transaction
[sfrench/cifs-2.6.git] / fs / btrfs / relocation.c
index 8783a1776540fbb214a6d464858d9a9fb36be843..a3f75b8926d4474aa1093ffdd852d422b853e2d2 100644 (file)
@@ -648,8 +648,8 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
                                        int level, u64 bytenr)
 {
        struct backref_cache *cache = &rc->backref_cache;
-       struct btrfs_path *path1;
-       struct btrfs_path *path2;
+       struct btrfs_path *path1; /* For searching extent root */
+       struct btrfs_path *path2; /* For searching parent of TREE_BLOCK_REF */
        struct extent_buffer *eb;
        struct btrfs_root *root;
        struct backref_node *cur;
@@ -662,7 +662,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
        struct btrfs_key key;
        unsigned long end;
        unsigned long ptr;
-       LIST_HEAD(list);
+       LIST_HEAD(list); /* Pending edge list, upper node needs to be checked */
        LIST_HEAD(useless);
        int cowonly;
        int ret;
@@ -778,6 +778,10 @@ again:
                                key.type != BTRFS_SHARED_BLOCK_REF_KEY);
                }
 
+               /*
+                * Parent node found and matches current inline ref, no need to
+                * rebuild this node for this inline ref.
+                */
                if (exist &&
                    ((key.type == BTRFS_TREE_BLOCK_REF_KEY &&
                      exist->owner == key.offset) ||
@@ -787,11 +791,12 @@ again:
                        goto next;
                }
 
+               /* SHARED_BLOCK_REF means key.offset is the parent bytenr */
                if (key.type == BTRFS_SHARED_BLOCK_REF_KEY) {
                        if (key.objectid == key.offset) {
                                /*
-                                * only root blocks of reloc trees use
-                                * backref of this type.
+                                * Only root blocks of reloc trees use backref
+                                * pointing to itself.
                                 */
                                root = find_reloc_root(rc, cur->bytenr);
                                ASSERT(root);
@@ -840,7 +845,11 @@ again:
                        goto next;
                }
 
-               /* key.type == BTRFS_TREE_BLOCK_REF_KEY */
+               /*
+                * key.type == BTRFS_TREE_BLOCK_REF_KEY, inline ref offset
+                * means the root objectid. We need to search the tree to get
+                * its parent bytenr.
+                */
                root = read_fs_root(rc->extent_root->fs_info, key.offset);
                if (IS_ERR(root)) {
                        err = PTR_ERR(root);
@@ -863,10 +872,7 @@ again:
 
                level = cur->level + 1;
 
-               /*
-                * searching the tree to find upper level blocks
-                * reference the block.
-                */
+               /* Search the tree to find parent blocks referring the block. */
                path2->search_commit_root = 1;
                path2->skip_locking = 1;
                path2->lowest_level = level;
@@ -884,7 +890,8 @@ again:
                    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,
+                                 cur->bytenr, level - 1,
+                                 root->root_key.objectid,
                                  node_key->objectid, node_key->type,
                                  node_key->offset);
                        err = -ENOENT;
@@ -892,6 +899,8 @@ again:
                }
                lower = cur;
                need_check = true;
+
+               /* Add all nodes and edges in the path */
                for (; level < BTRFS_MAX_LEVEL; level++) {
                        if (!path2->nodes[level]) {
                                ASSERT(btrfs_root_bytenr(&root->root_item) ==
@@ -1281,7 +1290,7 @@ static void __del_reloc_root(struct btrfs_root *root)
        struct mapping_node *node = NULL;
        struct reloc_control *rc = fs_info->reloc_ctl;
 
-       if (rc) {
+       if (rc && root->node) {
                spin_lock(&rc->reloc_root_tree.lock);
                rb_node = tree_search(&rc->reloc_root_tree.rb_root,
                                      root->node->start);
@@ -1735,7 +1744,7 @@ int memcmp_node_keys(struct extent_buffer *eb, int slot,
  * errors, a negative error number is returned.
  */
 static noinline_for_stack
-int replace_path(struct btrfs_trans_handle *trans,
+int replace_path(struct btrfs_trans_handle *trans, struct reloc_control *rc,
                 struct btrfs_root *dest, struct btrfs_root *src,
                 struct btrfs_path *path, struct btrfs_key *next_key,
                 int lowest_level, int max_level)
@@ -1879,14 +1888,9 @@ again:
                 *    and tree block numbers, if current trans doesn't free
                 *    data reloc tree inode.
                 */
-               ret = btrfs_qgroup_trace_subtree(trans, parent,
-                               btrfs_header_generation(parent),
-                               btrfs_header_level(parent));
-               if (ret < 0)
-                       break;
-               ret = btrfs_qgroup_trace_subtree(trans, path->nodes[level],
-                               btrfs_header_generation(path->nodes[level]),
-                               btrfs_header_level(path->nodes[level]));
+               ret = btrfs_qgroup_trace_subtree_swap(trans, rc->block_group,
+                               parent, slot, path->nodes[level],
+                               path->slots[level], last_snapshot);
                if (ret < 0)
                        break;
 
@@ -2205,7 +2209,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
                    btrfs_comp_cpu_keys(&next_key, &key) >= 0) {
                        ret = 0;
                } else {
-                       ret = replace_path(trans, root, reloc_root, path,
+                       ret = replace_path(trans, rc, root, reloc_root, path,
                                           &next_key, level, max_level);
                }
                if (ret < 0) {
@@ -2911,7 +2915,6 @@ static int get_tree_block_key(struct btrfs_fs_info *fs_info,
                free_extent_buffer(eb);
                return -EIO;
        }
-       WARN_ON(btrfs_header_level(eb) != block->level);
        if (block->level == 0)
                btrfs_item_key_to_cpu(eb, &block->key, 0);
        else
@@ -2987,7 +2990,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
        struct backref_node *node;
        struct btrfs_path *path;
        struct tree_block *block;
-       struct rb_node *rb_node;
+       struct tree_block *next;
        int ret;
        int err = 0;
 
@@ -2997,29 +3000,23 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
                goto out_free_blocks;
        }
 
-       rb_node = rb_first(blocks);
-       while (rb_node) {
-               block = rb_entry(rb_node, struct tree_block, rb_node);
+       /* Kick in readahead for tree blocks with missing keys */
+       rbtree_postorder_for_each_entry_safe(block, next, blocks, rb_node) {
                if (!block->key_ready)
                        readahead_tree_block(fs_info, block->bytenr);
-               rb_node = rb_next(rb_node);
        }
 
-       rb_node = rb_first(blocks);
-       while (rb_node) {
-               block = rb_entry(rb_node, struct tree_block, rb_node);
+       /* Get first keys */
+       rbtree_postorder_for_each_entry_safe(block, next, blocks, rb_node) {
                if (!block->key_ready) {
                        err = get_tree_block_key(fs_info, block);
                        if (err)
                                goto out_free_path;
                }
-               rb_node = rb_next(rb_node);
        }
 
-       rb_node = rb_first(blocks);
-       while (rb_node) {
-               block = rb_entry(rb_node, struct tree_block, rb_node);
-
+       /* Do tree relocation */
+       rbtree_postorder_for_each_entry_safe(block, next, blocks, rb_node) {
                node = build_backref_tree(rc, &block->key,
                                          block->level, block->bytenr);
                if (IS_ERR(node)) {
@@ -3030,11 +3027,10 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
                ret = relocate_tree_block(trans, rc, node, &block->key,
                                          path);
                if (ret < 0) {
-                       if (ret != -EAGAIN || rb_node == rb_first(blocks))
+                       if (ret != -EAGAIN || &block->rb_node == rb_first(blocks))
                                err = ret;
                        goto out;
                }
-               rb_node = rb_next(rb_node);
        }
 out:
        err = finish_pending_nodes(trans, rc, path, err);
@@ -3963,6 +3959,7 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
 restart:
                if (update_backref_cache(trans, &rc->backref_cache)) {
                        btrfs_end_transaction(trans);
+                       trans = NULL;
                        continue;
                }
 
@@ -4669,7 +4666,7 @@ int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
        if (rc->merge_reloc_tree) {
                ret = btrfs_block_rsv_migrate(&pending->block_rsv,
                                              rc->block_rsv,
-                                             rc->nodes_relocated, 1);
+                                             rc->nodes_relocated, true);
                if (ret)
                        return ret;
        }