[Btrfs-devel] [PATCH 2/2] block accounting+sysfs support for btrfs

Josef Bacik jbacik at redhat.com
Tue Aug 28 11:53:29 PDT 2007


On Tue, Aug 28, 2007 at 11:06:14AM -0400, Chris Mason wrote:
> 
> Hello,
> 
> I've got this merged locally (the completion handler version) and the
> sysfs bits seem to be working fine.
> 
> The only problem is the accounting doesn't record blocks that are
> deleted in the root items.  This is because of the somewhat strange
> path things take to being freed.  So, lets pretend we've got a 1GB file
> named foo and we rm it.
> 
> 1) start a transaction
> 2) remove 'foo' from dir (this cows dir blocks)
> 3) remove extent pointers from foo (this cows all blocks w/extent
> pointers)
> 4) remove the foo's inode
> 5) (eventually) commit
> 
> At this point, we have two tree roots. There's the most recent root,
> where all traces of foo are gone, and there's the old root which has
> all the tree blocks from before the cow.  The extents from foo are not
> free on disk yet, because they are still referenced by the old root.
> 
> btrfs_drop_snapshot comes in and starts dropping reference counts on
> blocks in the old root.  It will find the extent pointers for foo and
> drop references on those too, and finally those extents will really
> freed on disk.
> 
> So, this is a very long way of saying that last place actually
> calling btrfs_free_extent is actually btrfs_drop_snapshot, and it does
> this with a copy of the root item.  So, when we make changes to
> root->root_item, they never actually get sent down to the disk.  What
> we want to do is update the block count in the most recent root with
> the number of blocks that were freed by btrfs_drop_snapshot.  So,
> before calling btrfs_drop_snapshot, we need to record the number of
> blocks allocated, and the compare it with the number still there after
> calling drop_snapshot.
> 
> Then update the most recent root to reflect the changes on disk.
> 
> Does that make any sense?
> 

Well that was alot of fun.  Try this bad boy on for size, this should work.
Thanks much,

Josef

diff -r 38b3f110a93d Makefile
--- a/Makefile	Mon Aug 27 16:49:44 2007 -0400
+++ b/Makefile	Tue Aug 28 14:58:35 2007 -0400
@@ -5,7 +5,7 @@ btrfs-y := super.o ctree.o extent-tree.o
 btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
 	   hash.o file-item.o inode-item.o inode-map.o disk-io.o \
 	   transaction.o bit-radix.o inode.o file.o tree-defrag.o \
-	   extent_map.o
+	   extent_map.o sysfs.o
 
 #btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
 #	  root-tree.o dir-item.o hash.o file-item.o inode-item.o \
diff -r 38b3f110a93d ctree.h
--- a/ctree.h	Mon Aug 27 16:49:44 2007 -0400
+++ b/ctree.h	Tue Aug 28 14:58:35 2007 -0400
@@ -22,6 +22,7 @@
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
 #include <linux/workqueue.h>
+#include <linux/completion.h>
 #include "bit-radix.h"
 
 struct btrfs_trans_handle;
@@ -313,6 +314,8 @@ struct btrfs_fs_info {
 	struct list_head trans_list;
 	struct list_head dead_roots;
 	struct delayed_work trans_work;
+	struct kobject super_kobj;
+	struct completion kobj_unregister;
 	int do_barriers;
 	int closing;
 };
