Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[cascardo/linux.git] / fs / btrfs / backref.c
index aded3ef..aad7201 100644 (file)
@@ -220,7 +220,8 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,
 
 static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
                           struct ulist *parents, struct __prelim_ref *ref,
-                          int level, u64 time_seq, const u64 *extent_item_pos)
+                          int level, u64 time_seq, const u64 *extent_item_pos,
+                          u64 total_refs)
 {
        int ret = 0;
        int slot;
@@ -249,7 +250,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
        if (path->slots[0] >= btrfs_header_nritems(path->nodes[0]))
                ret = btrfs_next_old_leaf(root, path, time_seq);
 
-       while (!ret && count < ref->count) {
+       while (!ret && count < total_refs) {
                eb = path->nodes[0];
                slot = path->slots[0];
 
@@ -306,7 +307,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
                                  struct btrfs_path *path, u64 time_seq,
                                  struct __prelim_ref *ref,
                                  struct ulist *parents,
-                                 const u64 *extent_item_pos)
+                                 const u64 *extent_item_pos, u64 total_refs)
 {
        struct btrfs_root *root;
        struct btrfs_key root_key;
@@ -361,7 +362,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
        }
 
        ret = add_all_parents(root, path, parents, ref, level, time_seq,
-                             extent_item_pos);
+                             extent_item_pos, total_refs);
 out:
        path->lowest_level = 0;
        btrfs_release_path(path);
@@ -374,7 +375,7 @@ out:
 static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
                                   struct btrfs_path *path, u64 time_seq,
                                   struct list_head *head,
-                                  const u64 *extent_item_pos)
+                                  const u64 *extent_item_pos, u64 total_refs)
 {
        int err;
        int ret = 0;
@@ -400,7 +401,8 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
                if (ref->count == 0)
                        continue;
                err = __resolve_indirect_ref(fs_info, path, time_seq, ref,
-                                            parents, extent_item_pos);
+                                            parents, extent_item_pos,
+                                            total_refs);
                /*
                 * we can only tolerate ENOENT,otherwise,we should catch error
                 * and return directly.
@@ -557,7 +559,7 @@ static void __merge_refs(struct list_head *head, int mode)
  * smaller or equal that seq to the list
  */
 static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
-                             struct list_head *prefs)
+                             struct list_head *prefs, u64 *total_refs)
 {
        struct btrfs_delayed_extent_op *extent_op = head->extent_op;
        struct rb_node *n = &head->node.rb_node;
@@ -593,6 +595,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
                default:
                        BUG_ON(1);
                }
