@@ -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);
}
@@ -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;
}
@@ -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;
}
@@ -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 {