diff mbox

[RFC,PATCH2] exporting info via sysfs

Message ID 201011081913.46171.kreijack@libero.it (mailing list archive)
State New, archived
Headers show

Commit Message

Goffredo Baroncelli Nov. 8, 2010, 6:13 p.m. UTC
None
diff mbox

Patch

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 8299a25..2251faf 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -51,6 +51,7 @@ 
 #include "version.h"
 #include "export.h"
 #include "compression.h"
+#include "sysfs.h"
 
 static const struct super_operations btrfs_super_ops;
 
@@ -59,6 +60,7 @@  static void btrfs_put_super(struct super_block *sb)
 	struct btrfs_root *root = btrfs_sb(sb);
 	int ret;
 
+	btrfs_sysfs_del_super(root->fs_info);
 	ret = close_ctree(root);
 	sb->s_fs_info = NULL;
 
@@ -585,6 +587,7 @@  static struct dentry *btrfs_mount(struct file_system_type *fs_type, int 
flags,
 	char *subvol_name = NULL;
 	u64 subvol_objectid = 0;
 	int error = 0;
+	struct btrfs_root *broot;
 
 	if (!(flags & MS_RDONLY))
 		mode |= FMODE_WRITE;
@@ -668,6 +671,10 @@  static struct dentry *btrfs_mount(struct file_system_type *fs_type, int 
flags,
 		root = new_root;
 	}
 
+
+	broot = s->s_fs_info;
+	btrfs_sysfs_add_super(broot->fs_info); /* FIXME: check error */
+
 	kfree(subvol_name);
 	return root;
 
@@ -677,6 +684,7 @@  error_close_devices:
 	btrfs_close_devices(fs_devices);
 error_free_subvol_name:
 	kfree(subvol_name);
+/*error:*/
 	return ERR_PTR(error);
 }
 
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index 4ce16ef..b64cf458 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -27,17 +27,70 @@ 
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
+#include "volumes.h"
 
-static ssize_t root_blocks_used_show(struct btrfs_root *root, char *buf)
+/*
+ * This function converts the supplied UUID into a 36 chars (plus
+ * trailing '\0') string like
+ * 1b4e28ba-2fa1-11d2-883f-0016d3cca427
+ */
+static void uuid_unparse(u8 *uuid, char *out)
 {
-	return snprintf(buf, PAGE_SIZE, "%llu\n",
-		(unsigned long long)btrfs_root_used(&root->root_item));
+	static char i2x[]="0123456789abcdef";
+	static int nchars[] = {4,2,2,2,6,0};
+	int	j;
+
+	for( j = 0 ; nchars[j] ; j++ ){
+		int	i;
+		for(i=0;i<nchars[j]; i++, uuid++){
+			*out++ = i2x[*uuid / 0x10];
+			*out++ = i2x[*uuid & 0x0f];
+		}
+		if(nchars[j+1])
+			*out++ = '-';
+	}
+	*out = 0;
 }
 
