From patchwork Mon Nov 8 18:13:35 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Goffredo Baroncelli X-Patchwork-Id: 308902 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oA8I9O0i009539 for ; Mon, 8 Nov 2010 18:09:25 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755240Ab0KHSJV (ORCPT ); Mon, 8 Nov 2010 13:09:21 -0500 Received: from smtp208.alice.it ([82.57.200.104]:38624 "EHLO smtp208.alice.it" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753605Ab0KHSJU (ORCPT ); Mon, 8 Nov 2010 13:09:20 -0500 Received: from venice.localnet (82.59.174.45) by smtp208.alice.it (8.5.124.08) id 4C1A2716099801C5; Mon, 8 Nov 2010 19:09:14 +0100 From: Goffredo Baroncelli Reply-To: kreijack@libero.it To: linux-btrfs@vger.kernel.org Subject: [RFC][PATCH2] exporting info via sysfs Date: Mon, 8 Nov 2010 19:13:35 +0100 User-Agent: KMail/1.13.5 (Linux/2.6.36-trunk-amd64; KDE/4.5.2; x86_64; ; ) Cc: Hugo Mills MIME-Version: 1.0 Message-Id: <201011081913.46171.kreijack@libero.it> Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Mon, 08 Nov 2010 18:09:25 +0000 (UTC) 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;iparam); \ +} \ +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 {