btrfs_create, btrfs_write_super, btrfs_sync_fs

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/TODO b/fs/btrfs/TODO
index c5d67bb..4b5bd05 100644
--- a/fs/btrfs/TODO
+++ b/fs/btrfs/TODO
@@ -3,6 +3,7 @@
 * Fix ENOSPC handling
 * make a real mkfs and superblock
 * Do checksumming
+* Use a real check instead of mark_buffer_dirty
 * Define FS objects in terms of different item types
 * Add block mapping tree (simple dm layer)
 * Add simple tree locking (semaphore per tree)
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index e690e2b..052434a 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -39,7 +39,7 @@
 	struct buffer_head *cow;
 	struct btrfs_node *cow_node;
 
-	if (!buffer_dirty(buf)) {
+	if (buffer_dirty(buf)) {
 		*cow_ret = buf;
 		return 0;
 	}
@@ -48,6 +48,7 @@
 	memcpy(cow_node, btrfs_buffer_node(buf), root->blocksize);
 	btrfs_set_header_blocknr(&cow_node->header, cow->b_blocknr);
 	*cow_ret = cow;
+	mark_buffer_dirty(cow);
 	btrfs_inc_ref(trans, root, buf);
 	if (buf == root->node) {
 		root->node = cow;
@@ -58,7 +59,7 @@
 	} else {
 		btrfs_set_node_blockptr(btrfs_buffer_node(parent), parent_slot,
 					cow->b_blocknr);
-		BUG_ON(!buffer_dirty(parent));
+		mark_buffer_dirty(parent);
 		btrfs_free_extent(trans, root, buf->b_blocknr, 1, 1);
 	}
 	btrfs_block_release(root, buf);
@@ -362,7 +363,7 @@
 			memcpy(&parent->ptrs[pslot + 1].key,
 				&right->ptrs[0].key,
 				sizeof(struct btrfs_disk_key));
-			BUG_ON(!buffer_dirty(parent_buf));
+			mark_buffer_dirty(parent_buf);
 		}
 	}
 	if (btrfs_header_nritems(&mid->header) == 1) {
@@ -398,7 +399,7 @@
 		/* update the parent key to reflect our changes */
 		memcpy(&parent->ptrs[pslot].key, &mid->ptrs[0].key,
 		       sizeof(struct btrfs_disk_key));
-		BUG_ON(!buffer_dirty(parent_buf));
+		mark_buffer_dirty(parent_buf);
 	}
 
 	/* update the path */
@@ -539,7 +540,7 @@
 			break;
 		t = btrfs_buffer_node(path->nodes[i]);
 		memcpy(&t->ptrs[tslot].key, key, sizeof(*key));
-		BUG_ON(!buffer_dirty(path->nodes[i]));
+		mark_buffer_dirty(path->nodes[i]);
 		if (tslot != 0)
 			break;
 	}
@@ -583,8 +584,8 @@
 	}
 	btrfs_set_header_nritems(&src->header, src_nritems - push_items);
 	btrfs_set_header_nritems(&dst->header, dst_nritems + push_items);
-	BUG_ON(!buffer_dirty(src_buf));
-	BUG_ON(!buffer_dirty(dst_buf));
+	mark_buffer_dirty(src_buf);
+	mark_buffer_dirty(dst_buf);
 	return ret;
 }
 
@@ -631,8 +632,8 @@
 	btrfs_set_header_nritems(&src->header, src_nritems - push_items);
 	btrfs_set_header_nritems(&dst->header, dst_nritems + push_items);
 
-	BUG_ON(!buffer_dirty(src_buf));
-	BUG_ON(!buffer_dirty(dst_buf));
+	mark_buffer_dirty(src_buf);
+	mark_buffer_dirty(dst_buf);
 	return ret;
 }
 
@@ -669,6 +670,9 @@
 		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]->b_blocknr);
+
+	mark_buffer_dirty(t);
+
 	/* the super has an extra ref to root->node */
 	btrfs_block_release(root, root->node);
 	root->node = t;
@@ -708,7 +712,7 @@
 	memcpy(&lower->ptrs[slot].key, key, sizeof(struct btrfs_disk_key));
 	btrfs_set_node_blockptr(lower, slot, blocknr);
 	btrfs_set_header_nritems(&lower->header, nritems + 1);
