Update btrfs-progs to better match the kernel
authorYan <yanzheng@21cn.com>
Wed, 5 Dec 2007 15:41:38 +0000 (10:41 -0500)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Wed, 5 Dec 2007 15:41:38 +0000 (10:41 -0500)
ctree.c
ctree.h
dir-item.c
disk-io.c
extent-tree.c
file-item.c
kerncompat.h
transaction.h

diff --git a/ctree.c b/ctree.c
index 1da711a..8826183 100644 (file)
--- a/ctree.c
+++ b/ctree.c
 #include <stdio.h>
 #include <stdlib.h>
 #include "kerncompat.h"
-#include "radix-tree.h"
 #include "ctree.h"
 #include "disk-io.h"
+#include "transaction.h"
 #include "print-tree.h"
-
 static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_path *path, int level);
 static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
-                     *root, struct btrfs_path *path, int data_size);
+                     *root, struct btrfs_key *ins_key,
+                     struct btrfs_path *path, int data_size, int extend);
 static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root
                          *root, struct btrfs_buffer *dst, struct btrfs_buffer
                          *src);
@@ -52,8 +52,7 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
        }
        memset(p, 0, sizeof(*p));
 }
-
-static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
+int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
                           *root, struct btrfs_buffer *buf, struct btrfs_buffer
                           *parent, int parent_slot, struct btrfs_buffer
                           **cow_ret)
@@ -67,6 +66,7 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
        cow = btrfs_alloc_free_block(trans, root, buf->size);
        memcpy(&cow->node, &buf->node, buf->size);
        btrfs_set_header_bytenr(&cow->node.header, cow->bytenr);
+       btrfs_set_header_generation(&cow->node.header, trans->transid);
        btrfs_set_header_owner(&cow->node.header, root->root_key.objectid);
        *cow_ret = cow;
        btrfs_inc_ref(trans, root, buf);
@@ -476,6 +476,128 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
                btrfs_block_release(root, left_buf);
        return ret;
 }
+static int push_nodes_for_insert(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               struct btrfs_path *path, int level)
+{
+       struct btrfs_node *right;
+       struct btrfs_node *mid;
+       struct btrfs_node *left;
+       struct btrfs_node *parent;
+       struct btrfs_buffer *right_buf;
+       struct btrfs_buffer *mid_buf;
+       struct btrfs_buffer *left_buf;
+       struct btrfs_buffer *parent_buf = NULL;
+       int ret = 0;
+       int wret;
+       int pslot;
+       int orig_slot = path->slots[level];
+       u64 orig_ptr;
+
+       if (level == 0)
+               return 1;
+
+       mid_buf = path->nodes[level];
+       mid = &mid_buf->node;
+       orig_ptr = btrfs_node_blockptr(mid, orig_slot);
+
+       if (level < BTRFS_MAX_LEVEL - 1)
+               parent_buf = path->nodes[level + 1];
+       pslot = path->slots[level + 1];
+
+       if (!parent_buf)
+               return 1;
+       parent = &parent_buf->node;
+
+       left_buf = read_node_slot(root, parent_buf, pslot - 1);
+       left = &left_buf->node;
+
+       /* first, try to make some room in the middle buffer */
+       if (left_buf) {
+               u32 left_nr;
+               left_nr = btrfs_header_nritems(&left->header);
+               if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) {
+                       wret = 1;
+               } else {
+                       ret = btrfs_cow_block(trans, root, left_buf,
+                                             parent_buf, pslot - 1,
+                                             &left_buf);
+                       left = &left_buf->node;
+                       if (ret)
+                               wret = 1;
+                       else {
+                               wret = push_node_left(trans, root,
+                                                     left_buf, mid_buf);
+                       }
+               }
+               if (wret < 0)
+                       ret = wret;
+               if (wret == 0) {
+                       orig_slot += left_nr;
+                       memcpy(&parent->ptrs[pslot].key, &mid->ptrs[0].key,
+                               sizeof(struct btrfs_disk_key));
+                       BUG_ON(list_empty(&parent_buf->dirty));
+                       if (btrfs_header_nritems(&left->header) > orig_slot) {
+                               path->nodes[level] = left_buf;
+                               path->slots[level + 1] -= 1;
+                               path->slots[level] = orig_slot;
+                               btrfs_block_release(root, mid_buf);
+                       } else {
+                               orig_slot -=
+                                       btrfs_header_nritems(&left->header);
+                               path->slots[level] = orig_slot;
+                               btrfs_block_release(root, left_buf);
+                       }
+                       return 0;
+               }
+               btrfs_block_release(root, left_buf);
+       }
+
+       right_buf = read_node_slot(root, parent_buf, pslot + 1);
+       right = &right_buf->node;
+
+       /*
+        * then try to empty the right most buffer into the middle
+        */
+       if (right_buf) {
+               u32 right_nr;
+               right_nr = btrfs_header_nritems(&right->header);
+               if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) {
+                       wret = 1;
+               } else {
+                       ret = btrfs_cow_block(trans, root, right_buf,
+                                             parent_buf, pslot + 1,
+                                             &right_buf);
+                       right = &right_buf->node;
+                       if (ret)
+                               wret = 1;
+                       else {
+                               wret = balance_node_right(trans, root,
+                                               right_buf, mid_buf);
+                       }
+               }
+               if (wret < 0)
+                       ret = wret;
+               if (wret == 0) {
+                       memcpy(&parent->ptrs[pslot + 1].key,
+                              &right->ptrs[0].key,
+                              sizeof(struct btrfs_disk_key));
+                       BUG_ON(list_empty(&parent_buf->dirty));
+                       if (btrfs_header_nritems(&mid->header) <= orig_slot) {
+                               path->nodes[level] = right_buf;
+                               path->slots[level + 1] += 1;
+                               path->slots[level] = orig_slot -
+                                       btrfs_header_nritems(&mid->header);
+                               btrfs_block_release(root, mid_buf);
+                       } else {
+                               btrfs_block_release(root, right_buf);
+                       }
+                       return 0;
+               }
+               btrfs_block_release(root, right_buf);
+       }
+       return 1;
+}
 
 /*
  * look for key in the tree.  path is filled in with nodes along the way
@@ -495,7 +617,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
                      ins_len, int cow)
 {
        struct btrfs_buffer *b;
-       struct btrfs_buffer *cow_buf;
        struct btrfs_node *c;
        int slot;
        int ret;
@@ -508,10 +629,14 @@ again:
                level = btrfs_header_level(&b->node.header);
                if (cow) {
                        int wret;
-                       wret = btrfs_cow_block(trans, root, b, p->nodes[level +
-                                              1], p->slots[level + 1],
-                                              &cow_buf);
-                       b = cow_buf;
+                       wret = btrfs_cow_block(trans, root, b,
+                                             p->nodes[level + 1],
+                                             p->slots[level + 1],
+                                             &b);
+                       if (wret) {
+                               btrfs_block_release(root, b);
+                               return wret;
+                       }
                }
                BUG_ON(!cow && ins_len);
                c = &b->node;
@@ -524,8 +649,8 @@ again:
                        if (ret && slot > 0)
                                slot -= 1;
                        p->slots[level] = slot;
-                       if (ins_len > 0 && btrfs_header_nritems(&c->header) ==
-                           BTRFS_NODEPTRS_PER_BLOCK(root)) {
+                       if (ins_len > 0 && btrfs_header_nritems(&c->header) >=
+                           BTRFS_NODEPTRS_PER_BLOCK(root) - 1) {
                                int sret = split_node(trans, root, p, level);
                                BUG_ON(sret > 0);
                                if (sret)
@@ -539,8 +664,10 @@ again:
                                if (sret)
                                        return sret;
                                b = p->nodes[level];
-                               if (!b)
+                               if (!b) {
+                                       btrfs_release_path(NULL, p);
                                        goto again;
+                               }
                                c = &b->node;
                                slot = p->slots[level];
                                BUG_ON(btrfs_header_nritems(&c->header) == 1);
@@ -553,7 +680,8 @@ again:
                        p->slots[level] = slot;
                        if (ins_len > 0 && btrfs_leaf_free_space(root, l) <
                            sizeof(struct btrfs_item) + ins_len) {
-                               int sret = split_leaf(trans, root, p, ins_len);
+                               int sret = split_leaf(trans, root, key,
+                                                     p, ins_len, ret == 0);
                                BUG_ON(sret > 0);
                                if (sret)
                                        return sret;
@@ -665,10 +793,9 @@ static int balance_node_right(struct btrfs_trans_handle *trans, struct
        if (push_items <= 0) {
                return 1;
        }
-
        max_push = src_nritems / 2 + 1;
        /* don't try to empty the node */
