[Btrfs-devel][PATCH]Updates for btrfs-progs

Yan Zheng yanzheng at 21cn.com
Wed Dec 5 05:06:41 PST 2007


Hello,

This patch updates some files in btrfs-progs according to kernel
module's codes.

Regards
YZ
---
diff -r 65f1b7acb8ba ctree.c
--- a/ctree.c	Tue Dec 04 15:11:12 2007 -0500
+++ b/ctree.c	Wed Dec 05 21:02:17 2007 +0800
@@ -19,15 +19,16 @@
 #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);
@@ -53,7 +54,7 @@ void btrfs_release_path(struct btrfs_roo
 	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 +68,7 @@ static int btrfs_cow_block(struct btrfs_
 	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);
@@ -477,6 +479,129 @@ static int balance_level(struct btrfs_tr
 	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
  * if key is found, we return zero and you can find the item in the leaf
@@ -495,7 +620,6 @@ int btrfs_search_slot(struct btrfs_trans
 		      ins_len, int cow)
 {
 	struct btrfs_buffer *b;
-	struct btrfs_buffer *cow_buf;
 	struct btrfs_node *c;
 	int slot;
 	int ret;
@@ -508,10 +632,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 +652,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 +667,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 +683,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;
@@ -668,7 +799,7 @@ static int balance_node_right(struct btr

 	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;
@@ -706,10 +837,11 @@ static int insert_new_root(struct btrfs_

 	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));
@@ -722,6 +854,7 @@ static int insert_new_root(struct btrfs_

 	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 +926,15 @@ static int split_node(struct btrfs_trans
 		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 +942,7 @@ static int split_node(struct btrfs_trans
 	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 +979,8 @@ static int split_node(struct btrfs_trans
  * 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,12 +988,13 @@ static int push_leaf_right(struct btrfs_
 	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];
@@ -879,7 +1024,18 @@ static int push_leaf_right(struct btrfs_
 	}

 	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 +1044,9 @@ static int push_leaf_right(struct btrfs_
 			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 +1103,8 @@ static int push_leaf_right(struct btrfs_
  * 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,6 +1117,8 @@ static int push_leaf_left(struct btrfs_t
 	int push_items = 0;
 	struct btrfs_item *item;
 	u32 old_left_nritems;
+	u32 right_nritems;
+	u32 nr;
 	int ret = 0;
 	int wret;

@@ -967,6 +1129,11 @@ static int push_leaf_left(struct btrfs_t
 	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);
@@ -986,7 +1153,12 @@ static int push_leaf_left(struct btrfs_t
 		return 1;
 	}

-	for (i = 0; i < btrfs_header_nritems(&right->header); i++) {
+	if (empty)
+		nr = right_nritems;
+	else
+		nr = right_nritems - 1;
+
+	for (i = 0; i < nr; i++) {
 		item = right->items + i;
 		if (path->slots[0] == i)
 			push_space += data_size + sizeof(*item);
@@ -1022,20 +1194,21 @@ static int push_leaf_left(struct btrfs_t
 	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 +1242,8 @@ static int push_leaf_left(struct btrfs_t
  * 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 +1256,128 @@ static int split_leaf(struct btrfs_trans
 	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 +1388,7 @@ static int split_leaf(struct btrfs_trans
 			  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,7 +1399,13 @@ static int split_leaf(struct btrfs_trans
 		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;
 }

@@ -1385,12 +1627,12 @@ int btrfs_del_item(struct btrfs_trans_ha
 			 */
 			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;
 			}
@@ -1413,6 +1655,102 @@ int btrfs_del_item(struct btrfs_trans_ha
 	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 +1845,6 @@ int btrfs_next_leaf(struct btrfs_root *r
 				       btrfs_node_blockptr(&next->node, 0),
 				       btrfs_level_size(root, level - 1));
 	}
+	check_leaf(root, path, 0);
 	return 0;
 }
diff -r 65f1b7acb8ba ctree.h
--- a/ctree.h	Tue Dec 04 15:11:12 2007 -0500
+++ b/ctree.h	Wed Dec 05 21:02:17 2007 +0800
@@ -24,6 +24,7 @@
 #include "radix-tree.h"
 #include "extent-cache.h"

+struct btrfs_root;
 struct btrfs_trans_handle;

 #define BTRFS_MAGIC "_B2RfS_M"
@@ -102,6 +103,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;
 /*
@@ -759,6 +763,16 @@ static inline void btrfs_set_root_bytenr
 	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;
@@ -1029,6 +1043,10 @@ static inline void btrfs_set_file_extent
 	((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)
 {
 	if (level == 0)
@@ -1036,15 +1054,25 @@ static inline u32 btrfs_level_size(struc
 	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 +1104,16 @@ int btrfs_insert_dir_item(struct btrfs_t
 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 +1130,18 @@ int btrfs_insert_block_group(struct btrf
 			     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
diff -r 65f1b7acb8ba dir-item.c
--- a/dir-item.c	Tue Dec 04 15:11:12 2007 -0500
+++ b/dir-item.c	Wed Dec 05 21:02:17 2007 +0800
@@ -30,7 +30,9 @@ static struct btrfs_dir_item *insert_wit
 						   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;
@@ -39,12 +41,15 @@ static struct btrfs_dir_item *insert_wit

 	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
 	if (ret == -EEXIST) {
+		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;
 	}
 	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 +80,8 @@ int btrfs_insert_dir_item(struct btrfs_t
 	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 +100,8 @@ int btrfs_insert_dir_item(struct btrfs_t
 	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;
@@ -110,36 +117,97 @@ out:
 	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;
+	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;
-}
-
-int btrfs_match_dir_item_name(struct btrfs_root *root,
-			      struct btrfs_path *path, char
-			      *name, int name_len)
-{
+	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);
+}
+
+struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
+			      struct btrfs_path *path,
+			      const char *name, int name_len)
+{
+	u32 cur = 0;
+	u32 this_len;
+	u32 total_len;
+	char *name_ptr;
+	struct btrfs_leaf *leaf;
 	struct btrfs_dir_item *dir_item;
-	char *name_ptr;
-
-	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;
+}
+
diff -r 65f1b7acb8ba disk-io.c
--- a/disk-io.c	Tue Dec 04 15:11:12 2007 -0500
+++ b/disk-io.c	Wed Dec 05 21:02:17 2007 +0800
@@ -305,7 +305,7 @@ int btrfs_commit_transaction(struct btrf

 	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 +420,7 @@ struct btrfs_root *open_ctree_fd(int fp,
 	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;
 }
@@ -431,6 +431,7 @@ int write_ctree_super(struct btrfs_trans
 	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);
@@ -461,13 +462,15 @@ int close_ctree(struct btrfs_root *root,
 	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));

diff -r 65f1b7acb8ba extent-tree.c
--- a/extent-tree.c	Tue Dec 04 15:11:12 2007 -0500
+++ b/extent-tree.c	Wed Dec 05 21:02:17 2007 +0800
@@ -88,19 +88,28 @@ int btrfs_inc_ref(struct btrfs_trans_han
 		  struct btrfs_buffer *buf)
 {
 	u64 bytenr;
+	u32 blocksize;
 	int i;
+	int level;

 	if (!root->ref_cows)
 		return 0;

 	if (btrfs_is_leaf(&buf->node))
 		return 0;
-
+	level = btrfs_header_level(&buf->node.header) - 1;
+	blocksize = btrfs_level_size(root, level);
 	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);
-	}
-	return 0;
+		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,
@@ -525,7 +534,7 @@ static int alloc_extent(struct btrfs_tra
 		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,
@@ -537,6 +546,9 @@ static int alloc_extent(struct btrfs_tra
 		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;
 }

@@ -553,12 +565,11 @@ struct btrfs_buffer *btrfs_alloc_free_bl
 	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);
diff -r 65f1b7acb8ba file-item.c
--- a/file-item.c	Tue Dec 04 15:11:12 2007 -0500
+++ b/file-item.c	Wed Dec 05 21:02:17 2007 +0800
@@ -23,9 +23,274 @@
 #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;
+}
+
diff -r 65f1b7acb8ba kerncompat.h
--- a/kerncompat.h	Tue Dec 04 15:11:12 2007 -0500
+++ b/kerncompat.h	Wed Dec 05 21:02:17 2007 +0800
@@ -21,6 +21,7 @@

 #include <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <string.h>
 #include <endian.h>
 #include <byteswap.h>
@@ -125,9 +126,6 @@ static inline int test_bit(int nr, const
         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__
diff -r 65f1b7acb8ba transaction.h
--- a/transaction.h	Tue Dec 04 15:11:12 2007 -0500
+++ b/transaction.h	Wed Dec 05 21:02:17 2007 +0800
@@ -28,8 +28,11 @@ static inline 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;



More information about the Btrfs-devel mailing list