-	BUG_ON(!buffer_dirty(path->nodes[level]));
+	mark_buffer_dirty(path->nodes[level]);
 	return 0;
 }
 
@@ -755,7 +759,8 @@
 	btrfs_set_header_nritems(&c->header, mid);
 	ret = 0;
 
-	BUG_ON(!buffer_dirty(t));
+	mark_buffer_dirty(t);
+	mark_buffer_dirty(split_buffer);
 	wret = insert_ptr(trans, root, path, &split->ptrs[0].key,
 			  split_buffer->b_blocknr, path->slots[level + 1] + 1,
 			  level + 1);
@@ -886,11 +891,11 @@
 	left_nritems -= push_items;
 	btrfs_set_header_nritems(&left->header, left_nritems);
 
-	BUG_ON(!buffer_dirty(left_buf));
-	BUG_ON(!buffer_dirty(right_buf));
+	mark_buffer_dirty(left_buf);
+	mark_buffer_dirty(right_buf);
 	memcpy(&upper_node->ptrs[slot + 1].key,
 		&right->items[0].key, sizeof(struct btrfs_disk_key));
-	BUG_ON(!buffer_dirty(upper));
+	mark_buffer_dirty(upper);
 
 	/* then fixup the leaf pointer in the path */
 	if (path->slots[0] >= left_nritems) {
@@ -1004,8 +1009,8 @@
 		push_space = btrfs_item_offset(right->items + i);
 	}
 
-	BUG_ON(!buffer_dirty(t));
-	BUG_ON(!buffer_dirty(right_buf));
+	mark_buffer_dirty(t);
+	mark_buffer_dirty(right_buf);
 
 	wret = fixup_low_keys(trans, root, path, &right->items[0].key, 1);
 	if (wret)
@@ -1115,8 +1120,8 @@
 			  right_buffer->b_blocknr, path->slots[1] + 1, 1);
 	if (wret)
 		ret = wret;
-	BUG_ON(!buffer_dirty(right_buffer));
-	BUG_ON(!buffer_dirty(l_buf));
+	mark_buffer_dirty(right_buffer);
+	mark_buffer_dirty(l_buf);
 	BUG_ON(path->slots[0] != slot);
 	if (mid <= slot) {
 		btrfs_block_release(root, path->nodes[0]);
@@ -1202,12 +1207,12 @@
 	btrfs_set_item_offset(leaf->items + slot, data_end - data_size);
 	btrfs_set_item_size(leaf->items + slot, data_size);
 	btrfs_set_header_nritems(&leaf->header, nritems + 1);
+	mark_buffer_dirty(leaf_buf);
 
 	ret = 0;
 	if (slot == 0)
 		ret = fixup_low_keys(trans, root, path, &disk_key, 1);
 
-	BUG_ON(!buffer_dirty(leaf_buf));
 	if (btrfs_leaf_free_space(root, leaf) < 0)
 		BUG();
 	check_leaf(root, path, 0);
@@ -1233,6 +1238,7 @@
 		ptr = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]),
 				     path.slots[0], u8);
 		memcpy(ptr, data, data_size);
+		mark_buffer_dirty(path.nodes[0]);
 	}
 	btrfs_release_path(root, &path);
 	return ret;
@@ -1273,7 +1279,7 @@
 		if (wret)
 			ret = wret;
 	}
-	BUG_ON(!buffer_dirty(parent));
+	mark_buffer_dirty(parent);
 	return ret;
 }
 
@@ -1368,8 +1374,11 @@
 				if (wret)
 					ret = wret;
 			} else {
+				mark_buffer_dirty(leaf_buf);
 				btrfs_block_release(root, leaf_buf);
 			}
