btrfs-progs: read_tree_block() and read_node_slot() cleanup.
[platform/upstream/btrfs-progs.git] / ctree.c
diff --git a/ctree.c b/ctree.c
index eb69b57..130c61f 100644 (file)
--- a/ctree.c
+++ b/ctree.c
@@ -48,11 +48,13 @@ struct btrfs_path *btrfs_alloc_path(void)
 
 void btrfs_free_path(struct btrfs_path *p)
 {
-       btrfs_release_path(NULL, p);
+       if (!p)
+               return;
+       btrfs_release_path(p);
        kfree(p);
 }
 
-void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
+void btrfs_release_path(struct btrfs_path *p)
 {
        int i;
        for (i = 0; i < BTRFS_MAX_LEVEL; i++) {
@@ -118,8 +120,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
                btrfs_set_header_owner(cow, new_root_objectid);
 
        write_extent_buffer(cow, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(cow),
-                           BTRFS_FSID_SIZE);
+                           btrfs_header_fsid(), BTRFS_FSID_SIZE);
 
        WARN_ON(btrfs_header_generation(buf) > trans->transid);
        ret = btrfs_inc_ref(trans, new_root, cow, 0);
@@ -136,8 +137,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
 /*
  * check if the tree block can be shared by multiple trees
  */
-int btrfs_block_can_be_shared(struct btrfs_root *root,
-                             struct extent_buffer *buf)
+static int btrfs_block_can_be_shared(struct btrfs_root *root,
+                                    struct extent_buffer *buf)
 {
        /*
         * Tree blocks not in refernece counted trees and tree roots
@@ -292,10 +293,10 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                btrfs_set_header_owner(cow, root->root_key.objectid);
 
        write_extent_buffer(cow, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(cow),
-                           BTRFS_FSID_SIZE);
+                           btrfs_header_fsid(), BTRFS_FSID_SIZE);
 
-       WARN_ON(btrfs_header_generation(buf) > trans->transid);
+       WARN_ON(!(buf->flags & EXTENT_BAD_TRANSID) &&
+               btrfs_header_generation(buf) > trans->transid);
 
        update_ref_for_cow(trans, root, buf, cow);
 
@@ -319,6 +320,10 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                btrfs_free_extent(trans, root, buf->start, buf->len,
                                  0, root->root_key.objectid, level, 1);
        }
+       if (!list_empty(&buf->recow)) {
+               list_del_init(&buf->recow);
+               free_extent_buffer(buf);
+       }
        free_extent_buffer(buf);
        btrfs_mark_buffer_dirty(cow);
        *cow_ret = cow;
@@ -368,31 +373,35 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-/*
- * compare two keys in a memcmp fashion
- */
-int btrfs_comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2)
+int btrfs_comp_cpu_keys(struct btrfs_key *k1, struct btrfs_key *k2)
 {
-       struct btrfs_key k1;
-
-       btrfs_disk_key_to_cpu(&k1, disk);
-
-       if (k1.objectid > k2->objectid)
+       if (k1->objectid > k2->objectid)
                return 1;
-       if (k1.objectid < k2->objectid)
+       if (k1->objectid < k2->objectid)
                return -1;
-       if (k1.type > k2->type)
+       if (k1->type > k2->type)
                return 1;
-       if (k1.type < k2->type)
+       if (k1->type < k2->type)
                return -1;
-       if (k1.offset > k2->offset)
+       if (k1->offset > k2->offset)
                return 1;
-       if (k1.offset < k2->offset)
+       if (k1->offset < k2->offset)
                return -1;
        return 0;
 }
 
 /*
+ * compare two keys in a memcmp fashion
+ */
+static int btrfs_comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2)
+{
+       struct btrfs_key k1;
+
+       btrfs_disk_key_to_cpu(&k1, disk);
+       return btrfs_comp_cpu_keys(&k1, k2);
+}
+
+/*
  * The leaf data grows from end-to-front in the node.
  * this returns the address of the start of the last item,
  * which is the stop of the leaf data stack
@@ -406,30 +415,33 @@ static inline unsigned int leaf_data_end(struct btrfs_root *root,
        return btrfs_item_offset_nr(leaf, nr - 1);
 }
 
-int btrfs_check_node(struct btrfs_root *root,
-                     struct btrfs_disk_key *parent_key,
-                     struct extent_buffer *buf)
+enum btrfs_tree_block_status
+btrfs_check_node(struct btrfs_root *root, struct btrfs_disk_key *parent_key,
+                struct extent_buffer *buf)
 {
        int i;
        struct btrfs_key cpukey;
        struct btrfs_disk_key key;
        u32 nritems = btrfs_header_nritems(buf);
+       enum btrfs_tree_block_status ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS;
 
        if (nritems == 0 || nritems > BTRFS_NODEPTRS_PER_BLOCK(root))
                goto fail;
 
+       ret = BTRFS_TREE_BLOCK_INVALID_PARENT_KEY;
        if (parent_key && parent_key->type) {
                btrfs_node_key(buf, &key, 0);
                if (memcmp(parent_key, &key, sizeof(key)))
                        goto fail;
        }
+       ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER;
        for (i = 0; nritems > 1 && i < nritems - 2; i++) {
                btrfs_node_key(buf, &key, i);
                btrfs_node_key_to_cpu(buf, &cpukey, i + 1);
                if (btrfs_comp_keys(&key, &cpukey) >= 0)
                        goto fail;
        }
-       return 0;
+       return BTRFS_TREE_BLOCK_CLEAN;
 fail:
        if (btrfs_header_owner(buf) == BTRFS_EXTENT_TREE_OBJECTID) {
                if (parent_key)
@@ -440,17 +452,18 @@ fail:
                                                buf->start, buf->len,
                                                btrfs_header_level(buf));
        }
-       return -EIO;
+       return ret;
 }
 
-int btrfs_check_leaf(struct btrfs_root *root,
-                     struct btrfs_disk_key *parent_key,
-                     struct extent_buffer *buf)
+enum btrfs_tree_block_status
+btrfs_check_leaf(struct btrfs_root *root, struct btrfs_disk_key *parent_key,
+                struct extent_buffer *buf)
 {
        int i;
        struct btrfs_key cpukey;
        struct btrfs_disk_key key;
        u32 nritems = btrfs_header_nritems(buf);
+       enum btrfs_tree_block_status ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS;
 
        if (nritems * sizeof(struct btrfs_item) > buf->len)  {
                fprintf(stderr, "invalid number of items %llu\n",
@@ -459,11 +472,13 @@ int btrfs_check_leaf(struct btrfs_root *root,
        }
 
        if (btrfs_header_level(buf) != 0) {
+               ret = BTRFS_TREE_BLOCK_INVALID_LEVEL;
                fprintf(stderr, "leaf is not a leaf %llu\n",
                       (unsigned long long)btrfs_header_bytenr(buf));
                goto fail;
        }
        if (btrfs_leaf_free_space(root, buf) < 0) {
+               ret = BTRFS_TREE_BLOCK_INVALID_FREE_SPACE;
                fprintf(stderr, "leaf free space incorrect %llu %d\n",
                        (unsigned long long)btrfs_header_bytenr(buf),
                        btrfs_leaf_free_space(root, buf));
@@ -471,24 +486,27 @@ int btrfs_check_leaf(struct btrfs_root *root,
        }
 
        if (nritems == 0)
-               return 0;
+               return BTRFS_TREE_BLOCK_CLEAN;
 
        btrfs_item_key(buf, &key, 0);
        if (parent_key && parent_key->type &&
            memcmp(parent_key, &key, sizeof(key))) {
+               ret = BTRFS_TREE_BLOCK_INVALID_PARENT_KEY;
                fprintf(stderr, "leaf parent key incorrect %llu\n",
                       (unsigned long long)btrfs_header_bytenr(buf));
                goto fail;
        }
-       for (i = 0; nritems > 1 && i < nritems - 2; i++) {
+       for (i = 0; nritems > 1 && i < nritems - 1; i++) {
                btrfs_item_key(buf, &key, i);
                btrfs_item_key_to_cpu(buf, &cpukey, i + 1);
                if (btrfs_comp_keys(&key, &cpukey) >= 0) {
+                       ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER;
                        fprintf(stderr, "bad key ordering %d %d\n", i, i+1);
                        goto fail;
                }
                if (btrfs_item_offset_nr(buf, i) !=
                        btrfs_item_end_nr(buf, i + 1)) {
+                       ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
                        fprintf(stderr, "incorrect offsets %u %u\n",
                                btrfs_item_offset_nr(buf, i),
                                btrfs_item_end_nr(buf, i + 1));
@@ -496,13 +514,14 @@ int btrfs_check_leaf(struct btrfs_root *root,
                }
                if (i == 0 && btrfs_item_end_nr(buf, i) !=
                    BTRFS_LEAF_DATA_SIZE(root)) {
+                       ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
                        fprintf(stderr, "bad item end %u wanted %u\n",
                                btrfs_item_end_nr(buf, i),
                                (unsigned)BTRFS_LEAF_DATA_SIZE(root));
                        goto fail;
                }
        }
-       return 0;
+       return BTRFS_TREE_BLOCK_CLEAN;
 fail:
        if (btrfs_header_owner(buf) == BTRFS_EXTENT_TREE_OBJECTID) {
                if (parent_key)
@@ -513,7 +532,7 @@ fail:
                btrfs_add_corrupt_extent_record(root->fs_info, &cpukey,
                                                buf->start, buf->len, 0);
        }
-       return -EIO;
+       return ret;
 }
 
 static int noinline check_block(struct btrfs_root *root,
@@ -522,15 +541,22 @@ static int noinline check_block(struct btrfs_root *root,
        struct btrfs_disk_key key;
        struct btrfs_disk_key *key_ptr = NULL;
        struct extent_buffer *parent;
+       enum btrfs_tree_block_status ret;
 
+       if (path->skip_check_block)
+               return 0;
        if (path->nodes[level + 1]) {
                parent = path->nodes[level + 1];
                btrfs_node_key(parent, &key, path->slots[level + 1]);
                key_ptr = &key;
        }
        if (level == 0)
-               return btrfs_check_leaf(root, key_ptr, path->nodes[0]);
-       return btrfs_check_node(root, key_ptr, path->nodes[level]);
+               ret =  btrfs_check_leaf(root, key_ptr, path->nodes[0]);
+       else
+               ret = btrfs_check_node(root, key_ptr, path->nodes[level]);
+       if (ret == BTRFS_TREE_BLOCK_CLEAN)
+               return 0;
+       return -EIO;
 }
 
 /*
@@ -651,7 +677,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
 
                /* promote the child to a root */
                child = read_node_slot(root, mid, 0);