+               *total_refs += (node->ref_mod * sgn);
                switch (node->type) {
                case BTRFS_TREE_BLOCK_REF_KEY: {
                        struct btrfs_delayed_tree_ref *ref;
@@ -653,7 +656,8 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
  */
 static int __add_inline_refs(struct btrfs_fs_info *fs_info,
                             struct btrfs_path *path, u64 bytenr,
-                            int *info_level, struct list_head *prefs)
+                            int *info_level, struct list_head *prefs,
+                            u64 *total_refs)
 {
        int ret = 0;
        int slot;
@@ -677,6 +681,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
 
        ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
        flags = btrfs_extent_flags(leaf, ei);
+       *total_refs += btrfs_extent_refs(leaf, ei);
        btrfs_item_key_to_cpu(leaf, &found_key, slot);
 
        ptr = (unsigned long)(ei + 1);
@@ -859,6 +864,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
        struct list_head prefs;
        struct __prelim_ref *ref;
        struct extent_inode_elem *eie = NULL;
+       u64 total_refs = 0;
 
        INIT_LIST_HEAD(&prefs);
        INIT_LIST_HEAD(&prefs_delayed);
@@ -873,8 +879,10 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
-       if (!trans)
+       if (!trans) {
                path->search_commit_root = 1;
+               path->skip_locking = 1;
+       }
 
        /*
         * grab both a lock on the path and a lock on the delayed ref head.
@@ -915,7 +923,7 @@ again:
                        }
                        spin_unlock(&delayed_refs->lock);
                        ret = __add_delayed_refs(head, time_seq,
-                                                &prefs_delayed);
+                                                &prefs_delayed, &total_refs);
                        mutex_unlock(&head->mutex);
                        if (ret)
                                goto out;
@@ -936,7 +944,8 @@ again:
                    (key.type == BTRFS_EXTENT_ITEM_KEY ||
                     key.type == BTRFS_METADATA_ITEM_KEY)) {
                        ret = __add_inline_refs(fs_info, path, bytenr,
-                                               &info_level, &prefs);
+                                               &info_level, &prefs,
+                                               &total_refs);
                        if (ret)
                                goto out;
                        ret = __add_keyed_refs(fs_info, path, bytenr,
@@ -956,7 +965,7 @@ again:
        __merge_refs(&prefs, 1);
 
        ret = __resolve_indirect_refs(fs_info, path, time_seq, &prefs,
-                                     extent_item_pos);
+                                     extent_item_pos, total_refs);
        if (ret)
                goto out;
 
@@ -965,7 +974,7 @@ again:
        while (!list_empty(&prefs)) {
                ref = list_first_entry(&prefs, struct __prelim_ref, list);
                WARN_ON(ref->count < 0);
-               if (ref->count && ref->root_id && ref->parent == 0) {
+               if (roots && ref->count && ref->root_id && ref->parent == 0) {
                        /* no parent == root of tree */
                        ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS);
                        if (ret < 0)
@@ -1061,22 +1070,14 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
                                u64 time_seq, struct ulist **leafs,
                                const u64 *extent_item_pos)
 {
-       struct ulist *tmp;
        int ret;
 
-       tmp = ulist_alloc(GFP_NOFS);
-       if (!tmp)
-               return -ENOMEM;
        *leafs = ulist_alloc(GFP_NOFS);
-       if (!*leafs) {
-               ulist_free(tmp);
+       if (!*leafs)
                return -ENOMEM;
-       }
 
        ret = find_parent_nodes(trans, fs_info, bytenr,
-                               time_seq, *leafs, tmp, extent_item_pos);
-       ulist_free(tmp);
-
+                               time_seq, *leafs, NULL, extent_item_pos);
        if (ret < 0 && ret != -ENOENT) {
                free_leaf_list(*leafs);
                return ret;
@@ -1333,38 +1334,13 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
        if (ret < 0)
                return ret;
 
-       while (1) {
-               u32 nritems;
-               if (path->slots[0] == 0) {
-                       btrfs_set_path_blocking(path);
-                       ret = btrfs_prev_leaf(fs_info->extent_root, path);
-                       if (ret != 0) {
-                               if (ret > 0) {
-                                       pr_debug("logical %llu is not within "
-                                                "any extent\n", logical);
-                                       ret = -ENOENT;
-                               }
-                               return ret;
-                       }
-               } else {
-                       path->slots[0]--;
-               }
-               nritems = btrfs_header_nritems(path->nodes[0]);
-               if (nritems == 0) {
-                       pr_debug("logical %llu is not within any extent\n",
-                                logical);
-                       return -ENOENT;
-               }
-               if (path->slots[0] == nritems)
-                       path->slots[0]--;
-
-               btrfs_item_key_to_cpu(path->nodes[0], found_key,
-                                     path->slots[0]);
-               if (found_key->type == BTRFS_EXTENT_ITEM_KEY ||
-                   found_key->type == BTRFS_METADATA_ITEM_KEY)
-                       break;
+       ret = btrfs_previous_extent_item(fs_info->extent_root, path, 0);
+       if (ret) {
+               if (ret > 0)
+                       ret = -ENOENT;
+               return ret;
        }
-
+       btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]);
        if (found_key->type == BTRFS_METADATA_ITEM_KEY)
                size = fs_info->extent_root->leafsize;
        else if (found_key->type == BTRFS_EXTENT_ITEM_KEY)