+		} else {
+			mark_buffer_dirty(leaf_buf);
 		}
 	}
 	return ret;
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 4c19a3f..983e3cc 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -833,7 +833,7 @@
 int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
 			 btrfs_root_item *item, struct btrfs_key *key);
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
-			  *root, char *name, int name_len, u64 dir, u64
+			  *root, const char *name, int name_len, u64 dir, u64
 			  objectid, u8 type);
 int btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 			  *root, struct btrfs_path *path, u64 dir,
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c
index 75d6e37..f81cbcc 100644
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -5,7 +5,7 @@
 #include "transaction.h"
 
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
-			  *root, char *name, int name_len, u64 dir, u64
+			  *root, const char *name, int name_len, u64 dir, u64
 			  objectid, u8 type)
 {
 	int ret = 0;
@@ -35,6 +35,7 @@
 	btrfs_set_dir_name_len(dir_item, name_len);
 	name_ptr = (char *)(dir_item + 1);
 	memcpy(name_ptr, name, name_len);
+	mark_buffer_dirty(path.nodes[0]);
 out:
 	btrfs_release_path(root, &path);
 	return ret;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 9cacca0..8e1dcda 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -145,19 +145,20 @@
 int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
 		      *root)
 {
-	return 0;
-#if 0
-	int ret;
-	btrfs_set_super_root(s, root->fs_info->tree_root->node->b_blocknr);
-
-	ret = pwrite(root->fs_info->fp, s, sizeof(*s),
-		     BTRFS_SUPER_INFO_OFFSET);
-	if (ret != sizeof(*s)) {
-		fprintf(stderr, "failed to write new super block err %d\n", ret);
-		return ret;
+	struct buffer_head *bh = root->fs_info->sb_buffer;
+	btrfs_set_super_root(root->fs_info->disk_super,
+			     root->fs_info->tree_root->node->b_blocknr);
+	lock_buffer(bh);
+	clear_buffer_dirty(bh);
+	bh->b_end_io = end_buffer_write_sync;
+	get_bh(bh);
+	submit_bh(WRITE, bh);
+	wait_on_buffer(bh);
+	if (!buffer_uptodate(bh)) {
+		WARN_ON(1);
+		return -EIO;
 	}
 	return 0;
-#endif
 }
 
 int close_ctree(struct btrfs_root *root)
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index e3af2c0..2818f1c 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -49,6 +49,7 @@
 	item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item);
 	refs = btrfs_extent_refs(item);
 	btrfs_set_extent_refs(item, refs + 1);
+	mark_buffer_dirty(path.nodes[0]);
 
 	btrfs_release_path(root->fs_info->extent_root, &path);
 	finish_current_insert(trans, root->fs_info->extent_root);
@@ -103,7 +104,7 @@
 int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
 			       btrfs_root *root)
 {
-	unsigned long gang[8];
+	struct buffer_head *gang[8];
 	u64 first = 0;
 	int ret;
 	int i;
@@ -116,13 +117,15 @@
 		if (!ret)
 			break;
 		if (!first)
-			first = gang[0];
+			first = gang[0]->b_blocknr;
 		for (i = 0; i < ret; i++) {
 			radix_tree_delete(&root->fs_info->pinned_radix,
-					  gang[i]);
+					  gang[i]->b_blocknr);
+			brelse(gang[i]);
 		}
 	}
-	root->fs_info->last_insert.objectid = first;
+	if (root->fs_info->last_insert.objectid > first)
+		root->fs_info->last_insert.objectid = first;
 	root->fs_info->last_insert.offset = 0;
 	return 0;
 }
@@ -161,8 +164,10 @@
 static int pin_down_block(struct btrfs_root *root, u64 blocknr, int tag)
 {
 	int err;
+	struct buffer_head *bh = sb_getblk(root->fs_info->sb, blocknr);
+	BUG_ON(!bh);
 	err = radix_tree_insert(&root->fs_info->pinned_radix,
-				blocknr, (void *)blocknr);
+				blocknr, bh);
 	BUG_ON(err);
 	if (err)
 		return err;
@@ -217,6 +222,7 @@
 		if (ret)
 			BUG();
 	}
+	mark_buffer_dirty(path.nodes[0]);
 	btrfs_release_path(extent_root, &path);
 	finish_current_insert(trans, extent_root);
 	return ret;
@@ -232,7 +238,7 @@
 	int ret;
 	int wret;
 	int err = 0;
-	unsigned long gang[4];
+	struct buffer_head *gang[4];
 	int i;
 	struct radix_tree_root *radix = &extent_root->fs_info->pinned_radix;
 