-               BUG_ON(!child);
+               BUG_ON(!extent_buffer_uptodate(child));
                ret = btrfs_cow_block(trans, root, child, mid, 0, &child);
                BUG_ON(ret);
 
@@ -675,7 +701,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
                return 0;
 
        left = read_node_slot(root, parent, pslot - 1);
-       if (left) {
+       if (extent_buffer_uptodate(left)) {
                wret = btrfs_cow_block(trans, root, left,
                                       parent, pslot - 1, &left);
                if (wret) {
@@ -684,7 +710,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
                }
        }
        right = read_node_slot(root, parent, pslot + 1);
-       if (right) {
+       if (extent_buffer_uptodate(right)) {
                wret = btrfs_cow_block(trans, root, right,
                                       parent, pslot + 1, &right);
                if (wret) {
@@ -838,7 +864,7 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
        left = read_node_slot(root, parent, pslot - 1);
 
        /* first, try to make some room in the middle buffer */
-       if (left) {
+       if (extent_buffer_uptodate(left)) {
                u32 left_nr;
                left_nr = btrfs_header_nritems(left);
                if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) {
@@ -881,7 +907,7 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
        /*
         * then try to empty the right most buffer into the middle
         */
-       if (right) {
+       if (extent_buffer_uptodate(right)) {
                u32 right_nr;
                right_nr = btrfs_header_nritems(right);
                if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) {
@@ -997,6 +1023,49 @@ void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
        }
 }
 
+int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path,
+               u64 iobjectid, u64 ioff, u8 key_type,
+               struct btrfs_key *found_key)
+{
+       int ret;
+       struct btrfs_key key;
+       struct extent_buffer *eb;
+       struct btrfs_path *path;
+
+       key.type = key_type;
+       key.objectid = iobjectid;
+       key.offset = ioff;
+
+       if (found_path == NULL) {
+               path = btrfs_alloc_path();
+               if (!path)
+                       return -ENOMEM;
+       } else
+               path = found_path;
+
+       ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0);
+       if ((ret < 0) || (found_key == NULL)) {
+               if (path != found_path)
+                       btrfs_free_path(path);
+               return ret;
+       }
+
+       eb = path->nodes[0];
+       if (ret && path->slots[0] >= btrfs_header_nritems(eb)) {
+               ret = btrfs_next_leaf(fs_root, path);
+               if (ret)
+                       return ret;
+               eb = path->nodes[0];
+       }
+
+       btrfs_item_key_to_cpu(eb, found_key, path->slots[0]);
+       if (found_key->type != key.type ||
+                       found_key->objectid != key.objectid)
+               return 1;
+
+       return 0;
+}
+
 /*
  * look for key in the tree.  path is filled in with nodes along the way
  * if key is found, we return zero and you can find the item in the leaf
@@ -1072,7 +1141,7 @@ again:
                                        return sret;
                                b = p->nodes[level];
                                if (!b) {
-                                       btrfs_release_path(NULL, p);
+                                       btrfs_release_path(p);
                                        goto again;
                                }
                                slot = p->slots[level];
@@ -1111,16 +1180,11 @@ again:
  * This is used after shifting pointers to the left, so it stops
  * fixing up pointers when a given leaf/node is not in slot 0 of the
  * higher levels
- *
- * If this fails to write a tree block, it returns -1, but continues
- * fixing up the blocks in ram so the tree is consistent.
  */
-static int fixup_low_keys(struct btrfs_trans_handle *trans,
-                         struct btrfs_root *root, struct btrfs_path *path,
+void btrfs_fixup_low_keys(struct btrfs_root *root, struct btrfs_path *path,
                          struct btrfs_disk_key *key, int level)
 {
        int i;
-       int ret = 0;
        struct extent_buffer *t;
 
        for (i = level; i < BTRFS_MAX_LEVEL; i++) {
@@ -1133,7 +1197,6 @@ static int fixup_low_keys(struct btrfs_trans_handle *trans,
                if (tslot != 0)
                        break;
        }
-       return ret;
 }
 
 /*
@@ -1142,8 +1205,7 @@ static int fixup_low_keys(struct btrfs_trans_handle *trans,
  * This function isn't completely safe. It's the caller's responsibility
  * that the new key won't break the order
  */
-int btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root, struct btrfs_path *path,
+int btrfs_set_item_key_safe(struct btrfs_root *root, struct btrfs_path *path,
                            struct btrfs_key *new_key)
 {
        struct btrfs_disk_key disk_key;
@@ -1167,11 +1229,33 @@ int btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
        btrfs_set_item_key(eb, &disk_key, slot);
        btrfs_mark_buffer_dirty(eb);
        if (slot == 0)
-               fixup_low_keys(trans, root, path, &disk_key, 1);
+               btrfs_fixup_low_keys(root, path, &disk_key, 1);
        return 0;
 }
 
 /*
+ * update an item key without the safety checks.  This is meant to be called by
+ * fsck only.
+ */
+void btrfs_set_item_key_unsafe(struct btrfs_root *root,
+                              struct btrfs_path *path,
+                              struct btrfs_key *new_key)
+{
+       struct btrfs_disk_key disk_key;
+       struct extent_buffer *eb;
+       int slot;
+
+       eb = path->nodes[0];
+       slot = path->slots[0];
+
+       btrfs_cpu_key_to_disk(&disk_key, new_key);
+       btrfs_set_item_key(eb, &disk_key, slot);
+       btrfs_mark_buffer_dirty(eb);
+       if (slot == 0)
+               btrfs_fixup_low_keys(root, path, &disk_key, 1);
+}
+
+/*
  * try to push data from one node into the next node left in the
  * tree.
  *
@@ -1338,11 +1422,10 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
        btrfs_set_header_owner(c, root->root_key.objectid);
 
        write_extent_buffer(c, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(c),
-                           BTRFS_FSID_SIZE);
+                           btrfs_header_fsid(), BTRFS_FSID_SIZE);
 
        write_extent_buffer(c, root->fs_info->chunk_tree_uuid,
-                           (unsigned long)btrfs_header_chunk_tree_uuid(c),
+                           btrfs_header_chunk_tree_uuid(c),
                            BTRFS_UUID_SIZE);
 
        btrfs_set_node_key(c, &lower_key, 0);
@@ -1459,10 +1542,9 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
        btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV);
        btrfs_set_header_owner(split, root->root_key.objectid);
        write_extent_buffer(split, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(split),
-                           BTRFS_FSID_SIZE);
+                           btrfs_header_fsid(), BTRFS_FSID_SIZE);
        write_extent_buffer(split, root->fs_info->chunk_tree_uuid,
-                           (unsigned long)btrfs_header_chunk_tree_uuid(split),
+                           btrfs_header_chunk_tree_uuid(split),
                            BTRFS_UUID_SIZE);
 
 
@@ -1569,6 +1651,11 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
                return 1;
 
        right = read_node_slot(root, upper, slot + 1);
+       if (!extent_buffer_uptodate(right)) {
+               if (IS_ERR(right))
+                       return PTR_ERR(right);
+               return -EIO;
+       }
        free_space = btrfs_leaf_free_space(root, right);
        if (free_space < data_size) {
                free_extent_buffer(right);
@@ -1601,7 +1688,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
 
        i = left_nritems - 1;
        while (i >= nr) {
-               item = btrfs_item_nr(left, i);
+               item = btrfs_item_nr(i);
 
                if (path->slots[0] == i)
                        push_space += data_size + sizeof(*item);
@@ -1657,7 +1744,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
        btrfs_set_header_nritems(right, right_nritems);
        push_space = BTRFS_LEAF_DATA_SIZE(root);
        for (i = 0; i < right_nritems; i++) {
-               item = btrfs_item_nr(right, i);
+               item = btrfs_item_nr(i);
                push_space -= btrfs_item_size(right, item);
                btrfs_set_item_offset(right, item, push_space);
        }
@@ -1705,7 +1792,6 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
        u32 right_nritems;
        u32 nr;
        int ret = 0;
-       int wret;
        u32 this_item_size;
        u32 old_left_item_size;
 
@@ -1748,7 +1834,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
                nr = right_nritems - 1;
 
        for (i = 0; i < nr; i++) {
-               item = btrfs_item_nr(right, i);
+               item = btrfs_item_nr(i);
 
                if (path->slots[0] == i)
                        push_space += data_size + sizeof(*item);
@@ -1789,7 +1875,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
        for (i = old_left_nritems; i < old_left_nritems + push_items; i++) {
                u32 ioff;
 
-               item = btrfs_item_nr(left, i);
+               item = btrfs_item_nr(i);
                ioff = btrfs_item_offset(left, item);
                btrfs_set_item_offset(left, item,
                      ioff - (BTRFS_LEAF_DATA_SIZE(root) - old_left_item_size));
@@ -1819,7 +1905,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
        btrfs_set_header_nritems(right, right_nritems);
        push_space = BTRFS_LEAF_DATA_SIZE(root);
        for (i = 0; i < right_nritems; i++) {
-               item = btrfs_item_nr(right, i);
+               item = btrfs_item_nr(i);
                push_space = push_space - btrfs_item_size(right, item);
                btrfs_set_item_offset(right, item, push_space);
        }
@@ -1829,9 +1915,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
                btrfs_mark_buffer_dirty(right);
 
        btrfs_item_key(right, &disk_key, 0);
-       wret = fixup_low_keys(trans, root, path, &disk_key, 1);
-       if (wret)
-               ret = wret;
+       btrfs_fixup_low_keys(root, path, &disk_key, 1);
 
        /* then fixup the leaf pointer in the path */
        if (path->slots[0] < push_items) {
@@ -1884,7 +1968,7 @@ static noinline int copy_for_split(struct btrfs_trans_handle *trans,
                      btrfs_item_end_nr(l, mid);
 
        for (i = 0; i < nritems; i++) {
-               struct btrfs_item *item = btrfs_item_nr(right, i);
+               struct btrfs_item *item = btrfs_item_nr(i);
                u32 ioff = btrfs_item_offset(right, item);
                btrfs_set_item_offset(right, item, ioff + rt_data_off);
        }
@@ -1938,6 +2022,12 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
        int split;
        int num_doubles = 0;
 
+       l = path->nodes[0];
+       slot = path->slots[0];
+       if (extend && data_size + btrfs_item_size_nr(l, slot) +
+           sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root))
+               return -EOVERFLOW;
+
        /* first try to make some room by pushing left and right */
        if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
                wret = push_leaf_right(trans, root, path, data_size, 0);
@@ -2020,11 +2110,10 @@ again:
        btrfs_set_header_owner(right, root->root_key.objectid);
        btrfs_set_header_level(right, 0);
        write_extent_buffer(right, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(right),
-                           BTRFS_FSID_SIZE);
+                           btrfs_header_fsid(), BTRFS_FSID_SIZE);
 
        write_extent_buffer(right, root->fs_info->chunk_tree_uuid,
-                           (unsigned long)btrfs_header_chunk_tree_uuid(right),
+                           btrfs_header_chunk_tree_uuid(right),
                            BTRFS_UUID_SIZE);
 
        if (split == 0) {
@@ -2052,10 +2141,8 @@ again:
                        path->nodes[0] = right;
                        path->slots[0] = 0;
                        if (path->slots[1] == 0) {
-                               wret = fixup_low_keys(trans, root,
-                                               path, &disk_key, 1);
-                               if (wret)
-                                       ret = wret;
+                               btrfs_fixup_low_keys(root, path,
+                                                    &disk_key, 1);
                        }
                }
                btrfs_mark_buffer_dirty(right);
@@ -2113,7 +2200,7 @@ int btrfs_split_item(struct btrfs_trans_handle *trans,
                goto split;
 
        item_size = btrfs_item_size_nr(leaf, path->slots[0]);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        path->search_for_split = 1;
 
@@ -2133,7 +2220,7 @@ int btrfs_split_item(struct btrfs_trans_handle *trans,
        leaf = path->nodes[0];
 
 split:
-       item = btrfs_item_nr(leaf, path->slots[0]);
+       item = btrfs_item_nr(path->slots[0]);
        orig_offset = btrfs_item_offset(leaf, item);
        item_size = btrfs_item_size(leaf, item);
 
@@ -2157,7 +2244,7 @@ split:
        btrfs_cpu_key_to_disk(&disk_key, new_key);
        btrfs_set_item_key(leaf, &disk_key, slot);
 
-       new_item = btrfs_item_nr(leaf, slot);
+       new_item = btrfs_item_nr(slot);
 
        btrfs_set_item_offset(leaf, new_item, orig_offset);
        btrfs_set_item_size(leaf, new_item, item_size - split_offset);
@@ -2227,7 +2314,7 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,
        /* first correct the data pointers */
        for (i = slot; i < nritems; i++) {
                u32 ioff;
-               item = btrfs_item_nr(leaf, i);
+               item = btrfs_item_nr(i);
                ioff = btrfs_item_offset(leaf, item);
                btrfs_set_item_offset(leaf, item, ioff + size_diff);
        }
@@ -2270,10 +2357,10 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,
                btrfs_set_disk_key_offset(&disk_key, offset + size_diff);
                btrfs_set_item_key(leaf, &disk_key, slot);
                if (slot == 0)
-                       fixup_low_keys(trans, root, path, &disk_key, 1);
+                       btrfs_fixup_low_keys(root, path, &disk_key, 1);
        }
 
-       item = btrfs_item_nr(leaf, slot);
+       item = btrfs_item_nr(slot);
        btrfs_set_item_size(leaf, item, new_size);
        btrfs_mark_buffer_dirty(leaf);
 
@@ -2324,7 +2411,7 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans,
        /* first correct the data pointers */
        for (i = slot; i < nritems; i++) {
                u32 ioff;
-               item = btrfs_item_nr(leaf, i);
+               item = btrfs_item_nr(i);
                ioff = btrfs_item_offset(leaf, item);
                btrfs_set_item_offset(leaf, item, ioff - data_size);
        }
@@ -2336,7 +2423,7 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans,
 
        data_end = old_data;
        old_size = btrfs_item_size_nr(leaf, slot);
-       item = btrfs_item_nr(leaf, slot);
+       item = btrfs_item_nr(slot);
        btrfs_set_item_size(leaf, item, old_size + data_size);
        btrfs_mark_buffer_dirty(leaf);
 
@@ -2401,7 +2488,6 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
        BUG_ON(slot < 0);
 
        if (slot != nritems) {
-               int i;
                unsigned int old_data = btrfs_item_end_nr(leaf, slot);
 
                if (old_data < data_end) {
@@ -2417,7 +2503,7 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
                for (i = slot; i < nritems; i++) {
                        u32 ioff;
 
-                       item = btrfs_item_nr(leaf, i);
+                       item = btrfs_item_nr(i);
                        ioff = btrfs_item_offset(leaf, item);
                        btrfs_set_item_offset(leaf, item, ioff - total_data);
                }
@@ -2438,7 +2524,7 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
        for (i = 0; i < nr; i++) {
                btrfs_cpu_key_to_disk(&disk_key, cpu_key + i);
                btrfs_set_item_key(leaf, &disk_key, slot + i);
-               item = btrfs_item_nr(leaf, slot + i);
+               item = btrfs_item_nr(slot + i);
                btrfs_set_item_offset(leaf, item, data_end - data_size[i]);
                data_end -= data_size[i];
                btrfs_set_item_size(leaf, item, data_size[i]);
@@ -2449,7 +2535,7 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
        ret = 0;
        if (slot == 0) {
                btrfs_cpu_key_to_disk(&disk_key, cpu_key);
-               ret = fixup_low_keys(trans, root, path, &disk_key, 1);
+               btrfs_fixup_low_keys(root, path, &disk_key, 1);
        }
 
        if (btrfs_leaf_free_space(root, leaf) < 0) {
@@ -2500,7 +2586,6 @@ int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        struct extent_buffer *parent = path->nodes[level];
        u32 nritems;
        int ret = 0;
-       int wret;
 
        nritems = btrfs_header_nritems(parent);
        if (slot != nritems -1) {
@@ -2520,9 +2605,7 @@ int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                struct btrfs_disk_key disk_key;
 
                btrfs_node_key(parent, &disk_key, 0);
-               wret = fixup_low_keys(trans, root, path, &disk_key, level + 1);
-               if (wret)
-                       ret = wret;
+               btrfs_fixup_low_keys(root, path, &disk_key, level + 1);
        }
        btrfs_mark_buffer_dirty(parent);
        return ret;
@@ -2580,7 +2663,6 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        nritems = btrfs_header_nritems(leaf);
 
        if (slot + nr != nritems) {
-               int i;
                int data_end = leaf_data_end(root, leaf);
 
                memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
@@ -2591,7 +2673,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                for (i = slot + nr; i < nritems; i++) {
                        u32 ioff;
 
-                       item = btrfs_item_nr(leaf, i);
+                       item = btrfs_item_nr(i);
                        ioff = btrfs_item_offset(leaf, item);
                        btrfs_set_item_offset(leaf, item, ioff + dsize);
                }
@@ -2623,10 +2705,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                        struct btrfs_disk_key disk_key;
 
                        btrfs_item_key(leaf, &disk_key, 0);
-                       wret = fixup_low_keys(trans, root, path,
-                                             &disk_key, 1);
-                       if (wret)
-                               ret = wret;
+                       btrfs_fixup_low_keys(root, path, &disk_key, 1);
                }
 
                /* delete the leaf if it is mostly empty */
@@ -2696,6 +2775,11 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
                slot--;
 
                next = read_node_slot(root, c, slot);
+               if (!extent_buffer_uptodate(next)) {
+                       if (IS_ERR(next))
+                               return PTR_ERR(next);
+                       return -EIO;
+               }
                break;
        }
        path->slots[level] = slot;
@@ -2711,6 +2795,11 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
                if (!level)
                        break;
                next = read_node_slot(root, next, slot);
+               if (!extent_buffer_uptodate(next)) {
+                       if (IS_ERR(next))
+                               return PTR_ERR(next);
+                       return -EIO;
+               }
        }
        return 0;
 }
@@ -2744,7 +2833,7 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
                        reada_for_search(root, path, level, slot, 0);
 
                next = read_node_slot(root, c, slot);
-               if (!next)
+               if (!extent_buffer_uptodate(next))
                        return -EIO;
                break;
        }
@@ -2760,7 +2849,7 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
                if (path->reada)
                        reada_for_search(root, path, level, 0, 0);
                next = read_node_slot(root, next, 0);
-               if (!next)
+               if (!extent_buffer_uptodate(next))
                        return -EIO;
        }
        return 0;
@@ -2790,3 +2879,44 @@ int btrfs_previous_item(struct btrfs_root *root,
        return 1;
 }
 
+/*
+ * search in extent tree to find a previous Metadata/Data extent item with
+ * min objecitd.
+ *
+ * returns 0 if something is found, 1 if nothing was found and < 0 on error
+ */
+int btrfs_previous_extent_item(struct btrfs_root *root,
+                       struct btrfs_path *path, u64 min_objectid)
+{
+       struct btrfs_key found_key;
+       struct extent_buffer *leaf;
+       u32 nritems;
+       int ret;
+
+       while (1) {
+               if (path->slots[0] == 0) {
+                       ret = btrfs_prev_leaf(root, path);
+                       if (ret != 0)
+                               return ret;
+               } else {
+                       path->slots[0]--;
+               }
+               leaf = path->nodes[0];
+               nritems = btrfs_header_nritems(leaf);
+               if (nritems == 0)
+                       return 1;
+               if (path->slots[0] == nritems)
+                       path->slots[0]--;
+
+               btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
+               if (found_key.objectid < min_objectid)
+                       break;
+               if (found_key.type == BTRFS_EXTENT_ITEM_KEY ||
+                   found_key.type == BTRFS_METADATA_ITEM_KEY)
+                       return 0;
+               if (found_key.objectid == min_objectid &&
+                   found_key.type < BTRFS_EXTENT_ITEM_KEY)
+                       break;
+       }
+       return 1;
+}