-       if (max_push > src_nritems)
+       if (max_push >= src_nritems)
                return 1;
        if (max_push < push_items)
                push_items = max_push;
@@ -703,13 +830,13 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root
 
        BUG_ON(path->nodes[level]);
        BUG_ON(path->nodes[level-1] != root->node);
-
        t = btrfs_alloc_free_block(trans, root, root->nodesize);
        c = &t->node;
-       memset(c, 0, root->nodesize);
+       memset(&c->header, 0, sizeof(c->header));
        btrfs_set_header_nritems(&c->header, 1);
        btrfs_set_header_level(&c->header, level);
        btrfs_set_header_bytenr(&c->header, t->bytenr);
+       btrfs_set_header_generation(&c->header, trans->transid);
        btrfs_set_header_owner(&c->header, root->root_key.objectid);
        memcpy(c->header.fsid, root->fs_info->disk_super->fsid,
               sizeof(c->header.fsid));
@@ -719,9 +846,9 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root
                lower_key = &((struct btrfs_leaf *)lower)->items[0].key;
        else
                lower_key = &lower->ptrs[0].key;
-
        memcpy(&c->ptrs[0].key, lower_key, sizeof(struct btrfs_disk_key));
        btrfs_set_node_blockptr(c, 0, path->nodes[level - 1]->bytenr);
+       BUG_ON(list_empty(&t->dirty));
        /* the super has an extra ref to root->node */
        btrfs_block_release(root, root->node);
        root->node = t;
@@ -793,6 +920,15 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
                ret = insert_new_root(trans, root, path, level + 1);
                if (ret)
                        return ret;
+       } else {
+               ret = push_nodes_for_insert(trans, root, path, level);
+               t = path->nodes[level];
+               c = &t->node;
+               if (!ret && btrfs_header_nritems(&c->header) <
+                   BTRFS_NODEPTRS_PER_BLOCK(root) - 1)
+                       return 0;
+               if (ret < 0)
+                       return ret;
        }
        c_nritems = btrfs_header_nritems(&c->header);
        split_buffer = btrfs_alloc_free_block(trans, root, root->nodesize);
@@ -800,6 +936,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
        btrfs_set_header_flags(&split->header, btrfs_header_flags(&c->header));
        btrfs_set_header_level(&split->header, btrfs_header_level(&c->header));
        btrfs_set_header_bytenr(&split->header, split_buffer->bytenr);
+       btrfs_set_header_generation(&split->header, trans->transid);
        btrfs_set_header_owner(&split->header, root->root_key.objectid);
        memcpy(split->header.fsid, root->fs_info->disk_super->fsid,
               sizeof(split->header.fsid));
@@ -836,7 +973,8 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
  * room, 0 if everything worked out and < 0 if there were major errors.
  */
 static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
-                          *root, struct btrfs_path *path, int data_size)
+                          *root, struct btrfs_path *path, int data_size,
+                          int empty)
 {
        struct btrfs_buffer *left_buf = path->nodes[0];
        struct btrfs_leaf *left = &left_buf->leaf;
@@ -844,14 +982,14 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
        struct btrfs_buffer *right_buf;
        struct btrfs_buffer *upper;
        int slot;
-       int i;
+       u32 i;
        int free_space;
        int push_space = 0;
        int push_items = 0;
        struct btrfs_item *item;
        u32 left_nritems;
+       u32 nr;
        u32 right_nritems;
-
        slot = path->slots[1];
        if (!path->nodes[1]) {
                return 1;
@@ -877,9 +1015,19 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
                btrfs_block_release(root, right_buf);
                return 1;
        }
-
        left_nritems = btrfs_header_nritems(&left->header);
-       for (i = left_nritems - 1; i >= 0; i--) {
+       if (left_nritems == 0) {
+               btrfs_block_release(root, right_buf);
+               return 1;
+       }
+
+       if (empty)
+               nr = 0;
+       else
+               nr = 1;
+
+       i = left_nritems - 1;
+       while (i >= nr) {
                item = left->items + i;
                if (path->slots[0] == i)
                        push_space += data_size + sizeof(*item);
@@ -888,6 +1036,9 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
                        break;
                push_items++;
                push_space += btrfs_item_size(item) + sizeof(*item);
+               if (i == 0)
+                       break;
+               i--;
        }
        if (push_items == 0) {
                btrfs_block_release(root, right_buf);
@@ -944,7 +1095,8 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
  * least data_size bytes.  returns zero if the push worked, nonzero otherwise
  */
 static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
-                         *root, struct btrfs_path *path, int data_size)
+                         *root, struct btrfs_path *path, int data_size,
+                         int empty)
 {
        struct btrfs_buffer *right_buf = path->nodes[0];
        struct btrfs_leaf *right = &right_buf->leaf;
@@ -957,9 +1109,10 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
        int push_items = 0;
        struct btrfs_item *item;
        u32 old_left_nritems;
+       u32 right_nritems;
+       u32 nr;
        int ret = 0;
        int wret;
-
        slot = path->slots[1];
        if (slot == 0) {
                return 1;
@@ -967,6 +1120,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
        if (!path->nodes[1]) {
                return 1;
        }
+       right_nritems = btrfs_header_nritems(&right->header);
+       if (right_nritems == 0) {
+               return 1;
+       }
+
        t = read_tree_block(root,
                    btrfs_node_blockptr(&path->nodes[1]->node, slot - 1),
                    root->leafsize);
@@ -985,8 +1143,12 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
                btrfs_block_release(root, t);
                return 1;
        }
+       if (empty)
+               nr = right_nritems;
+       else
+               nr = right_nritems - 1;
 
-       for (i = 0; i < btrfs_header_nritems(&right->header); i++) {
+       for (i = 0; i < nr; i++) {
                item = right->items + i;
                if (path->slots[0] == i)
                        push_space += data_size + sizeof(*item);
@@ -1020,22 +1182,21 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
                                                        old_left_nritems - 1)));
        }
        btrfs_set_header_nritems(&left->header, old_left_nritems + push_items);