@@ -328,6 +331,8 @@ struct btrfs_root {
 	struct btrfs_key root_key;
 	struct btrfs_fs_info *fs_info;
 	struct inode *inode;
+	struct kobject root_kobj;
+	struct completion kobj_unregister;
 	u64 objectid;
 	u64 last_trans;
 	u32 blocksize;
@@ -338,6 +343,7 @@ struct btrfs_root {
 	struct btrfs_key defrag_progress;
 	int defrag_running;
 	int defrag_level;
+	char *name;
 };
 
 /* the lower bits in the key flags defines the item type */
@@ -814,6 +820,28 @@ static inline void btrfs_set_root_flags(
 	item->flags = cpu_to_le32(val);
 }
 
+static inline void btrfs_set_root_blocks_used(struct btrfs_root_item *item,
+						   u64 val)
+{
+	item->blocks_used = cpu_to_le64(val);
+}
+
+static inline u64 btrfs_root_blocks_used(struct btrfs_root_item *item)
+{
+	return le64_to_cpu(item->blocks_used);
+}
+
+static inline void btrfs_set_root_block_limit(struct btrfs_root_item *item,
+						u64 val)
+{
+	item->block_limit = cpu_to_le64(val);
+}
+
+static inline u64 btrfs_root_block_limit(struct btrfs_root_item *item)
+{
+	return le64_to_cpu(item->block_limit);
+}
+
 static inline u64 btrfs_super_blocknr(struct btrfs_super_block *s)
 {
 	return le64_to_cpu(s->blocknr);
@@ -1012,6 +1040,23 @@ static inline void btrfs_memmove(struct 
 {
 	btrfs_check_bounds(dst, nr, dst_block, root->fs_info->sb->s_blocksize);
 	memmove(dst, src, nr);
+}
+
+static inline int btrfs_set_root_name(struct btrfs_root *root, 
+				      const char *name, int len)
+{
+	/* if we already have a name just free it */
+	if (root->name)
+		kfree(root->name);
+
+	root->name = kmalloc(len+1, GFP_KERNEL);
+	if (!root->name)
+		return -ENOMEM;
+
+	memcpy(root->name, name, len);
+	root->name[len] ='\0';
+
+	return 0;
 }
 
 /* helper function to cast into the data area of the leaf. */
@@ -1191,4 +1236,13 @@ int btrfs_drop_extents(struct btrfs_tran
 /* tree-defrag.c */
 int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
 			struct btrfs_root *root, int cache_only);
+
+/* sysfs.c */
+int btrfs_init_sysfs(void);
+void btrfs_exit_sysfs(void);
+int btrfs_sysfs_add_super(struct btrfs_fs_info *fs);
+int btrfs_sysfs_add_root(struct btrfs_root *root);
+void btrfs_sysfs_del_root(struct btrfs_root *root);
+void btrfs_sysfs_del_super(struct btrfs_fs_info *root);
+
 #endif
diff -r 38b3f110a93d disk-io.c
--- a/disk-io.c	Mon Aug 27 16:49:44 2007 -0400
+++ b/disk-io.c	Tue Aug 28 11:49:36 2007 -0400
@@ -294,9 +294,12 @@ static int __setup_root(int blocksize,
 	root->last_trans = 0;
 	root->highest_inode = 0;
 	root->last_inode_alloc = 0;
+	root->name = NULL;
 	memset(&root->root_key, 0, sizeof(root->root_key));
 	memset(&root->root_item, 0, sizeof(root->root_item));
 	memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
+	memset(&root->root_kobj, 0, sizeof(root->root_kobj));
+	init_completion(&root->kobj_unregister);
 	root->defrag_running = 0;
 	root->defrag_level = 0;
 	root->root_key.objectid = objectid;
@@ -384,7 +387,8 @@ insert:
 }
 
 struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
-				      struct btrfs_key *location)
+				      struct btrfs_key *location,
+				      const char *name, int namelen)
 {
 	struct btrfs_root *root;
 	int ret;
@@ -405,6 +409,22 @@ struct btrfs_root *btrfs_read_fs_root(st
 		kfree(root);
 		return ERR_PTR(ret);
 	}
+
+	ret = btrfs_set_root_name(root, name, namelen);
+	if (ret) {
+		brelse(root->node);
+		kfree(root);
+		return ERR_PTR(ret);
+	}
+
+	ret = btrfs_sysfs_add_root(root);
+	if (ret) {
+		brelse(root->node);
+		kfree(root->name);
+		kfree(root);
+		return ERR_PTR(ret);
+	}
+
 	return root;
 }
 
@@ -433,6 +453,8 @@ struct btrfs_root *open_ctree(struct sup
 	INIT_RADIX_TREE(&fs_info->block_group_data_radix, GFP_KERNEL);
 	INIT_LIST_HEAD(&fs_info->trans_list);
 	INIT_LIST_HEAD(&fs_info->dead_roots);
+	memset(&fs_info->super_kobj, 0, sizeof(fs_info->super_kobj));
+	init_completion(&fs_info->kobj_unregister);
 	sb_set_blocksize(sb, 4096);
 	fs_info->running_transaction = NULL;
 	fs_info->last_trans_committed = 0;
@@ -500,8 +522,10 @@ struct btrfs_root *open_ctree(struct sup
 
 	fs_info->generation = btrfs_super_generation(disk_super) + 1;
 	ret = btrfs_find_dead_roots(tree_root);
-	if (ret)
+	if (ret) {
+		mutex_unlock(&fs_info->fs_mutex);
 		goto fail_tree_root;
+	}
 	mutex_unlock(&fs_info->fs_mutex);
 	return tree_root;
 
@@ -553,12 +577,15 @@ int btrfs_free_fs_root(struct btrfs_fs_i
 {
 	radix_tree_delete(&fs_info->fs_roots_radix,
 			  (unsigned long)root->root_key.objectid);
+	btrfs_sysfs_del_root(root);
 	if (root->inode)
 		iput(root->inode);
 	if (root->node)
 		brelse(root->node);
 	if (root->commit_root)
 		brelse(root->commit_root);
+	if (root->name)
+		kfree(root->name);
 	kfree(root);
 	return 0;
 }
diff -r 38b3f110a93d disk-io.h
--- a/disk-io.h	Mon Aug 27 16:49:44 2007 -0400
+++ b/disk-io.h	Tue Aug 28 11:49:36 2007 -0400
@@ -66,7 +66,8 @@ int btrfs_csum_data(struct btrfs_root * 
 int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len,
 		    char *result);
 struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
-				      struct btrfs_key *location);
+				      struct btrfs_key *location, 
+				      const char *name, int namelen);
 struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info,
 					       struct btrfs_key *location);
 u64 bh_blocknr(struct buffer_head *bh);
diff -r 38b3f110a93d extent-tree.c
--- a/extent-tree.c	Mon Aug 27 16:49:44 2007 -0400
+++ b/extent-tree.c	Tue Aug 28 14:26:58 2007 -0400
@@ -858,16 +858,23 @@ static int __free_extent(struct btrfs_tr
 	btrfs_set_extent_refs(ei, refs);
 	btrfs_mark_buffer_dirty(path->nodes[0]);
 	if (refs == 0) {
-		u64 super_blocks_used;
+		u64 super_blocks_used, root_blocks_used;
 
 		if (pin) {
 			ret = pin_down_block(root, blocknr, 0);
 			BUG_ON(ret);
 		}
 
+		/* block accounting for super block */
 		super_blocks_used = btrfs_super_blocks_used(&info->super_copy);
 		btrfs_set_super_blocks_used(&info->super_copy,
 					    super_blocks_used - num_blocks);
+
+		/* block accounting for root item */
+		root_blocks_used = btrfs_root_blocks_used(&root->root_item);
+		btrfs_set_root_blocks_used(&root->root_item, 
+					   root_blocks_used - num_blocks);
+
 		ret = btrfs_del_item(trans, extent_root, path);
 		if (ret) {
 			return ret;
@@ -1175,7 +1182,7 @@ int btrfs_alloc_extent(struct btrfs_tran
 {
 	int ret;
 	int pending_ret;
-	u64 super_blocks_used;
+	u64 super_blocks_used, root_blocks_used;
 	u64 search_start = 0;
 	struct btrfs_fs_info *info = root->fs_info;
 	struct btrfs_root *extent_root = info->extent_root;
@@ -1193,9 +1200,15 @@ int btrfs_alloc_extent(struct btrfs_tran
 	if (ret)
 		return ret;
 
+	/* block accounting for super block */
 	super_blocks_used = btrfs_super_blocks_used(&info->super_copy);
 	btrfs_set_super_blocks_used(&info->super_copy, super_blocks_used +
 				    num_blocks);
+	
+	/* block accounting for root item */
+	root_blocks_used = btrfs_root_blocks_used(&root->root_item);
+	btrfs_set_root_blocks_used(&root->root_item, root_blocks_used +
+				   num_blocks);
 
 	if (root == extent_root) {
 		BUG_ON(num_blocks != 1);
diff -r 38b3f110a93d inode.c
--- a/inode.c	Mon Aug 27 16:49:44 2007 -0400
+++ b/inode.c	Tue Aug 28 14:58:35 2007 -0400
@@ -733,7 +733,8 @@ out:
  */
 static int fixup_tree_root_location(struct btrfs_root *root,
 			     struct btrfs_key *location,
-			     struct btrfs_root **sub_root)
+			     struct btrfs_root **sub_root,
+			     struct dentry *dentry)
 {
 	struct btrfs_path *path;
 	struct btrfs_root_item *ri;
@@ -747,7 +748,9 @@ static int fixup_tree_root_location(stru
 	BUG_ON(!path);
 	mutex_lock(&root->fs_info->fs_mutex);
 
-	*sub_root = btrfs_read_fs_root(root->fs_info, location);
+	*sub_root = btrfs_read_fs_root(root->fs_info, location, 
+					dentry->d_name.name, 
+					dentry->d_name.len);
 	if (IS_ERR(*sub_root))
 		return PTR_ERR(*sub_root);
 
@@ -812,7 +815,8 @@ static struct dentry *btrfs_lookup(struc
 		return ERR_PTR(ret);
 	inode = NULL;
 	if (location.objectid) {
-		ret = fixup_tree_root_location(root, &location, &sub_root);
+		ret = fixup_tree_root_location(root, &location, &sub_root, 
+						dentry);
 		if (ret < 0)
 			return ERR_PTR(ret);
 		if (ret > 0)
@@ -1829,6 +1833,7 @@ static int create_subvol(struct btrfs_ro
 
 	btrfs_set_root_blocknr(&root_item, bh_blocknr(subvol));
 	btrfs_set_root_refs(&root_item, 1);
+	btrfs_set_root_blocks_used(&root_item, 0);
 	memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
 	root_item.drop_level = 0;
 	brelse(subvol);
@@ -1865,7 +1870,7 @@ static int create_subvol(struct btrfs_ro
 	if (ret)
 		goto fail_commit;
 
-	new_root = btrfs_read_fs_root(root->fs_info, &key);
+	new_root = btrfs_read_fs_root(root->fs_info, &key, name, namelen);
 	BUG_ON(!new_root);
 
 	trans = btrfs_start_transaction(new_root, 1);
diff -r 38b3f110a93d super.c
--- a/super.c	Mon Aug 27 16:49:44 2007 -0400
+++ b/super.c	Tue Aug 28 11:49:36 2007 -0400
@@ -45,12 +45,14 @@ static void btrfs_put_super (struct supe
 static void btrfs_put_super (struct super_block * sb)
 {
 	struct btrfs_root *root = btrfs_sb(sb);
+	struct btrfs_fs_info *fs = root->fs_info;
 	int ret;
 
 	ret = close_ctree(root);
 	if (ret) {
 		printk("close ctree returns %d\n", ret);
 	}
+	btrfs_sysfs_del_super(fs);
 	sb->s_fs_info = NULL;
 }
 
@@ -101,6 +103,12 @@ static int btrfs_fill_super(struct super
 		err = -ENOMEM;
 		goto fail_close;
 	}
+
+	/* this does the super kobj at the same time */
+	err = btrfs_sysfs_add_super(tree_root->fs_info);
+	if (err)
+		goto fail_close;
+		
 	sb->s_root = root_dentry;
 	btrfs_transaction_queue_work(tree_root, HZ * 30);
 	return 0;
@@ -182,6 +190,11 @@ static int __init init_btrfs_fs(void)
 static int __init init_btrfs_fs(void)
 {
 	int err;
+
+	err = btrfs_init_sysfs();
+	if (err)
+		return err;
+
 	btrfs_init_transaction_sys();
 	err = btrfs_init_cachep();
 	if (err)
@@ -196,6 +209,7 @@ static void __exit exit_btrfs_fs(void)
 	btrfs_destroy_cachep();
 	extent_map_exit();
 	unregister_filesystem(&btrfs_fs_type);
+	btrfs_exit_sysfs();
 }
 
 module_init(init_btrfs_fs)
diff -r 38b3f110a93d sysfs.c
--- a/sysfs.c	Mon Aug 27 16:49:44 2007 -0400
+++ b/sysfs.c	Tue Aug 28 11:49:36 2007 -0400
@@ -16,6 +16,242 @@
  * Boston, MA 021110-1307, USA.
  */
 
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
+
+static ssize_t root_blocks_used_show(struct btrfs_root *root, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%llu\n", 
+		(unsigned long long)btrfs_root_blocks_used(&root->root_item));
+}
+
+static ssize_t root_block_limit_show(struct btrfs_root *root, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%llu\n",
+		(unsigned long long)btrfs_root_block_limit(&root->root_item));
+}
+
+static ssize_t super_blocks_used_show(struct btrfs_fs_info *fs, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%llu\n",
+		(unsigned long long)btrfs_super_blocks_used(fs->disk_super));
+}
+
+static ssize_t super_total_blocks_show(struct btrfs_fs_info *fs, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%llu\n",
+		(unsigned long long)btrfs_super_total_blocks(fs->disk_super));
+}
+
+static ssize_t super_blocksize_show(struct btrfs_fs_info *fs, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%llu\n",
+		(unsigned long long)btrfs_super_blocksize(fs->disk_super));
+}
+
+/* this is for root attrs (subvols/snapshots) */
+struct btrfs_root_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct btrfs_root *, char *);
+	ssize_t (*store)(struct btrfs_root *, const char *, size_t);
+};
+
+#define ROOT_ATTR(name, mode, show, store) \
+static struct btrfs_root_attr btrfs_root_attr_##name = __ATTR(name, mode, show, store)
+
+ROOT_ATTR(blocks_used,	0444,	root_blocks_used_show,	NULL);
+ROOT_ATTR(block_limit,	0644,	root_block_limit_show,	NULL);
+
+static struct attribute *btrfs_root_attrs[] = {
+	&btrfs_root_attr_blocks_used.attr,
+	&btrfs_root_attr_block_limit.attr,
+	NULL,
+};
+
+/* this is for super attrs (actual full fs) */
+struct btrfs_super_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct btrfs_fs_info *, char *);
+	ssize_t (*store)(struct btrfs_fs_info *, const char *, size_t);
+};
+
+#define SUPER_ATTR(name, mode, show, store) \
+static struct btrfs_super_attr btrfs_super_attr_##name = __ATTR(name, mode, show, store)
+
+SUPER_ATTR(blocks_used,		0444,	super_blocks_used_show,		NULL);
+SUPER_ATTR(total_blocks,	0444,	super_total_blocks_show,	NULL);
+SUPER_ATTR(blocksize,		0444,	super_blocksize_show,		NULL);
+
+static struct attribute *btrfs_super_attrs[] = {
+	&btrfs_super_attr_blocks_used.attr,
+	&btrfs_super_attr_total_blocks.attr,
+	&btrfs_super_attr_blocksize.attr,
+	NULL,
+};
+
+static ssize_t btrfs_super_attr_show(struct kobject *kobj, 
+				    struct attribute *attr, char *buf)
+{
+	struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info,
+						super_kobj);
+	struct btrfs_super_attr *a = container_of(attr, 
+						  struct btrfs_super_attr,
+						  attr);
+
+	return a->show ? a->show(fs, buf) : 0;
+}
+
+static ssize_t btrfs_super_attr_store(struct kobject *kobj,
+				     struct attribute *attr,
+				     const char *buf, size_t len)
+{
+	struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info,
+						super_kobj);
+	struct btrfs_super_attr *a = container_of(attr,
+						  struct btrfs_super_attr,
+						  attr);
+
+	return a->store ? a->store(fs, buf, len) : 0;
+}
+
+static ssize_t btrfs_root_attr_show(struct kobject *kobj, 
+				    struct attribute *attr, char *buf)
+{
+	struct btrfs_root *root = container_of(kobj, struct btrfs_root, 
+						root_kobj);
+	struct btrfs_root_attr *a = container_of(attr, 
+						 struct btrfs_root_attr,
+						 attr);
+
+	return a->show ? a->show(root, buf) : 0;
+}
+
+static ssize_t btrfs_root_attr_store(struct kobject *kobj, 
+				     struct attribute *attr, 
+				     const char *buf, size_t len)
+{
+	struct btrfs_root *root = container_of(kobj, struct btrfs_root, 
+						root_kobj);
+	struct btrfs_root_attr *a = container_of(attr, 
+						 struct btrfs_root_attr, 
+						 attr);
+	return a->store ? a->store(root, buf, len) : 0;
+}
+
+static void btrfs_super_release(struct kobject *kobj)
+{
+	struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info,
+						super_kobj);
+	complete(&fs->kobj_unregister);
+}
+
+static void btrfs_root_release(struct kobject *kobj)
+{
+	struct btrfs_root *root = container_of(kobj, struct btrfs_root,
+						root_kobj);
+	complete(&root->kobj_unregister);
+}
+
+static struct sysfs_ops btrfs_super_attr_ops = {
+	.show	= btrfs_super_attr_show,
+	.store	= btrfs_super_attr_store,
+};
+
+static struct sysfs_ops btrfs_root_attr_ops = {
+	.show	= btrfs_root_attr_show,
+	.store	= btrfs_root_attr_store,
+};
+
+static struct kobj_type btrfs_root_ktype = {
+	.default_attrs	= btrfs_root_attrs,
+	.sysfs_ops	= &btrfs_root_attr_ops,
+	.release	= btrfs_root_release,
+};
+
+static struct kobj_type btrfs_super_ktype = {
+	.default_attrs	= btrfs_super_attrs,
+	.sysfs_ops	= &btrfs_super_attr_ops,
+	.release	= btrfs_super_release,
+};
+
+static struct kset btrfs_kset = {
+	.kobj	= {.name = "btrfs"},
+};
+
+int btrfs_sysfs_add_super(struct btrfs_fs_info *fs)
+{
+	int error;
+
+	fs->super_kobj.kset = &btrfs_kset;
+	fs->super_kobj.ktype = &btrfs_super_ktype;
+
+	error = kobject_set_name(&fs->super_kobj, "%s", 
+				 fs->sb->s_id);
+	if (error)
+		goto fail;
+
+	error = kobject_register(&fs->super_kobj);
+	if (error)
+		goto fail;
+
+	return 0;
+
+fail:
+	printk(KERN_ERR "btrfs: sysfs creation for super failed\n");
+	return error;
+}
+
+int btrfs_sysfs_add_root(struct btrfs_root *root)
+{
+	int error;
+
+	root->root_kobj.ktype = &btrfs_root_ktype;
+	root->root_kobj.parent = &root->fs_info->super_kobj;
+
+	error = kobject_set_name(&root->root_kobj, "%s", root->name);
+	if (error) {
+		goto fail;
+	}
+
+	error = kobject_register(&root->root_kobj);
+	if (error)
+		goto fail;
+
+	return 0;
+
+fail:
+	printk(KERN_ERR "btrfs: sysfs creation for root failed\n");
+	return error;
+}
+
+void btrfs_sysfs_del_root(struct btrfs_root *root)
+{
+	kobject_unregister(&root->root_kobj);
+	wait_for_completion(&root->kobj_unregister);
+}
+
+void btrfs_sysfs_del_super(struct btrfs_fs_info *fs)
+{
+	kobject_unregister(&fs->super_kobj);
+	wait_for_completion(&fs->kobj_unregister);
+}
+
+int btrfs_init_sysfs()
+{
+	kobj_set_kset_s(&btrfs_kset, fs_subsys);
+	return kset_register(&btrfs_kset);
+}
+
+void btrfs_exit_sysfs()
+{
+	kset_unregister(&btrfs_kset);
+}
diff -r 38b3f110a93d transaction.c
--- a/transaction.c	Mon Aug 27 16:49:44 2007 -0400
+++ b/transaction.c	Tue Aug 28 14:54:18 2007 -0400
@@ -236,6 +236,7 @@ struct dirty_root {
 struct dirty_root {
 	struct list_head list;
 	struct btrfs_root *root;
+	struct btrfs_root *latest_root;
 };
 
 int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list)
@@ -291,6 +292,7 @@ static int add_dirty_roots(struct btrfs_
 
 			memcpy(dirty->root, root, sizeof(*root));
 			dirty->root->node = root->commit_root;
+			dirty->latest_root = root;
 			root->commit_root = NULL;
 
 			root->root_key.offset = root->fs_info->generation;
@@ -388,16 +390,24 @@ static int drop_dirty_roots(struct btrfs
 	int err;
 
 	while(!list_empty(list)) {
+		u64 num_blocks, blocks_used;
+		struct btrfs_root *root;
+
 		mutex_lock(&tree_root->fs_info->fs_mutex);
 		dirty = list_entry(list->next, struct dirty_root, list);
 		list_del_init(&dirty->list);
 
+		num_blocks = btrfs_root_blocks_used(&dirty->root->root_item);
+		root = dirty->latest_root;
+		
 		while(1) {
 			trans = btrfs_start_transaction(tree_root, 1);
+
 			ret = btrfs_drop_snapshot(trans, dirty->root);
 			if (ret != -EAGAIN) {
 				break;
 			}
+
 			err = btrfs_update_root(trans,
 					tree_root,
 					&dirty->root->root_key,
@@ -414,6 +424,12 @@ static int drop_dirty_roots(struct btrfs
 			mutex_lock(&tree_root->fs_info->fs_mutex);
 		}
 		BUG_ON(ret);
+
+		num_blocks -= btrfs_root_blocks_used(&dirty->root->root_item);
+		blocks_used = btrfs_root_blocks_used(&root->root_item);
+		btrfs_set_root_blocks_used(&root->root_item,
+					   blocks_used - num_blocks);
+
 		ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key);
 		if (ret)
 			break;



More information about the Btrfs-devel mailing list