@@ -245,10 +251,12 @@
 		if (!ret)
 			break;
 		for (i = 0; i < ret; i++) {
-			radix_tree_tag_set(radix, gang[i], CTREE_EXTENT_PINNED);
-			radix_tree_tag_clear(radix, gang[i],
+			radix_tree_tag_set(radix, gang[i]->b_blocknr,
+					   CTREE_EXTENT_PINNED);
+			radix_tree_tag_clear(radix, gang[i]->b_blocknr,
 					     CTREE_EXTENT_PENDING_DEL);
-			wret = __free_extent(trans, extent_root, gang[i], 1);
+			wret = __free_extent(trans, extent_root,
+					     gang[i]->b_blocknr, 1);
 			if (wret)
 				err = wret;
 		}
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c
index c45aec2..ad2d375 100644
--- a/fs/btrfs/inode-map.c
+++ b/fs/btrfs/inode-map.c
@@ -108,6 +108,7 @@
 	inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]),
 				    path.slots[0], struct btrfs_inode_map_item);
 	btrfs_cpu_key_to_disk(&inode_item->key, location);
+	mark_buffer_dirty(path.nodes[0]);
 out:
 	btrfs_release_path(inode_root, &path);
 	return ret;
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index a4554c0..a821b5d 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -55,6 +55,7 @@
 	slot = path.slots[0];
 	memcpy(btrfs_item_ptr(l, slot, struct btrfs_root_item), item,
 		sizeof(*item));
+	mark_buffer_dirty(path.nodes[0]);
 out:
 	btrfs_release_path(root, &path);
 	return ret;
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 6204308..6080a81 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -10,6 +10,7 @@
 #include <linux/backing-dev.h>
 #include "ctree.h"
 #include "disk-io.h"
+#include "transaction.h"
 
 #define BTRFS_SUPER_MAGIC 0x9123682E
 
@@ -357,6 +358,131 @@
 	return 0;
 }
 
