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

Josef Bacik jbacik at redhat.com
Mon Aug 20 14:31:14 PDT 2007


On Mon, Aug 20, 2007 at 04:52:06PM -0400, Chris Mason wrote:
> On Fri, 17 Aug 2007 17:49:30 -0400
> Josef Bacik <jbacik at redhat.com> wrote:
> 
> > Hello,
> > 
> > This patch adds block accounting per root_item in btrfs, and adds a
> > sysfs infrastructure to report it (as well as future things).  The
> > sysfs heirarchy is 
> > 
> > /sys/fs/btrfs/<sb->s_id>/<root_item name>/
> 
> Ok, this is almost perfect ;)  I see one small problem, quoting from
> the kobject docs (Documentation/kobject.txt
> 
> -------
> It is _imperative_ that you supply a destructor for dynamically
> allocated kobjects to free them if you are using kobject reference
> counts. The reference count controls the lifetime of the object.
> If it goes to 0, then it is assumed that the object will
> be freed and cannot be used.
> -------
> 
> This means that we have to free anything referenced by the kobject in
> the destructor for the kobject.  Looks like most of your sysfs bits
> touch things from kmalloc (struct btrfs_root and struct btrfs_fs_info),
> with the exception of the 3 fields that reference struct
> btrfs_fs_info->disk_super.
> 
> What I would do in this case is just get rid of those sysfs methods.
> You can get them via df, and we can deal with other problems later ;)
> 

If anything this will give you a good laugh.  I've added a completion to handle
the unregister stuff, so when we go to delete the root/super entry we
wait_on_completion, and then the release function will do the complete() on that
completion and we can continue on our merry way, nice, simple and keeps us from
crashing.  Let me know what you think.  Thank you,

Josef

diff -r 6125224d77d0 Makefile
--- a/Makefile	Fri Aug 10 16:22:09 2007 -0400
+++ b/Makefile	Mon Aug 20 17:24:34 2007 -0400
@@ -4,7 +4,7 @@ obj-m  := btrfs.o
 obj-m  := btrfs.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
+	   transaction.o bit-radix.o inode.o file.o tree-defrag.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 6125224d77d0 ctree.h
--- a/ctree.h	Fri Aug 10 16:22:09 2007 -0400
+++ b/ctree.h	Mon Aug 20 17:33:53 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. */
@@ -1184,4 +1229,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 6125224d77d0 disk-io.c
--- a/disk-io.c	Fri Aug 10 16:22:09 2007 -0400
+++ b/disk-io.c	Mon Aug 20 17:29:00 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 6125224d77d0 disk-io.h
--- a/disk-io.h	Fri Aug 10 16:22:09 2007 -0400
+++ b/disk-io.h	Mon Aug 20 17:24:34 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 6125224d77d0 extent-tree.c
--- a/extent-tree.c	Fri Aug 10 16:22:09 2007 -0400
+++ b/extent-tree.c	Mon Aug 20 17:24:34 2007 -0400
@@ -860,16 +860,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;
@@ -1184,7 +1191,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;
@@ -1202,9 +1209,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 6125224d77d0 inode.c
--- a/inode.c	Fri Aug 10 16:22:09 2007 -0400
+++ b/inode.c	Mon Aug 20 17:24:34 2007 -0400
@@ -692,7 +692,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;
@@ -706,7 +707,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);
 
@@ -769,7 +772,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)
@@ -2022,6 +2026,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);
@@ -2058,7 +2063,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 6125224d77d0 root-tree.c
--- a/root-tree.c	Fri Aug 10 16:22:09 2007 -0400
+++ b/root-tree.c	Mon Aug 20 17:24:34 2007 -0400
@@ -40,7 +40,7 @@ int btrfs_find_last_root(struct btrfs_ro
 	if (ret < 0)
 		goto out;
 	BUG_ON(ret == 0);
-	l = btrfs_buffer_leaf(path->nodes[0]);
+	l = btrfs_buffer_leaf(path->nodes[0]);	
 	BUG_ON(path->slots[0] == 0);
 	slot = path->slots[0] - 1;
 	if (btrfs_disk_key_objectid(&l->items[slot].key) != objectid) {
@@ -50,6 +50,7 @@ int btrfs_find_last_root(struct btrfs_ro
 	memcpy(item, btrfs_item_ptr(l, slot, struct btrfs_root_item),
 		sizeof(*item));
 	btrfs_disk_key_to_cpu(key, &l->items[slot].key);
+
 	ret = 0;
 out:
 	btrfs_release_path(root, path);
diff -r 6125224d77d0 super.c
--- a/super.c	Fri Aug 10 16:22:09 2007 -0400
+++ b/super.c	Mon Aug 20 17:24:34 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;
 }
 
@@ -100,6 +102,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;
@@ -181,6 +189,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)
@@ -193,6 +206,7 @@ static void __exit exit_btrfs_fs(void)
 	btrfs_exit_transaction_sys();
 	btrfs_destroy_cachep();
 	unregister_filesystem(&btrfs_fs_type);
+	btrfs_exit_sysfs();
 }
 
 module_init(init_btrfs_fs)
diff -r 6125224d77d0 sysfs.c
--- a/sysfs.c	Fri Aug 10 16:22:09 2007 -0400
+++ b/sysfs.c	Mon Aug 20 17:33:08 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);
+}



More information about the Btrfs-devel mailing list