-
        /* fixup right node */
-       push_space = btrfs_item_offset(right->items + push_items - 1) -
-                    leaf_data_end(root, right);
-       memmove(btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) -
-               push_space, btrfs_leaf_data(right) +
-               leaf_data_end(root, right), push_space);
-       memmove(right->items, right->items + push_items,
-               (btrfs_header_nritems(&right->header) - push_items) *
-               sizeof(struct btrfs_item));
-       btrfs_set_header_nritems(&right->header,
-                                btrfs_header_nritems(&right->header) -
-                                push_items);
+       if (push_items < right_nritems) {
+               push_space = btrfs_item_offset(right->items + push_items - 1) -
+                                              leaf_data_end(root, right);
+               memmove(btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) -
+                       push_space, btrfs_leaf_data(right) +
+                       leaf_data_end(root, right), push_space);
+               memmove(right->items, right->items + push_items,
+                       (right_nritems - push_items) *
+                       sizeof(struct btrfs_item));
+       }
+       right_nritems -= push_items;
+       btrfs_set_header_nritems(&right->header, right_nritems);
        push_space = BTRFS_LEAF_DATA_SIZE(root);
-
-       for (i = 0; i < btrfs_header_nritems(&right->header); i++) {
+       for (i = 0; i < right_nritems; i++) {
                btrfs_set_item_offset(right->items + i, push_space -
                                      btrfs_item_size(right->items + i));
                push_space = btrfs_item_offset(right->items + i);
@@ -1069,7 +1230,8 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
  * returns 0 if all went well and < 0 on failure.
  */
 static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
-                     *root, struct btrfs_path *path, int data_size)
+                     *root, struct btrfs_key *ins_key,
+                     struct btrfs_path *path, int data_size, int extend)
 {
        struct btrfs_buffer *l_buf;
        struct btrfs_leaf *l;
@@ -1082,67 +1244,125 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
        int data_copy_size;
        int rt_data_off;
        int i;
-       int ret;
+       int ret = 0;
        int wret;
+       int double_split;
+       int num_doubles = 0;
+       struct btrfs_disk_key disk_key;
 
+       if (extend)
+               space_needed = data_size;
        /* first try to make some room by pushing left and right */
-       wret = push_leaf_left(trans, root, path, data_size);
-       if (wret < 0)
-               return wret;
-       if (wret) {
-               wret = push_leaf_right(trans, root, path, data_size);
-               if (wret < 0)
+       if (ins_key->type != BTRFS_DIR_ITEM_KEY) {
+               wret = push_leaf_right(trans, root, path, data_size, 0);
+               if (wret < 0) {
                        return wret;
-       }
-       l_buf = path->nodes[0];
-       l = &l_buf->leaf;
-
-       /* did the pushes work? */
-       if (btrfs_leaf_free_space(root, l) >=
-           sizeof(struct btrfs_item) + data_size)
-               return 0;
+               }
+               if (wret) {
+                       wret = push_leaf_left(trans, root, path, data_size, 0);
+                       if (wret < 0)
+                               return wret;
+               }
+               l_buf = path->nodes[0];
+               l = &l_buf->leaf;
 
+               /* did the pushes work? */
+               if (btrfs_leaf_free_space(root, l) >= space_needed)
+                       return 0;
+       }
        if (!path->nodes[1]) {
                ret = insert_new_root(trans, root, path, 1);
                if (ret)
                        return ret;
        }
+again:
+       double_split = 0;
+       l_buf = path->nodes[0];
+       l = &l_buf->leaf;
        slot = path->slots[0];
        nritems = btrfs_header_nritems(&l->header);
        mid = (nritems + 1)/ 2;
+
        right_buffer = btrfs_alloc_free_block(trans, root, root->leafsize);
-       BUG_ON(!right_buffer);
-       BUG_ON(mid == nritems);
        right = &right_buffer->leaf;
        memset(&right->header, 0, sizeof(right->header));
-       if (mid <= slot) {
-               /* FIXME, just alloc a new leaf here */
-               if (leaf_space_used(l, mid, nritems - mid) + space_needed >
-                       BTRFS_LEAF_DATA_SIZE(root))
-                       BUG();
-       } else {
-               /* FIXME, just alloc a new leaf here */
-               if (leaf_space_used(l, 0, mid + 1) + space_needed >
-                       BTRFS_LEAF_DATA_SIZE(root))
-                       BUG();
-       }
-       btrfs_set_header_nritems(&right->header, nritems - mid);
        btrfs_set_header_bytenr(&right->header, right_buffer->bytenr);
+       btrfs_set_header_generation(&right->header, trans->transid);
        btrfs_set_header_level(&right->header, 0);
        btrfs_set_header_owner(&right->header, root->root_key.objectid);
        memcpy(right->header.fsid, root->fs_info->disk_super->fsid,
               sizeof(right->header.fsid));
-       data_copy_size = btrfs_item_end(l->items + mid) -
+       if (mid <= slot) {
+               if (nritems == 1 ||
+                   leaf_space_used(l, mid, nritems - mid) + space_needed >
+                       BTRFS_LEAF_DATA_SIZE(root)) {
+                       if (slot >= nritems) {
+                               btrfs_cpu_key_to_disk(&disk_key, ins_key);
+                               btrfs_set_header_nritems(&right->header, 0);
+                               wret = insert_ptr(trans, root, path,
+                                                 &disk_key, right_buffer->bytenr,
+                                                 path->slots[1] + 1, 1);
+                               if (wret)
+                                       ret = wret;
+                               btrfs_block_release(root, path->nodes[0]);
+                               path->nodes[0] = right_buffer;
+                               path->slots[0] = 0;
+                               path->slots[1] += 1;
+                               return ret;
+                       }
+                       mid = slot;
+                       if (mid != nritems &&
+                           leaf_space_used(l, mid, nritems - mid) +
+                           space_needed > BTRFS_LEAF_DATA_SIZE(root)) {
+                               double_split = 1;
+                       }
+               }
+       } else {
+               if (leaf_space_used(l, 0, mid) + space_needed >
+                       BTRFS_LEAF_DATA_SIZE(root)) {
+                       if (!extend && slot == 0) {
+                               btrfs_cpu_key_to_disk(&disk_key, ins_key);
+                               btrfs_set_header_nritems(&right->header, 0);
+                               wret = insert_ptr(trans, root, path,
+                                                 &disk_key,
+                                                 right_buffer->bytenr,
+                                                 path->slots[1], 1);
+                               if (wret)
+                                       ret = wret;
+                               btrfs_block_release(root, path->nodes[0]);
+                               path->nodes[0] = right_buffer;
+                               path->slots[0] = 0;
+                               if (path->slots[1] == 0) {
+                                       wret = fixup_low_keys(trans, root,
+                                                  path, &disk_key, 1);
+                                       if (wret)
+                                               ret = wret;
+                               }
+                               return ret;
+                       } else if (extend && slot == 0) {
+                               mid = 1;
+                       } else {
+                               mid = slot;
+                               if (mid != nritems &&
+                                   leaf_space_used(l, mid, nritems - mid) +
+                                   space_needed > BTRFS_LEAF_DATA_SIZE(root)) {
+                                       double_split = 1;
+                               }
+                       }
+               }
+       }
+       nritems = nritems - mid;
+       btrfs_set_header_nritems(&right->header, nritems);
+       data_copy_size = btrfs_item_end(l->items +  mid) -
                         leaf_data_end(root, l);
        memcpy(right->items, l->items + mid,
-              (nritems - mid) * sizeof(struct btrfs_item));
+              nritems * sizeof(struct btrfs_item));
        memcpy(btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) -
                data_copy_size, btrfs_leaf_data(l) +
                leaf_data_end(root, l), data_copy_size);
        rt_data_off = BTRFS_LEAF_DATA_SIZE(root) -
                      btrfs_item_end(l->items + mid);
-
-       for (i = 0; i < btrfs_header_nritems(&right->header); i++) {
+       for (i = 0; i < nritems; i++) {
                u32 ioff = btrfs_item_offset(right->items + i);
                btrfs_set_item_offset(right->items + i, ioff + rt_data_off);
        }
@@ -1153,6 +1373,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
                          right_buffer->bytenr, path->slots[1] + 1, 1);
        if (wret)
                ret = wret;
+
        BUG_ON(list_empty(&right_buffer->dirty));
        BUG_ON(list_empty(&l_buf->dirty));
        BUG_ON(path->slots[0] != slot);
@@ -1163,10 +1384,15 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
                path->slots[1] += 1;
        } else
                btrfs_block_release(root, right_buffer);
+
        BUG_ON(path->slots[0] < 0);
+       if (double_split) {
+               BUG_ON(num_doubles != 0);
+               num_doubles++;
+               goto again;
+       }
        return ret;
 }
-
 /*
  * Given a key and some data, insert an item into the tree.
  * This does all the path init required, making room in the tree if needed.
@@ -1385,12 +1611,12 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                         */
                        slot = path->slots[1];
                        leaf_buf->count++;
-                       wret = push_leaf_left(trans, root, path, 1);
+                       wret = push_leaf_right(trans, root, path, 1, 1);
                        if (wret < 0)
                                ret = wret;
                        if (path->nodes[0] == leaf_buf &&
                            btrfs_header_nritems(&leaf->header)) {
-                               wret = push_leaf_right(trans, root, path, 1);
+                               wret = push_leaf_left(trans, root, path, 1, 1);
                                if (wret < 0)
                                        ret = wret;
                        }
@@ -1412,6 +1638,101 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        }
        return ret;
 }
+int btrfs_truncate_item(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *root,
+                       struct btrfs_path *path,
+                       u32 new_size, int from_end)
+{
+       int ret = 0;
+       int slot;
+       int slot_orig;
+       struct btrfs_leaf *leaf;
+       struct btrfs_item *item;
+       u32 nritems;
+       unsigned int data_end;
+       unsigned int old_data_start;
+       unsigned int old_size;
+       unsigned int size_diff;
+       int i;
+
+       slot_orig = path->slots[0];
+       leaf = &path->nodes[0]->leaf;
+       slot = path->slots[0];
+
+       old_size = btrfs_item_size(leaf->items + slot);
+       if (old_size == new_size)
+               return 0;
+
+       nritems = btrfs_header_nritems(&leaf->header);
+       data_end = leaf_data_end(root, leaf);
+
+       old_data_start = btrfs_item_offset(leaf->items + slot);
+
+       size_diff = old_size - new_size;
+
+       BUG_ON(slot < 0);
+       BUG_ON(slot >= nritems);
+
+       /*
+        * item0..itemN ... dataN.offset..dataN.size .. data0.size
+        */
+       /* first correct the data pointers */
+       for (i = slot; i < nritems; i++) {
+               u32 ioff;
+               item = leaf->items + i;
+               ioff = btrfs_item_offset(item);
+               btrfs_set_item_offset(item, ioff + size_diff);
+       }
+
+       /* shift the data */
+       if (from_end) {
+               memmove(btrfs_leaf_data(leaf) + data_end + size_diff,
+                       btrfs_leaf_data(leaf) + data_end,
+                       old_data_start + new_size - data_end);
+       } else {
+               struct btrfs_disk_key *disk_key;
+               u64 offset;
+
+               disk_key = &leaf->items[slot].key;
+               if (btrfs_disk_key_type(disk_key) == BTRFS_EXTENT_DATA_KEY) {
+                       char *ptr;
+                       struct btrfs_file_extent_item *fi;
+
+                       fi = btrfs_item_ptr(leaf, slot,
+                                           struct btrfs_file_extent_item);
+                       fi = (struct btrfs_file_extent_item *)(
+                            (unsigned long)fi - size_diff);
+
+                       if (btrfs_file_extent_type(fi) ==
+                           BTRFS_FILE_EXTENT_INLINE) {
+                               ptr = btrfs_item_ptr(leaf, slot, char);
+                               memmove(ptr, (char *)fi,
+                                       offsetof(struct btrfs_file_extent_item,
+                                                disk_bytenr));
+                       }
+               }
+
+               memmove(btrfs_leaf_data(leaf) + data_end + size_diff,
+                       btrfs_leaf_data(leaf) + data_end,
+                       old_data_start - data_end);
+
+               offset = btrfs_disk_key_offset(disk_key);
+               btrfs_set_disk_key_offset(disk_key, offset + size_diff);
+               if (slot == 0)
+                       fixup_low_keys(trans, root, path, disk_key, 1);
+       }
+
+       item = leaf->items + slot;
+       btrfs_set_item_size(item, new_size);
+       BUG_ON(list_empty(&path->nodes[0]->dirty));
+
+       ret = 0;
+       if (btrfs_leaf_free_space(root, leaf) < 0) {
+               btrfs_print_leaf(root, leaf);
+               BUG();
+       }
+       return ret;
+}
 
 int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_path *path, u32 data_size)
@@ -1507,5 +1828,6 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
                                       btrfs_node_blockptr(&next->node, 0),
                                       btrfs_level_size(root, level - 1));
        }
+       check_leaf(root, path, 0);
        return 0;
 }
diff --git a/ctree.h b/ctree.h
index fb972c1..57d04ae 100644 (file)
--- a/ctree.h
+++ b/ctree.h
@@ -23,9 +23,8 @@
 #include "kerncompat.h"
 #include "radix-tree.h"
 #include "extent-cache.h"
-
+struct btrfs_root;
 struct btrfs_trans_handle;
-
 #define BTRFS_MAGIC "_B2RfS_M"
 
 #define BTRFS_ROOT_TREE_OBJECTID 1ULL
@@ -102,7 +101,9 @@ struct btrfs_header {
                               (sizeof(struct btrfs_disk_key) + sizeof(u64)))
 #define __BTRFS_LEAF_DATA_SIZE(bs) ((bs) - sizeof(struct btrfs_header))
 #define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->leafsize))
-
+#define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
+                                       sizeof(struct btrfs_item) - \
+                                       sizeof(struct btrfs_file_extent_item))
 struct btrfs_buffer;
 /*
  * the super block basically lists the main trees of the FS
@@ -759,6 +760,17 @@ static inline void btrfs_set_root_bytenr(struct btrfs_root_item *item, u64 val)
        item->bytenr = cpu_to_le64(val);
 }
 
+static inline u64 btrfs_root_byte_limit(struct btrfs_root_item *item)
+{
+       return le64_to_cpu(item->byte_limit);
+}
+
+static inline void btrfs_set_root_byte_limit(struct btrfs_root_item *item,
+                                            u64 val)
+{
+       item->byte_limit = cpu_to_le64(val);
+}
+
 static inline u8 btrfs_root_level(struct btrfs_root_item *item)
 {
        return item->level;
@@ -1028,6 +1040,9 @@ static inline void btrfs_set_file_extent_num_bytes(struct
 #define btrfs_item_ptr(leaf, slot, type) \
        ((type *)(btrfs_leaf_data(leaf) + \
        btrfs_item_offset((leaf)->items + (slot))))
+#define btrfs_item_ptr_offset(leaf, slot) \
+       ((unsigned long)(btrfs_leaf_data(leaf) + \
+       btrfs_item_offset_nr(leaf, slot)))
 
 static inline u32 btrfs_level_size(struct btrfs_root *root, int level)
 {
@@ -1036,15 +1051,25 @@ static inline u32 btrfs_level_size(struct btrfs_root *root, int level)
        return root->nodesize;
 }
 int btrfs_comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2);
-int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
-                     *root, struct btrfs_path *path, u32 data_size);
 struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                                            struct btrfs_root *root,
                                            u32 blocksize);
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                  struct btrfs_buffer *buf);
+int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
+                      struct btrfs_root *root);
 int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, u64 bytenr, u64 num_bytes, int pin);
+int btrfs_cow_block(struct btrfs_trans_handle *trans,
+                   struct btrfs_root *root, struct btrfs_buffer *buf,
+                   struct btrfs_buffer *parent, int parent_slot,
+                   struct btrfs_buffer **cow_ret);
+int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
+                     *root, struct btrfs_path *path, u32 data_size);
+int btrfs_truncate_item(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *root,
+                       struct btrfs_path *path,
+                       u32 new_size, int from_end);
 int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_key *key, struct btrfs_path *p, int
                      ins_len, int cow);
@@ -1076,11 +1101,16 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
                          *root, char *name, int name_len, u64 dir,
                          struct btrfs_key *location, u8 type);
-int btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
-                         *root, struct btrfs_path *path, u64 dir, char *name,
-                         int name_len, int mod);
-int btrfs_match_dir_item_name(struct btrfs_root *root, struct btrfs_path *path,
-                             char *name, int name_len);
+struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root, struct btrfs_path *path,
+                         u64 dir, char *name, int name_len, int mod);
+struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
+                             struct btrfs_path *path,
+                             const char *name, int name_len);
+int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
+                             struct btrfs_root *root,
+                             struct btrfs_path *path,
+                             struct btrfs_dir_item *di);
 int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
                             struct btrfs_root *fs_root,
                             u64 dirid, u64 *objectid);
@@ -1097,4 +1127,18 @@ int btrfs_insert_block_group(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct btrfs_key *key,
                             struct btrfs_block_group_item *bi);
+/* file-item.c */
+int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
+                            struct btrfs_root *root,
+                            u64 objectid, u64 pos, u64 offset,
+                            u64 disk_num_bytes, u64 num_bytes);
+int btrfs_insert_inline_file_extent(struct btrfs_trans_handle *trans,
+                                   struct btrfs_root *root, u64 objectid,
+                                   u64 offset, char *buffer, size_t size);
+int btrfs_lookup_csum(struct btrfs_trans_handle *trans, struct btrfs_root
+                     *root, struct btrfs_path *path, u64 objectid,
+                     u64 offset, int cow, struct btrfs_csum_item **item_ret);
+int btrfs_csum_file_block(struct btrfs_trans_handle *trans, struct btrfs_root
+                         *root, struct btrfs_inode_item *inode,
+                         u64 objectid, u64 offset, char *data, size_t len);
 #endif
index 3c49c56..a3cb278 100644 (file)
@@ -30,21 +30,25 @@ static struct btrfs_dir_item *insert_with_overflow(struct
                                                   struct btrfs_root *root,
                                                   struct btrfs_path *path,
                                                   struct btrfs_key *cpu_key,
-                                                  u32 data_size)
+                                                  u32 data_size,
+                                                  const char *name,
+                                                  int name_len)
 {
        int ret;
        char *ptr;
        struct btrfs_item *item;
        struct btrfs_leaf *leaf;
-
        ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
        if (ret == -EEXIST) {
-               ret = btrfs_extend_item(trans, root, path, data_size);
-               BUG_ON(ret > 0);
-               if (ret)
+               struct btrfs_dir_item *di;
+               di = btrfs_match_dir_item_name(root, path, name, name_len);
+               if (di)
                        return NULL;
+               ret = btrfs_extend_item(trans, root, path, data_size);
        }
        BUG_ON(ret > 0);
+       if (ret)
+               return NULL;
        leaf = &path->nodes[0]->leaf;
        item = leaf->items + path->slots[0];
        ptr = btrfs_item_ptr(leaf, path->slots[0], char);
@@ -75,7 +79,8 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
        BUG_ON(ret);
        btrfs_init_path(&path);
        data_size = sizeof(*dir_item) + name_len;
-       dir_item = insert_with_overflow(trans, root, &path, &key, data_size);
+       dir_item = insert_with_overflow(trans, root, &path, &key, data_size,
+                                       name, name_len);
        if (!dir_item) {
                ret = -1;
                goto out;
@@ -94,7 +99,8 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
        btrfs_release_path(root, &path);
        btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
        key.offset = location->objectid;
-       dir_item = insert_with_overflow(trans, root, &path, &key, data_size);
+       dir_item = insert_with_overflow(trans, root, &path, &key, data_size,
+                                       name, name_len);
        if (!dir_item) {
                ret = -1;
                goto out;
@@ -109,37 +115,95 @@ out:
        btrfs_release_path(root, &path);
        return ret;
 }
-
-int btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
-                         *root, struct btrfs_path *path, u64 dir, char *name,
-                         int name_len, int mod)
+struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
+                                             struct btrfs_root *root,
+                                             struct btrfs_path *path, u64 dir,
+                                             char *name, int name_len, int mod)
 {
        int ret;
        struct btrfs_key key;
        int ins_len = mod < 0 ? -1 : 0;
        int cow = mod != 0;
-
+       struct btrfs_key found_key;
+       struct btrfs_leaf *leaf;
        key.objectid = dir;
        btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
        ret = btrfs_name_hash(name, name_len, &key.offset);
        BUG_ON(ret);
        ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
-       return ret;
+       if (ret < 0)
+               return NULL;
+       if (ret > 0) {
+               if (path->slots[0] == 0)
+                       return NULL;
+               path->slots[0]--;
+       }
+
+       leaf = &path->nodes[0]->leaf;
+       btrfs_disk_key_to_cpu(&found_key, &leaf->items[path->slots[0]].key);
+
+       if (found_key.objectid != dir ||
+           btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY ||
+           found_key.offset != key.offset)
+               return NULL;
+
+       return btrfs_match_dir_item_name(root, path, name, name_len);
 }
 
-int btrfs_match_dir_item_name(struct btrfs_root *root,
-                             struct btrfs_path *path, char
-                             *name, int name_len)
+struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
+                             struct btrfs_path *path,
+                             const char *name, int name_len)
 {
-       struct btrfs_dir_item *dir_item;
+       u32 cur = 0;
+       u32 this_len;
+       u32 total_len;
        char *name_ptr;
+       struct btrfs_leaf *leaf;
+       struct btrfs_dir_item *dir_item;
 
-       dir_item = btrfs_item_ptr(&path->nodes[0]->leaf, path->slots[0],
-                                 struct btrfs_dir_item);
-       if (btrfs_dir_name_len(dir_item) != name_len)
-               return 0;
-       name_ptr = (char *)(dir_item + 1);
-       if (memcmp(name_ptr, name, name_len))
-               return 0;
-       return 1;
+       leaf = &path->nodes[0]->leaf;
+       dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
+       total_len = btrfs_item_size(leaf->items + path->slots[0]);
+       while(cur < total_len) {
+               this_len = sizeof(*dir_item) + btrfs_dir_name_len(dir_item) +
+                          btrfs_dir_data_len(dir_item);
+               name_ptr = (char *)(dir_item + 1);
+
+               if (btrfs_dir_name_len(dir_item) == name_len &&
+                   memcmp(name, name_ptr, name_len) == 0)
+                       return dir_item;
+
+               cur += this_len;
+               dir_item = (struct btrfs_dir_item *)((char *)dir_item +
+                                                    this_len);
+       }
+       return NULL;
+}
+
+int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
+                             struct btrfs_root *root,
+                             struct btrfs_path *path,
+                             struct btrfs_dir_item *di)
+{
+
+       struct btrfs_leaf *leaf;
+       u32 sub_item_len;
+       u32 item_len;
+       int ret = 0;
+
+       leaf = &path->nodes[0]->leaf;
+       sub_item_len = sizeof(*di) + btrfs_dir_name_len(di) +
+                      btrfs_dir_data_len(di);
+       item_len = btrfs_item_size(leaf->items + path->slots[0]);
+       if (sub_item_len == item_len) {
+               ret = btrfs_del_item(trans, root, path);
+       } else {
+               char *ptr = (char *)di;
+               char *start = btrfs_item_ptr(leaf, path->slots[0], char);
+               memmove(ptr, ptr + sub_item_len,
+                       item_len - (ptr + sub_item_len - start));
+               ret = btrfs_truncate_item(trans, root, path,
+                                         item_len - sub_item_len, 1);
+       }
+       return 0;
 }
index 026cdfd..da65491 100644 (file)
--- a/disk-io.c
+++ b/disk-io.c
@@ -302,11 +302,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct
        root->node->count++;
        ret = btrfs_drop_snapshot(trans, root, snap);
        BUG_ON(ret);
-
        ret = btrfs_del_root(trans, root->fs_info->tree_root, &snap_key);
        BUG_ON(ret);
-       root->fs_info->generation = root->root_key.offset + 1;
-
+       btrfs_free_transaction(root, trans);
        return ret;
 }
 
@@ -420,7 +418,7 @@ struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super)
        root->commit_root = root->node;
        root->node->count++;
        root->ref_cows = 1;
-       root->fs_info->generation = root->root_key.offset + 1;
+       root->fs_info->generation = btrfs_super_generation(super) + 1;
        btrfs_read_block_groups(root);
        return root;
 }
@@ -429,8 +427,8 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_super_block *s)
 {
        int ret;
-
        btrfs_set_super_root(s, root->fs_info->tree_root->node->bytenr);
+       btrfs_set_super_generation(s, trans->transid);
        btrfs_set_super_root_level(s,
              btrfs_header_level(&root->fs_info->tree_root->node->node.header));
        btrfs_csum_super(root, s);
@@ -460,17 +458,17 @@ int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s)
 {
        int ret;
        struct btrfs_trans_handle *trans;
-
-       trans = root->fs_info->running_transaction;
+       trans = btrfs_start_transaction(root, 1);
        btrfs_commit_transaction(trans, root, s);
+       trans = btrfs_start_transaction(root, 1);
        ret = commit_tree_roots(trans, root->fs_info);
        BUG_ON(ret);
        ret = __commit_transaction(trans, root);
        BUG_ON(ret);
        write_ctree_super(trans, root, s);
+       btrfs_free_transaction(root, trans);
        drop_cache(root);
        BUG_ON(!list_empty(&root->fs_info->trans));
-
        btrfs_free_block_groups(root->fs_info);
        close(root->fs_info->fp);
        if (root->node)
index 8615a43..621f3f6 100644 (file)
@@ -88,21 +88,34 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                  struct btrfs_buffer *buf)
 {
        u64 bytenr;
+       u32 blocksize;
        int i;
+       int level;
 
        if (!root->ref_cows)
                return 0;
 
+       level = btrfs_header_level(&buf->node.header) - 1;
+       blocksize = btrfs_level_size(root, level);
+
        if (btrfs_is_leaf(&buf->node))
                return 0;
 
        for (i = 0; i < btrfs_header_nritems(&buf->node.header); i++) {
                bytenr = btrfs_node_blockptr(&buf->node, i);
-               inc_block_ref(trans, root, bytenr, root->nodesize);
+               inc_block_ref(trans, root, bytenr, blocksize);
        }
+
        return 0;
 }
 
+int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
+                      struct btrfs_root *root)
+{
+       return inc_block_ref(trans, root, root->node->bytenr,
+                            root->node->size);
+}
+
 static int write_one_cache_group(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root,
                                 struct btrfs_path *path,
@@ -525,9 +538,8 @@ static int alloc_extent(struct btrfs_trans_handle *trans,
                ret = insert_cache_extent(&root->fs_info->pending_tree,
                                            ins->objectid, ins->offset);
                BUG_ON(ret);
-               return 0;
+               goto update_block;
        }
-
        ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
                                sizeof(extent_item));
 
@@ -537,9 +549,11 @@ static int alloc_extent(struct btrfs_trans_handle *trans,
                return ret;
        if (pending_ret)
                return pending_ret;
+update_block:
+       ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
+       BUG_ON(ret);
        return 0;
 }