+static void fill_inode_item(struct btrfs_inode_item *item,
+			    struct inode *inode)
+{
+	btrfs_set_inode_uid(item, inode->i_uid);
+	btrfs_set_inode_gid(item, inode->i_gid);
+	btrfs_set_inode_size(item, inode->i_size);
+	btrfs_set_inode_mode(item, inode->i_mode);
+	btrfs_set_inode_nlink(item, inode->i_nlink);
+	btrfs_set_timespec_sec(&item->atime, inode->i_atime.tv_sec);
+	btrfs_set_timespec_nsec(&item->atime, inode->i_atime.tv_nsec);
+	btrfs_set_timespec_sec(&item->mtime, inode->i_mtime.tv_sec);
+	btrfs_set_timespec_nsec(&item->mtime, inode->i_mtime.tv_nsec);
+	btrfs_set_timespec_sec(&item->ctime, inode->i_ctime.tv_sec);
+	btrfs_set_timespec_nsec(&item->ctime, inode->i_ctime.tv_nsec);
+	btrfs_set_inode_nblocks(item, inode->i_blocks);
+	btrfs_set_inode_generation(item, inode->i_generation);
+}
+
+static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
+				     struct inode *dir, int mode)
+{
+	struct inode *inode;
+	struct btrfs_inode_item inode_item;
+	struct btrfs_root *root = btrfs_sb(dir->i_sb);
+	struct btrfs_key key;
+	int ret;
+	u64 objectid;
+
+	inode = new_inode(dir->i_sb);
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+
+	ret = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
+	BUG_ON(ret);
+
+	inode->i_uid = current->fsuid;
+	inode->i_gid = current->fsgid;
+	inode->i_mode = mode;
+	inode->i_ino = objectid;
+	inode->i_blocks = 0;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+	fill_inode_item(&inode_item, inode);
+
+
+	key.objectid = objectid;
+	key.flags = 0;
+	key.offset = 0;
+	btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
+	ret = btrfs_insert_inode_map(trans, root, objectid, &key);
+	BUG_ON(ret);
+
+	ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
+	BUG_ON(ret);
+
+	insert_inode_hash(inode);
+	// FIXME mark_inode_dirty(inode)
+	return inode;
+}
+
+static int btrfs_add_link(struct btrfs_trans_handle *trans,
+			    struct dentry *dentry, struct inode *inode)
+{
+	int ret;
+	ret = btrfs_insert_dir_item(trans, btrfs_sb(inode->i_sb),
+				    dentry->d_name.name, dentry->d_name.len,
+				    dentry->d_parent->d_inode->i_ino,
+				    inode->i_ino, 0);
+	BUG_ON(ret);
+	return ret;
+}
+
+static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
+			    struct dentry *dentry, struct inode *inode)
+{
+	int err = btrfs_add_link(trans, dentry, inode);
+	if (!err) {
+		d_instantiate(dentry, inode);
+		return 0;
+	}
+	inode_dec_link_count(inode);
+	iput(inode);
+	return err;
+}
+
+static int btrfs_create(struct inode *dir, struct dentry *dentry,
+			int mode, struct nameidata *nd)
+{
+	struct btrfs_trans_handle *trans;
+	struct btrfs_root *root = btrfs_sb(dir->i_sb);
+	struct inode *inode;
+	int err;
+
+	trans = btrfs_start_transaction(root, 1);
+	inode = btrfs_new_inode(trans, dir, mode);
+	err = PTR_ERR(inode);
+	if (IS_ERR(inode))
+		return err;
+	// FIXME mark the inode dirty
+	err = btrfs_add_nondir(trans, dentry, inode);
+	dir->i_sb->s_dirt = 1;
+	btrfs_end_transaction(trans, root);
+	return err;
+}
+
+static void btrfs_write_super(struct super_block *sb)
+{
+	sb->s_dirt = 0;
+printk("btrfs write_super!\n");
+}
+
+static int btrfs_sync_fs(struct super_block *sb, int wait)
+{
+	struct btrfs_trans_handle *trans;
+	struct btrfs_root *root;
+	int ret;
+	sb->s_dirt = 0;
+	root = btrfs_sb(sb);
+	trans = btrfs_start_transaction(root, 1);
+	ret = btrfs_commit_transaction(trans, root);
+	sb->s_dirt = 0;
+	BUG_ON(ret);
+printk("btrfs sync_fs\n");
+	return 0;
+}
+
 static int btrfs_get_sb(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 {
@@ -377,10 +503,13 @@
 	.drop_inode	= generic_delete_inode,
 	.put_super	= btrfs_put_super,
 	.read_inode	= btrfs_read_locked_inode,
+	.write_super	= btrfs_write_super,
+	.sync_fs	= btrfs_sync_fs,
 };
 
 static struct inode_operations btrfs_dir_inode_operations = {
 	.lookup		= btrfs_lookup,
+	.create		= btrfs_create,
 };
 
 static struct file_operations btrfs_dir_file_operations = {
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 8dc1c17..4903b47 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -25,7 +25,7 @@
 		init_waitqueue_head(&cur_trans->writer_wait);
 		init_waitqueue_head(&cur_trans->commit_wait);
 		cur_trans->in_commit = 0;
-		cur_trans->use_count = 0;
+		cur_trans->use_count = 1;
 		cur_trans->commit_done = 0;
 	}
 	cur_trans->num_writers++;
@@ -56,7 +56,7 @@
 	struct btrfs_transaction *cur_trans;
 	mutex_lock(&root->fs_info->trans_mutex);
 	cur_trans = root->fs_info->running_transaction;
-	WARN_ON(cur_trans->num_writers <= 1);
+	WARN_ON(cur_trans->num_writers < 1);
 	if (waitqueue_active(&cur_trans->writer_wait))
 		wake_up(&cur_trans->writer_wait);
 	cur_trans->num_writers--;
@@ -155,10 +155,13 @@
 
 	cur_trans = root->fs_info->running_transaction;
 	root->fs_info->running_transaction = NULL;
-	mutex_unlock(&root->fs_info->trans_mutex);
 
-	memcpy(&snap_key, &root->root_key, sizeof(snap_key));
-	root->root_key.offset++;
+	if (root->node != root->commit_root) {
+		memcpy(&snap_key, &root->root_key, sizeof(snap_key));
+		root->root_key.offset++;
+	}
+
+	mutex_unlock(&root->fs_info->trans_mutex);
 
 	if (btrfs_root_blocknr(&root->root_item) != root->node->b_blocknr) {
 		btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr);