Add generation number to btrfs_header, readdir fixes, hash collision fixes

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 052434a..b33a6bfa 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1,6 +1,7 @@
 #include <linux/module.h>
 #include "ctree.h"
 #include "disk-io.h"
+#include "transaction.h"
 
 static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
 		      *root, struct btrfs_path *path, int level);
@@ -39,7 +40,8 @@
 	struct buffer_head *cow;
 	struct btrfs_node *cow_node;
 
-	if (buffer_dirty(buf)) {
+	if (btrfs_header_generation(btrfs_buffer_header(buf)) ==
+				    trans->transid) {
 		*cow_ret = buf;
 		return 0;
 	}
@@ -47,6 +49,7 @@
 	cow_node = btrfs_buffer_node(cow);
 	memcpy(cow_node, btrfs_buffer_node(buf), root->blocksize);
 	btrfs_set_header_blocknr(&cow_node->header, cow->b_blocknr);
+	btrfs_set_header_generation(&cow_node->header, trans->transid);
 	*cow_ret = cow;
 	mark_buffer_dirty(cow);
 	btrfs_inc_ref(trans, root, buf);
@@ -661,6 +664,7 @@
 	btrfs_set_header_nritems(&c->header, 1);
 	btrfs_set_header_level(&c->header, level);
 	btrfs_set_header_blocknr(&c->header, t->b_blocknr);
+	btrfs_set_header_generation(&c->header, trans->transid);
 	btrfs_set_header_parentid(&c->header,
 	      btrfs_header_parentid(btrfs_buffer_header(root->node)));
 	lower = btrfs_buffer_node(path->nodes[level-1]);
@@ -750,6 +754,7 @@
 	split = btrfs_buffer_node(split_buffer);
 	btrfs_set_header_flags(&split->header, btrfs_header_flags(&c->header));
 	btrfs_set_header_blocknr(&split->header, split_buffer->b_blocknr);
+	btrfs_set_header_generation(&split->header, trans->transid);
 	btrfs_set_header_parentid(&split->header,
 	      btrfs_header_parentid(btrfs_buffer_header(root->node)));
 	mid = (c_nritems + 1) / 2;
@@ -1096,6 +1101,7 @@
 	}
 	btrfs_set_header_nritems(&right->header, nritems - mid);
 	btrfs_set_header_blocknr(&right->header, right_buffer->b_blocknr);
+	btrfs_set_header_generation(&right->header, trans->transid);
 	btrfs_set_header_level(&right->header, 0);
 	btrfs_set_header_parentid(&right->header,
 	      btrfs_header_parentid(btrfs_buffer_header(root->node)));
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 983e3cc..96cec63 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -52,6 +52,7 @@
 struct btrfs_header {
 	u8 fsid[16]; /* FS specific uuid */
 	__le64 blocknr; /* which block this node is supposed to live in */
+	__le64 generation;
 	__le64 parentid; /* objectid of the tree root */
 	__le32 csum;
 	__le32 ham;
@@ -600,6 +601,17 @@
 	h->blocknr = cpu_to_le64(blocknr);
 }
 
+static inline u64 btrfs_header_generation(struct btrfs_header *h)
+{
+	return le64_to_cpu(h->generation);
+}
+
+static inline void btrfs_set_header_generation(struct btrfs_header *h,
+					       u64 val)
+{
+	h->generation = cpu_to_le64(val);
+}
+
 static inline u64 btrfs_header_parentid(struct btrfs_header *h)
 {
 	return le64_to_cpu(h->parentid);
@@ -839,7 +851,7 @@
 			  *root, struct btrfs_path *path, u64 dir,
 			  const 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);
+			      const char *name, int name_len);
 int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
 			     struct btrfs_root *fs_root,
 			     u64 dirid, u64 *objectid);
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c
index f81cbcc..c18f817 100644
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -60,8 +60,8 @@
 }
 
 int btrfs_match_dir_item_name(struct btrfs_root *root,
-			      struct btrfs_path *path, char
-			      *name, int name_len)
+			      struct btrfs_path *path,
+			      const char *name, int name_len)
 {
 	struct btrfs_dir_item *dir_item;
 	char *name_ptr;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 2f1eb4a..3dea757 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -11,11 +11,7 @@
 		BUG();
 	if (root->node && btrfs_header_parentid(&node->header) !=
 	    btrfs_header_parentid(btrfs_buffer_header(root->node))) {
-		printk("block %Lu parentids don't match buf %Lu, root %Lu\n",
-		       buf->b_blocknr,
-		       btrfs_header_parentid(&node->header),
-		       btrfs_header_parentid(btrfs_buffer_header(root->node)));
-		WARN_ON(1);
+		BUG();
 	}
 	return 0;
 }
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 8970e9a..a2db055 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -199,7 +199,7 @@
 	btrfs_init_path(&path);
 	ret = btrfs_lookup_dir_item(NULL, root, &path, dir->i_ino, name,
 				    namelen, 0);
-	if (ret) {
+	if (ret || !btrfs_match_dir_item_name(root, &path, name, namelen)) {
 		*ino = 0;
 		goto out;
 	}
@@ -247,7 +247,7 @@
 	int slot;
 	int advance;
 	unsigned char d_type = DT_UNKNOWN;
-	int over;
+	int over = 0;
 
 	key.objectid = inode->i_ino;
 	key.flags = 0;
@@ -258,7 +258,7 @@
 	if (ret < 0) {
 		goto err;
 	}
-	advance = filp->f_pos > 0 && ret != 0;
+	advance = 0;
 	while(1) {
 		leaf = btrfs_buffer_leaf(path.nodes[0]);
 		nritems = btrfs_header_nritems(&leaf->header);
@@ -282,13 +282,17 @@
 			break;
 		if (btrfs_disk_key_type(&item->key) != BTRFS_DIR_ITEM_KEY)
 			continue;
+		if (btrfs_disk_key_offset(&item->key) < filp->f_pos)
+			continue;
 		di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
 		over = filldir(dirent, (const char *)(di + 1),
 			       btrfs_dir_name_len(di),
 			       btrfs_disk_key_offset(&item->key),
 			       btrfs_dir_objectid(di), d_type);
-		if (over)
+		if (over) {
+			filp->f_pos = btrfs_disk_key_offset(&item->key);
 			break;
+		}
 		filp->f_pos = btrfs_disk_key_offset(&item->key) + 1;
 	}
 	ret = 0;
@@ -425,7 +429,6 @@
 				    dentry->d_name.name, dentry->d_name.len,
 				    dentry->d_parent->d_inode->i_ino,
 				    inode->i_ino, 0);
-	BUG_ON(ret);
 	return ret;
 }
 
@@ -466,6 +469,7 @@
 {
 	sb->s_dirt = 0;
 printk("btrfs write_super!\n");
+	filemap_flush(sb->s_bdev->bd_inode->i_mapping);
 }
 
 static int btrfs_sync_fs(struct super_block *sb, int wait)