-
 /*
  * helper function to allocate a block for a given tree
  * returns the tree buffer or NULL.
@@ -551,14 +565,12 @@ struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
        struct btrfs_key ins;
        int ret;
        struct btrfs_buffer *buf;
-
        ret = alloc_extent(trans, root, root->root_key.objectid,
-                          blocksize, 0, (unsigned long)-1, &ins);
+                          blocksize, 0, (u64)-1, &ins);
        if (ret) {
                BUG();
                return NULL;
        }
-       ret = update_block_group(trans, root, ins.objectid, ins.offset, 1);
        buf = find_tree_block(root, ins.objectid, blocksize);
        btrfs_set_header_generation(&buf->node.header,
                                    root->root_key.offset + 1);
index 9d0a354..9d119cf 100644 (file)
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
+#include "crc32c.h"
 
+#define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \
+                              sizeof(struct btrfs_item) * 2) / \
+                              BTRFS_CRC32_SIZE) - 1))
 int btrfs_create_file(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root, u64 dirid, u64 *objectid)
 {
        return 0;
 }
+
+int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root,
+                              u64 objectid, u64 pos,
+                              u64 offset, u64 disk_num_bytes,
+                              u64 num_bytes)
+{
+       int ret = 0;
+       struct btrfs_file_extent_item *item;
+       struct btrfs_key file_key;
+       struct btrfs_path path;
+       struct btrfs_leaf *leaf;
+
+
+       btrfs_init_path(&path);
+       file_key.objectid = objectid;
+       file_key.offset = pos;
+       btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
+
+       ret = btrfs_insert_empty_item(trans, root, &path, &file_key,
+                                     sizeof(*item));
+       if (ret < 0)
+               goto out;
+       BUG_ON(ret);
+       leaf = &path.nodes[0]->leaf;
+       item = btrfs_item_ptr(leaf, path.slots[0],
+                             struct btrfs_file_extent_item);
+       btrfs_set_file_extent_disk_bytenr(item, offset);
+       btrfs_set_file_extent_disk_num_bytes(item, disk_num_bytes);
+       btrfs_set_file_extent_offset(item, 0);
+       btrfs_set_file_extent_num_bytes(item, num_bytes);
+       btrfs_set_file_extent_generation(item, trans->transid);
+       btrfs_set_file_extent_type(item, BTRFS_FILE_EXTENT_REG);
+out:
+       btrfs_release_path(root, &path);
+       return ret;
+}
+
+int btrfs_insert_inline_file_extent(struct btrfs_trans_handle *trans,
+                                   struct btrfs_root *root, u64 objectid,
+                                   u64 offset, char *buffer, size_t size)
+{
+       int ret;
+       char *ptr;
+       u32 datasize;
+       struct btrfs_key key;
+       struct btrfs_path path;
+       struct btrfs_leaf *leaf;
+       struct btrfs_file_extent_item *ei;
+
+       btrfs_init_path(&path);
+       key.objectid = objectid;
+       key.offset = offset;
+       btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
+
+       datasize = btrfs_file_extent_calc_inline_size(size);
+       ret = btrfs_insert_empty_item(trans, root, &path, &key,
+                                     datasize);
+       BUG_ON(ret);
+       leaf = &path.nodes[0]->leaf;
+       ei = btrfs_item_ptr(leaf, path.slots[0],
+                           struct btrfs_file_extent_item);
+       btrfs_set_file_extent_generation(ei, trans->transid);
+       btrfs_set_file_extent_type(ei, BTRFS_FILE_EXTENT_INLINE);
+       ptr = btrfs_file_extent_inline_start(ei);
+       memcpy(ptr, buffer, size);
+       btrfs_release_path(root, &path);
+       return 0;
+}
+
+int btrfs_lookup_csum(struct btrfs_trans_handle *trans,
+                     struct btrfs_root *root,
+                     struct btrfs_path *path,
+                     u64 objectid, u64 offset, int cow,
+                     struct btrfs_csum_item **item_ret)
+{
+       int ret;
+       int slot;
+       struct btrfs_key file_key;
+       struct btrfs_key found_key;
+       struct btrfs_csum_item *item;
+       struct btrfs_leaf *leaf;
+       u64 csum_offset = 0;
+       int csums_in_item;
+
+       file_key.objectid = objectid;
+       file_key.offset = offset;
+       btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
+       ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
+       if (ret < 0)
+               goto fail;
+       leaf = &path->nodes[0]->leaf;
+       if (ret > 0) {
+               if (path->slots[0] == 0)
+                       goto fail;
+               path->slots[0]--;
+
+               slot = path->slots[0];
+               btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key);
+               if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
+                   found_key.objectid != objectid) {
+                       goto fail;
+               }
+               csum_offset = (offset - found_key.offset) / root->sectorsize;
+               csums_in_item = btrfs_item_size(&leaf->items[slot]);
+               csums_in_item /= BTRFS_CRC32_SIZE;
+
+               if (csum_offset >= csums_in_item) {
+                       ret = -EFBIG;
+                       goto fail;
+               }
+               ret = 0;
+       }
+       item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
+       item = (struct btrfs_csum_item *)((unsigned char *)item +
+                                         csum_offset * BTRFS_CRC32_SIZE);
+       *item_ret = item;
+fail:
+       if (ret > 0)
+               ret = -ENOENT;
+       return ret;
+}
+
+int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root,
+                         struct btrfs_inode_item *inode,
+                         u64 objectid, u64 offset,
+                         char *data, size_t len)
+{
+       int ret;
+       int slot;
+       struct btrfs_key file_key;
+       struct btrfs_key found_key;
+       u64 next_offset = (u64)-1;
+       int found_next = 0;
+       struct btrfs_path path;
+       struct btrfs_csum_item *item;
+       struct btrfs_leaf *leaf = NULL;
+       u64 csum_offset;
+       u32 csum_result = ~(u32)0;
+       u32 nritems;
+       u32 ins_size;
+
+       btrfs_init_path(&path);
+
+       file_key.objectid = objectid;
+       file_key.offset = offset;
+       btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
+
+       ret = btrfs_lookup_csum(trans, root, &path, objectid,
+                               offset, 1, &item);
+       if (!ret) {
+               leaf = &path.nodes[0]->leaf;
+               goto found;
+       }
+       if (ret != -EFBIG && ret != -ENOENT)
+               goto fail;
+       leaf = &path.nodes[0]->leaf;
+       if (ret == -EFBIG) {
+               u32 item_size;
+               slot = path.slots[0];
+               /* we found one, but it isn't big enough yet */
+               item_size = btrfs_item_size(&leaf->items[slot]);
+               if ((item_size / BTRFS_CRC32_SIZE) >= MAX_CSUM_ITEMS(root)) {
+                       /* already at max size, make a new one */
+                       goto insert;
+               }
+       } else {
+               slot = path.slots[0] + 1;
+               /* we didn't find a csum item, insert one */
+               nritems = btrfs_header_nritems(&leaf->header);
+               if (path.slots[0] >= nritems - 1) {
+                       ret = btrfs_next_leaf(root, &path);
+                       if (ret == 1)
+                               found_next = 1;
+                       if (ret != 0)
+                               goto insert;
+                       slot = 0;
+               }
+               btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key);
+               if (found_key.objectid != objectid ||
+                   found_key.type != BTRFS_CSUM_ITEM_KEY) {
+                       found_next = 1;
+                       goto insert;
+               }
+               next_offset = found_key.offset;
+               found_next = 1;
+               goto insert;
+       }
+
+       /*
+        * at this point, we know the tree has an item, but it isn't big
+        * enough yet to put our csum in.  Grow it
+        */
+       btrfs_release_path(root, &path);
+       ret = btrfs_search_slot(trans, root, &file_key, &path,
+                               BTRFS_CRC32_SIZE, 1);
+       if (ret < 0)
+               goto fail;
+       BUG_ON(ret == 0);
+       if (path.slots[0] == 0) {
+               goto insert;
+       }
+       path.slots[0]--;
+       slot = path.slots[0];
+       leaf = &path.nodes[0]->leaf;
+       btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key);
+       csum_offset = (offset - found_key.offset) / root->sectorsize;
+       if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
+           found_key.objectid != objectid ||
+           csum_offset >= MAX_CSUM_ITEMS(root)) {
+               goto insert;
+       }
+       if (csum_offset >= btrfs_item_size(&leaf->items[slot]) /
+           BTRFS_CRC32_SIZE) {
+               u32 diff = (csum_offset + 1) * BTRFS_CRC32_SIZE;
+               diff = diff - btrfs_item_size(&leaf->items[slot]);
+               if (diff != BTRFS_CRC32_SIZE)
+                       goto insert;
+               ret = btrfs_extend_item(trans, root, &path, diff);
+               BUG_ON(ret);
+               goto csum;
+       }
+
+insert:
+       btrfs_release_path(root, &path);
+       csum_offset = 0;
+       if (found_next) {
+               u64 tmp;
+               if (next_offset > btrfs_inode_size(inode))
+                       next_offset = btrfs_inode_size(inode);
+               tmp = next_offset - offset + root->sectorsize - 1;
+               tmp /= root->sectorsize;
+               if (tmp > MAX_CSUM_ITEMS(root))
+                       tmp =  MAX_CSUM_ITEMS(root);
+               ins_size = BTRFS_CRC32_SIZE * tmp;
+       } else {
+               ins_size = BTRFS_CRC32_SIZE;
+       }
+       ret = btrfs_insert_empty_item(trans, root, &path, &file_key,
+                                     ins_size);
+       if (ret < 0)
+               goto fail;
+       BUG_ON(ret != 0);
+csum:
+       slot = path.slots[0];
+       leaf = &path.nodes[0]->leaf;
+       item = btrfs_item_ptr(leaf, slot, struct btrfs_csum_item);
+       item = (struct btrfs_csum_item *)((unsigned char *)item +
+                                         csum_offset * BTRFS_CRC32_SIZE);
+found:
+       csum_result = crc32c(csum_result, data, len);
+       csum_result = ~cpu_to_le32(csum_result);
+       memcpy(item, &csum_result, BTRFS_CRC32_SIZE);
+       ret = 0;
+fail:
+       btrfs_release_path(root, &path);
+       return ret;
+}
index 8686012..3681dd8 100644 (file)
@@ -18,9 +18,9 @@
 
 #ifndef __KERNCOMPAT
 #define __KERNCOMPAT
-
 #include <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <string.h>
 #include <endian.h>
 #include <byteswap.h>
@@ -124,10 +124,6 @@ static inline int test_bit(int nr, const volatile unsigned long *addr)
 #define container_of(ptr, type, member) ({                      \
         const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
                (type *)( (char *)__mptr - offsetof(type,member) );})
-
-#define ENOMEM 5
-#define EEXIST 6
-
 #ifdef __CHECKER__
 #define __CHECK_ENDIAN__
 #define __bitwise __bitwise__
index bffd5b2..ac026aa 100644 (file)
@@ -28,8 +28,11 @@ struct btrfs_trans_handle {
 static inline struct btrfs_trans_handle *
 btrfs_start_transaction(struct btrfs_root *root, int num_blocks)
 {
+       struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_trans_handle *h = malloc(sizeof(*h));
-       h->transid = root->root_key.offset;
+       fs_info->running_transaction = h;
+       fs_info->generation++;
+       h->transid = fs_info->generation;
        h->blocks_reserved = num_blocks;
        h->blocks_used = 0;
        return h;