-static ssize_t root_block_limit_show(struct btrfs_root *root, char *buf)
+#define BTRFS_SYSFS_ATTR_SHOW_LLU(s, name, mode) \
+	BTRFS_SYSFS_ATTR_SHOW_LLU_EX(s, name, mode, name)
+
+#define BTRFS_SYSFS_ATTR_SHOW_LLU_EX(s, name, mode, param)                 \
+static ssize_t s##_##name##_show(struct s *obj, char *buf)                 \
+{                                                                          \
+	return snprintf(buf, PAGE_SIZE, "%llu\n",                          \
+		(unsigned long long)obj->param);                           \
+}                                                                          \
+static struct s##_attr s##_attr_##name = __ATTR(name, mode,                \
+						s##_##name##_show, NULL)
+
+#define BTRFS_SYSFS_ATTR_SHOW_FUNC(s, name, mode)                          \
+static ssize_t s##_##name##_show(struct s *obj, char *buf);                \
+static struct s##_attr s##_attr_##name = __ATTR(name, mode,                \
+						s##_##name##_show, NULL);  \
+static ssize_t s##_##name##_show(struct s *obj, char *buf)
+
+/* this is for super attrs (actual full fs) */
+struct btrfs_fs_info_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct btrfs_fs_info *, char *);
+	ssize_t (*store)(struct btrfs_fs_info *, const char *, size_t);
+};
+
+BTRFS_SYSFS_ATTR_SHOW_LLU_EX(btrfs_fs_info, num_devices, 0444,
+					 fs_devices->num_devices);
+BTRFS_SYSFS_ATTR_SHOW_LLU_EX(btrfs_fs_info, open_devices, 0444,
+					 fs_devices->open_devices);
+BTRFS_SYSFS_ATTR_SHOW_LLU_EX(btrfs_fs_info, rw_devices, 0444,
+					 fs_devices->rw_devices);
+BTRFS_SYSFS_ATTR_SHOW_LLU_EX(btrfs_fs_info, total_devices, 0444,
+					 super_copy.num_devices);
+BTRFS_SYSFS_ATTR_SHOW_FUNC(btrfs_fs_info, label, 0444)
 {
-	return snprintf(buf, PAGE_SIZE, "%llu\n",
-		(unsigned long long)btrfs_root_limit(&root->root_item));
+	strncpy(buf, obj->super_copy.label, PAGE_SIZE-2);
+	buf[PAGE_SIZE-2]=0;
+	strcat(buf,"\n");
+	return strlen(buf);
 }
 
 static ssize_t super_blocks_used_show(struct btrfs_fs_info *fs, char *buf)
@@ -59,26 +112,6 @@  static ssize_t super_blocksize_show(struct btrfs_fs_info *fs, char *buf)
 		(unsigned long long)btrfs_super_sectorsize(&fs->super_copy));
 }
 
-/* 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;
@@ -98,6 +131,11 @@  static struct attribute *btrfs_super_attrs[] = {
 	&btrfs_super_attr_blocks_used.attr,
 	&btrfs_super_attr_total_blocks.attr,
 	&btrfs_super_attr_blocksize.attr,
+	&btrfs_fs_info_attr_num_devices.attr,
+	&btrfs_fs_info_attr_open_devices.attr,
+	&btrfs_fs_info_attr_rw_devices.attr,
+	&btrfs_fs_info_attr_total_devices.attr,
+	&btrfs_fs_info_attr_label.attr,
 	NULL,
 };
 
@@ -126,42 +164,13 @@  static ssize_t btrfs_super_attr_store(struct kobject *kobj,
 	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);
+	printk("->complete(&fs->kobj_unregister)\n");
 	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);
+	printk("<-complete(&fs->kobj_unregister)\n");
 }
 
 static const struct sysfs_ops btrfs_super_attr_ops = {
@@ -169,17 +178,6 @@  static const struct sysfs_ops btrfs_super_attr_ops = {
 	.store	= btrfs_super_attr_store,
 };
 
-static const 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,
@@ -187,83 +185,229 @@  static struct kobj_type btrfs_super_ktype = {
 };
 
 /* /sys/fs/btrfs/ entry */
-static struct kset *btrfs_kset;
+static struct kobject *btrfs_kobject=NULL;
+static struct kset *btrfs_devices_kset=NULL;
+static struct kset *btrfs_fs_kset=NULL;
 
-int btrfs_sysfs_add_super(struct btrfs_fs_info *fs)
+/*
+ * devices helper function
+ */
+struct btrfs_device_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct btrfs_device *, char *);
+	ssize_t (*store)(struct btrfs_device *, const char *, size_t);
+};
+
+BTRFS_SYSFS_ATTR_SHOW_FUNC(btrfs_device, fsid, 0444)
 {
-	int error;
-	char *name;
-	char c;
-	int len = strlen(fs->sb->s_id) + 1;
-	int i;
-
-	name = kmalloc(len, GFP_NOFS);
-	if (!name) {
-		error = -ENOMEM;
-		goto fail;
+	spin_lock(&obj->io_lock);
+	uuid_unparse(obj->fs_devices->fsid, buf);
+	spin_unlock(&obj->io_lock);
+	return 36;
+}
+BTRFS_SYSFS_ATTR_SHOW_FUNC(btrfs_device, minor, 0444)
+{
+	int	len;
+	
+	if(!obj->bdev){
+		strcpy(buf,"none\n");
+		return 5;
 	}
+	spin_lock(&obj->io_lock);
+	len = snprintf(buf, PAGE_SIZE, "%llu\n",
+		(unsigned long long)MINOR(obj->bdev->bd_dev));
+	spin_unlock(&obj->io_lock);
+	return len;
+}
+BTRFS_SYSFS_ATTR_SHOW_FUNC(btrfs_device, major, 0444)
+{
+	int	len;
 
-	for (i = 0; i < len; i++) {
-		c = fs->sb->s_id[i];
-		if (c == '/' || c == '\\')
-			c = '!';
-		name[i] = c;
+	if(!obj->bdev){
+		strcpy(buf,"none\n");
+		return 5;
 	}
-	name[len] = '\0';
+	spin_lock(&obj->io_lock);
+	len = snprintf(buf, PAGE_SIZE, "%llu\n",
+		(unsigned long long)MAJOR(obj->bdev->bd_dev));
+	spin_unlock(&obj->io_lock);
+	return len;
+}
+BTRFS_SYSFS_ATTR_SHOW_FUNC(btrfs_device, name, 0444)
+{
+	int	len=0;
+
+	spin_lock(&obj->io_lock);
+	
+	if(obj->bdev){
+		len = snprintf(buf, PAGE_SIZE, "%d/%d\n",
+				MAJOR(obj->bdev->bd_dev),
+				MINOR(obj->bdev->bd_dev));
+		goto exit;
+	}
+	if(!obj->name)
+		goto exit;
+	strncpy(buf, obj->name,PAGE_SIZE-1);
+	buf[PAGE_SIZE-1]=0;
+	len = strlen(obj->name);
+
+exit:
+	spin_unlock(&obj->io_lock);
+	return len;
+}
+BTRFS_SYSFS_ATTR_SHOW_LLU(btrfs_device, devid,	 0444);
+BTRFS_SYSFS_ATTR_SHOW_LLU(btrfs_device, writeable,	 0444);
+BTRFS_SYSFS_ATTR_SHOW_LLU(btrfs_device, bytes_used,	 0444);
+BTRFS_SYSFS_ATTR_SHOW_LLU(btrfs_device, total_bytes, 0444);
+BTRFS_SYSFS_ATTR_SHOW_LLU(btrfs_device, disk_total_bytes, 0444);
+BTRFS_SYSFS_ATTR_SHOW_FUNC(btrfs_device, status, 0444)
+{
+	return snprintf(buf, PAGE_SIZE, obj->bdev ? "online\n" : "offline\n");
+}
 
-	fs->super_kobj.kset = btrfs_kset;
-	error = kobject_init_and_add(&fs->super_kobj, &btrfs_super_ktype,
+static struct attribute *btrfs_device_attrs[] = {
+	&btrfs_device_attr_fsid.attr,
+	&btrfs_device_attr_devid.attr,
+	&btrfs_device_attr_writeable.attr,
+	&btrfs_device_attr_minor.attr,
+	&btrfs_device_attr_major.attr,
+	&btrfs_device_attr_total_bytes.attr,
+	&btrfs_device_attr_bytes_used.attr,
+	&btrfs_device_attr_disk_total_bytes.attr,
+	&btrfs_device_attr_name.attr,
+	&btrfs_device_attr_status.attr,
+	NULL,
+};
+
+static ssize_t btrfs_device_attr_show(struct kobject *kobj,
+				    struct attribute *attr, char *buf)
+{
+	struct btrfs_device *dev = container_of(kobj, struct btrfs_device,
+						device_kobj);
+	struct btrfs_device_attr *a = container_of(attr,
+						 struct btrfs_device_attr,
+						 attr);
+
+	return a->show ? a->show(dev, buf) : 0;
+}
+
+static ssize_t btrfs_device_attr_store(struct kobject *kobj,
+				     struct attribute *attr,
+				     const char *buf, size_t len)
+{
+	struct btrfs_device *dev = container_of(kobj, struct btrfs_device,
+						device_kobj);
+	struct btrfs_device_attr *a = container_of(attr,
+						 struct btrfs_device_attr,
+						 attr);
+	return a->store ? a->store(dev, buf, len) : 0;
+}
+
+
+static const struct sysfs_ops btrfs_device_attr_ops = {
+	.show	= btrfs_device_attr_show,
+	.store	= btrfs_device_attr_store,
+};
+
+static void btrfs_device_release(struct kobject *kobj)
+{
+	struct btrfs_device *dev = container_of(kobj, struct btrfs_device,
+						device_kobj);
+	complete(&dev->kobj_unregister);
+}
+
+static struct kobj_type btrfs_device_ktype = {
+	.default_attrs	= btrfs_device_attrs,
+	.sysfs_ops	= &btrfs_device_attr_ops,
+	.release	= btrfs_device_release,
+};
+
+int btrfs_sysfs_add_device(struct btrfs_device *dev)
+{
+	int error = 0;
+	char name[37];
+
+	uuid_unparse(dev->uuid, name);
+
+	dev->device_kobj.kset = btrfs_devices_kset;
+	error = kobject_init_and_add(&dev->device_kobj, &btrfs_device_ktype,
 				     NULL, "%s", name);
-	kfree(name);
+	init_completion(&dev->kobj_unregister);
 	if (error)
-		goto fail;
+		printk(KERN_ERR "btrfs: sysfs creation for devices failed\n");
 
-	return 0;
-
-fail:
-	printk(KERN_ERR "btrfs: sysfs creation for super failed\n");
+	printk("dev->name = %s; dev->bdev = 0x%p\n",
+	       dev->name, dev->bdev);
 	return error;
+
 }
+void btrfs_sysfs_del_device(struct btrfs_device *dev)
+{
+	printk("btrfs_sysfs_del_device\n");
 
-int btrfs_sysfs_add_root(struct btrfs_root *root)
+	kobject_put(&dev->device_kobj);
+	wait_for_completion(&dev->kobj_unregister);
+}
+int btrfs_sysfs_add_super(struct btrfs_fs_info *fs)
 {
 	int error;
+	char name[37];
+
+	printk("btrfs_sysfs_add_super\n");
+	
+	uuid_unparse(fs->fsid, name);
 
-	error = kobject_init_and_add(&root->root_kobj, &btrfs_root_ktype,
-				     &root->fs_info->super_kobj,
-				     "%s", root->name);
+	fs->super_kobj.kset = btrfs_fs_kset;
+	error = kobject_init_and_add(&fs->super_kobj, &btrfs_super_ktype,
+				     NULL, "%s", name);
 	if (error)
 		goto fail;
 
 	return 0;
 
 fail:
-	printk(KERN_ERR "btrfs: sysfs creation for root failed\n");
+	printk(KERN_ERR "btrfs: sysfs creation for super failed\n");
 	return error;
 }
 
-void btrfs_sysfs_del_root(struct btrfs_root *root)
-{
-	kobject_put(&root->root_kobj);
-	wait_for_completion(&root->kobj_unregister);
-}
-
 void btrfs_sysfs_del_super(struct btrfs_fs_info *fs)
 {
+	printk("btrfs_sysfs_del_super\n");
+	
 	kobject_put(&fs->super_kobj);
+	printk("->wait_for_completion(&fs->kobj_unregister)\n");
 	wait_for_completion(&fs->kobj_unregister);
+	printk("<-wait_for_completion(&fs->kobj_unregister)\n");
 }
 
 int btrfs_init_sysfs(void)
 {
-	btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
-	if (!btrfs_kset)
+	printk("start init btrfs-syfs\n");
+	btrfs_kobject = kobject_create_and_add("btrfs", fs_kobj);
+	if (!btrfs_kobject){
+		printk("Not enough memory\n");
+		return -ENOMEM;
+	}
+	btrfs_devices_kset = kset_create_and_add("devices", NULL, btrfs_kobject);
+	if (!btrfs_devices_kset){
+		btrfs_exit_sysfs();
 		return -ENOMEM;
+	}
+	btrfs_fs_kset = kset_create_and_add("filesystems", NULL, btrfs_kobject);
+	if (!btrfs_fs_kset){
+		btrfs_exit_sysfs();
+		return -ENOMEM;
+	}
 	return 0;
 }
 
 void btrfs_exit_sysfs(void)
 {
-	kset_unregister(btrfs_kset);
+	printk("exit sysfs\n");
+	if(btrfs_fs_kset) kset_unregister(btrfs_fs_kset);
+	if(btrfs_devices_kset) kset_unregister(btrfs_devices_kset);
+	if(btrfs_kobject) kobject_put(btrfs_kobject);
+	btrfs_kobject=NULL;
+	btrfs_fs_kset=btrfs_devices_kset=NULL;
 }
 
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index cc04dc1..61f348b 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -31,6 +31,7 @@ 
 #include "print-tree.h"
 #include "volumes.h"
 #include "async-thread.h"
+#include "sysfs.h"
 
 struct map_lookup {
 	u64 type;
@@ -82,6 +83,7 @@  static void free_fs_devices(struct btrfs_fs_devices *fs_devices)
 		device = list_entry(fs_devices->devices.next,
 				    struct btrfs_device, dev_list);
 		list_del(&device->dev_list);
+		btrfs_sysfs_del_device(device);
 		kfree(device->name);
 		kfree(device);
 	}
@@ -412,6 +414,9 @@  static noinline int device_list_add(const char *path,
 
 		device->fs_devices = fs_devices;
 		fs_devices->num_devices++;
+
+		btrfs_sysfs_add_device(device);
+		
 	} else if (strcmp(device->name, path)) {
 		name = kstrdup(path, GFP_NOFS);
 		if (!name)
@@ -468,6 +473,12 @@  static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices 
*orig)
 		list_add(&device->dev_list, &fs_devices->devices);
 		device->fs_devices = fs_devices;
 		fs_devices->num_devices++;
+
+		/* TODO: these code means that may exists two devices with the
+		 * same UUID ?
+		 */
+		btrfs_sysfs_add_device(device);
+		
 	}
 	mutex_unlock(&orig->device_list_mutex);
 	return fs_devices;
@@ -488,6 +499,8 @@  again:
 		if (device->in_fs_metadata)
 			continue;
 
+
+		btrfs_sysfs_del_device(device);
 		if (device->bdev) {
 			close_bdev_exclusive(device->bdev, device->mode);
 			device->bdev = NULL;
@@ -1224,7 +1237,7 @@  int btrfs_rm_device(struct btrfs_root *root, char *device_path)
 		goto error_brelse;
 
 	device->in_fs_metadata = 0;
-
+	btrfs_sysfs_del_device(device);
 	/*
 	 * the device list mutex makes sure that we don't change
 	 * the device list while someone else is writing out all
@@ -1561,6 +1574,7 @@  int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 		ret = btrfs_relocate_sys_chunks(root);
 		BUG_ON(ret);
 	}
+	btrfs_sysfs_add_device(device); /* FIXME: check the error */
 out:
 	mutex_unlock(&root->fs_info->volume_mutex);
 	return ret;
@@ -3084,6 +3098,9 @@  static struct btrfs_device *add_missing_dev(struct btrfs_root *root,
 	spin_lock_init(&device->io_lock);
 	INIT_LIST_HEAD(&device->dev_alloc_list);
 	memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE);
+
+	btrfs_sysfs_add_device(device);
+			
 	return device;
 }
 
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 2b638b6..8e16b7f 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -82,6 +82,10 @@  struct btrfs_device {
 	u8 uuid[BTRFS_UUID_SIZE];
 
 	struct btrfs_work work;
+	
+	/* sysfs stuff */
+	struct kobject	device_kobj;
+	struct completion kobj_unregister;
 };
 
 struct btrfs_fs_devices {