From 248d200df34f3e44a4140f32dfc7428c52615332 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:19 +0800 Subject: [PATCH 01/26] Btrfs: sysfs: fix, btrfs_release_super_kobj() should to clean up the kobject data The following test case fails indicating that, thread tried to init an initialized object. kernel: [232104.016513] kobject (ffff880006c1c980): tried to init an initialized object, something is seriously wrong. btrfs_sysfs_remove_one() self test code: open_tree() { :: ret = btrfs_sysfs_add_one(fs_info); if (ret) { pr_err("BTRFS: failed to init sysfs interface: %d\n", ret); goto fail_block_groups; } + btrfs_sysfs_remove_one(fs_info); + ret = btrfs_sysfs_add_one(fs_info); + if (ret) { + pr_err("BTRFS: failed to init sysfs interface: %d\n", ret); + goto fail_block_groups; + } cleaning up the unregistered kobject fixes this. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index e8a4c86d274d..db2f8aed2b7d 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -439,6 +439,8 @@ static struct attribute *btrfs_attrs[] = { static void btrfs_release_super_kobj(struct kobject *kobj) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); + + memset(&fs_info->super_kobj, 0, sizeof(struct kobject)); complete(&fs_info->kobj_unregister); } From 4e51f005a22a2c7795351b975437b0cee0acce3e Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:20 +0800 Subject: [PATCH 02/26] Btrfs: sysfs: fix, fs_info kobject_unregister has init_completion() twice kobject_unregister is to handle the release of the kobject, its completion init is being called in btrfs_sysfs_add_one(), so we don't have to do the same in the open_ctree() again. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 2ef9a4b72d06..c42503cf3462 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2494,7 +2494,6 @@ int open_ctree(struct super_block *sb, seqlock_init(&fs_info->profiles_lock); init_rwsem(&fs_info->delayed_iput_sem); - init_completion(&fs_info->kobj_unregister); INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); INIT_LIST_HEAD(&fs_info->space_info); INIT_LIST_HEAD(&fs_info->tree_mod_seq_list); From e7e1aa9c913da380fbf1977ac4fa98e464023605 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:21 +0800 Subject: [PATCH 03/26] Btrfs: sysfs: fix, undo sysfs device links Theoritically need to remove the device links attributes, but since its entire device kobject was removed, so there wasn't any issue of about it. Just do it nicely. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index db2f8aed2b7d..ca0786190edd 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -522,6 +522,7 @@ void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) kobject_del(fs_info->space_info_kobj); kobject_put(fs_info->space_info_kobj); } + btrfs_kobj_rm_device(fs_info, NULL); kobject_del(fs_info->device_dir_kobj); kobject_put(fs_info->device_dir_kobj); addrm_unknown_feature_attrs(fs_info, false); @@ -604,6 +605,8 @@ static void init_feature_attrs(void) } } +/* when one_device is NULL, it removes all device links */ + int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info, struct btrfs_device *one_device) { @@ -621,6 +624,20 @@ int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info, disk_kobj->name); } + if (one_device) + return 0; + + list_for_each_entry(one_device, + &fs_info->fs_devices->devices, dev_list) { + if (!one_device->bdev) + continue; + disk = one_device->bdev->bd_part; + disk_kobj = &part_to_dev(disk)->kobj; + + sysfs_remove_link(fs_info->device_dir_kobj, + disk_kobj->name); + } + return 0; } From 8345ea31dc6e1772726d1d0b8864dedac55038e0 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Fri, 20 Mar 2015 18:01:20 +0800 Subject: [PATCH 04/26] Btrfs: sysfs: fix, kobject pointer clean up needed after kobject release The sysfs clean up self test like in the below code fails, since fs_info->device_dir_kobject still points to its stale kobject. Reseting this pointer will help to fix this. open_ctree() { ret = btrfs_sysfs_add_one(fs_info); :: + btrfs_sysfs_remove_one(fs_info); + ret = btrfs_sysfs_add_one(fs_info); + if (ret) { + pr_err("BTRFS: failed to init sysfs interface: %d\n", ret); + goto fail_block_groups; + } Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index ca0786190edd..f31fcec01e9c 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -525,6 +525,7 @@ void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) btrfs_kobj_rm_device(fs_info, NULL); kobject_del(fs_info->device_dir_kobj); kobject_put(fs_info->device_dir_kobj); + fs_info->device_dir_kobj = NULL; addrm_unknown_feature_attrs(fs_info, false); sysfs_remove_group(&fs_info->super_kobj, &btrfs_feature_attr_group); __btrfs_sysfs_remove_one(fs_info); From 4d435731f99db87020730c4b17e1da148908340e Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:23 +0800 Subject: [PATCH 05/26] Btrfc: sysfs: fix, check if device_dir_kobj is init before destroy Since the failure code in the btrfs_sysfs_add_one() can call btrfs_sysfs_remove_one() even before device_dir_kobj has been created we need to check if its null. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index f31fcec01e9c..6218d31a6912 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -522,10 +522,12 @@ void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) kobject_del(fs_info->space_info_kobj); kobject_put(fs_info->space_info_kobj); } - btrfs_kobj_rm_device(fs_info, NULL); - kobject_del(fs_info->device_dir_kobj); - kobject_put(fs_info->device_dir_kobj); - fs_info->device_dir_kobj = NULL; + if (fs_info->device_dir_kobj) { + btrfs_kobj_rm_device(fs_info, NULL); + kobject_del(fs_info->device_dir_kobj); + kobject_put(fs_info->device_dir_kobj); + fs_info->device_dir_kobj = NULL; + } addrm_unknown_feature_attrs(fs_info, false); sysfs_remove_group(&fs_info->super_kobj, &btrfs_feature_attr_group); __btrfs_sysfs_remove_one(fs_info); From aaf13305160490531b0d5ee4d56d32fc09f9bfa0 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:24 +0800 Subject: [PATCH 06/26] Btrfs: sysfs: reorder the kobject creations As of now the order in which the kobjects are created at btrfs_sysfs_add_one() is.. fsid features unknown features (dynamic features) devices. Since we would move fsid and device kobject to fs_devices from fs_info structure, this patch will reorder in which the kobjects are created as below. fsid devices features unknown features (dynamic features) And hence the btrfs_sysfs_remove_one() will follow the same in reverse order. and the device kobject destroy now can be moved into the function __btrfs_sysfs_remove_one() Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 6218d31a6912..8eb2463c973c 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -510,6 +510,13 @@ static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add) static void __btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) { + if (fs_info->device_dir_kobj) { + btrfs_kobj_rm_device(fs_info, NULL); + kobject_del(fs_info->device_dir_kobj); + kobject_put(fs_info->device_dir_kobj); + fs_info->device_dir_kobj = NULL; + } + kobject_del(&fs_info->super_kobj); kobject_put(&fs_info->super_kobj); wait_for_completion(&fs_info->kobj_unregister); @@ -522,12 +529,6 @@ void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) kobject_del(fs_info->space_info_kobj); kobject_put(fs_info->space_info_kobj); } - if (fs_info->device_dir_kobj) { - btrfs_kobj_rm_device(fs_info, NULL); - kobject_del(fs_info->device_dir_kobj); - kobject_put(fs_info->device_dir_kobj); - fs_info->device_dir_kobj = NULL; - } addrm_unknown_feature_attrs(fs_info, false); sysfs_remove_group(&fs_info->super_kobj, &btrfs_feature_attr_group); __btrfs_sysfs_remove_one(fs_info); @@ -700,6 +701,12 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) if (error) return error; + error = btrfs_kobj_add_device(fs_info, NULL); + if (error) { + __btrfs_sysfs_remove_one(fs_info); + return error; + } + error = sysfs_create_group(&fs_info->super_kobj, &btrfs_feature_attr_group); if (error) { @@ -711,10 +718,6 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) if (error) goto failure; - error = btrfs_kobj_add_device(fs_info, NULL); - if (error) - goto failure; - fs_info->space_info_kobj = kobject_create_and_add("allocation", &fs_info->super_kobj); if (!fs_info->space_info_kobj) { From 3a08f3b72a4f03e413d89d8505b17c05194e63f9 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:25 +0800 Subject: [PATCH 07/26] Btrfs: sysfs: rename __btrfs_sysfs_remove_one to btrfs_sysfs_remove_fsid Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 8eb2463c973c..8b6eff48268a 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -508,7 +508,7 @@ static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add) return 0; } -static void __btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) +static void btrfs_sysfs_remove_fsid(struct btrfs_fs_info *fs_info) { if (fs_info->device_dir_kobj) { btrfs_kobj_rm_device(fs_info, NULL); @@ -531,7 +531,7 @@ void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) } addrm_unknown_feature_attrs(fs_info, false); sysfs_remove_group(&fs_info->super_kobj, &btrfs_feature_attr_group); - __btrfs_sysfs_remove_one(fs_info); + btrfs_sysfs_remove_fsid(fs_info); } const char * const btrfs_feature_set_names[3] = { @@ -703,14 +703,14 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) error = btrfs_kobj_add_device(fs_info, NULL); if (error) { - __btrfs_sysfs_remove_one(fs_info); + btrfs_sysfs_remove_fsid(fs_info); return error; } error = sysfs_create_group(&fs_info->super_kobj, &btrfs_feature_attr_group); if (error) { - __btrfs_sysfs_remove_one(fs_info); + btrfs_sysfs_remove_fsid(fs_info); return error; } From 720592157eeef627ff9a7c7c55ab1713bc48fb50 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:26 +0800 Subject: [PATCH 08/26] Btrfs: sysfs: introduce function btrfs_sysfs_add_fsid() to create sysfs fsid We need it in a seperate function so that it can be called from the device discovery thread as well. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 8b6eff48268a..83c0c5d5368b 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -690,7 +690,12 @@ static struct dentry *btrfs_debugfs_root_dentry; /* Debugging tunables and exported data */ u64 btrfs_debugfs_test; -int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) +/* + * Can be called by the device discovery thread. + * And parent can be specified for seed device + */ +int btrfs_sysfs_add_fsid(struct btrfs_fs_info *fs_info, + struct kobject *parent) { int error; @@ -698,6 +703,14 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) fs_info->super_kobj.kset = btrfs_kset; error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL, "%pU", fs_info->fsid); + return error; +} + +int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) +{ + int error; + + error = btrfs_sysfs_add_fsid(fs_info, NULL); if (error) return error; From 0dd2906f7229186424cdc80be8654b2c21d9c04c Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:27 +0800 Subject: [PATCH 09/26] Btrfs: sysfs: let default_attrs be separate from the kset As of now btrfs_attrs are provided using the default_attrs through the kset. Separate them and create the default_attrs using the sysfs_create_files instead. By doing this we will have the flexibility that device discovery thread could create fsid kobject. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 83c0c5d5368b..11fa8e6c533c 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -428,7 +428,7 @@ static ssize_t btrfs_clone_alignment_show(struct kobject *kobj, BTRFS_ATTR(clone_alignment, btrfs_clone_alignment_show); -static struct attribute *btrfs_attrs[] = { +static const struct attribute *btrfs_attrs[] = { BTRFS_ATTR_PTR(label), BTRFS_ATTR_PTR(nodesize), BTRFS_ATTR_PTR(sectorsize), @@ -447,7 +447,6 @@ static void btrfs_release_super_kobj(struct kobject *kobj) static struct kobj_type btrfs_ktype = { .sysfs_ops = &kobj_sysfs_ops, .release = btrfs_release_super_kobj, - .default_attrs = btrfs_attrs, }; static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj) @@ -531,6 +530,7 @@ void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) } addrm_unknown_feature_attrs(fs_info, false); sysfs_remove_group(&fs_info->super_kobj, &btrfs_feature_attr_group); + sysfs_remove_files(&fs_info->super_kobj, btrfs_attrs); btrfs_sysfs_remove_fsid(fs_info); } @@ -720,13 +720,17 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) return error; } - error = sysfs_create_group(&fs_info->super_kobj, - &btrfs_feature_attr_group); + error = sysfs_create_files(&fs_info->super_kobj, btrfs_attrs); if (error) { btrfs_sysfs_remove_fsid(fs_info); return error; } + error = sysfs_create_group(&fs_info->super_kobj, + &btrfs_feature_attr_group); + if (error) + goto failure; + error = addrm_unknown_feature_attrs(fs_info, true); if (error) goto failure; From 00c921c23f9155597ff4ac1263a6ff46dc9e2206 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:28 +0800 Subject: [PATCH 10/26] Btrfs: sysfs: separate device kobject and its attribute creation Separate device kobject and its attribute creation so that device kobject can be created from the device discovery thread. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 11fa8e6c533c..e71da324104a 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -645,6 +645,18 @@ int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info, return 0; } +int btrfs_sysfs_add_device(struct btrfs_fs_info *fs_info) +{ + if (!fs_info->device_dir_kobj) + fs_info->device_dir_kobj = kobject_create_and_add("devices", + &fs_info->super_kobj); + + if (!fs_info->device_dir_kobj) + return -ENOMEM; + + return 0; +} + int btrfs_kobj_add_device(struct btrfs_fs_info *fs_info, struct btrfs_device *one_device) { @@ -652,12 +664,9 @@ int btrfs_kobj_add_device(struct btrfs_fs_info *fs_info, struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; struct btrfs_device *dev; - if (!fs_info->device_dir_kobj) - fs_info->device_dir_kobj = kobject_create_and_add("devices", - &fs_info->super_kobj); - - if (!fs_info->device_dir_kobj) - return -ENOMEM; + error = btrfs_sysfs_add_device(fs_info); + if (error) + return error; list_for_each_entry(dev, &fs_devices->devices, dev_list) { struct hd_struct *disk; From 2e7910d6ca359ff1dbe05b74e3d7f353b5b65362 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:29 +0800 Subject: [PATCH 11/26] Btrfs: sysfs: move super_kobj and device_dir_kobj from fs_info to btrfs_fs_devices This patch will provide a framework and help to create attributes from the structure btrfs_fs_devices which are available even before fs_info is created. So by moving the parent kobject super_kobj from fs_info to btrfs_fs_devices, it will help to create attributes from the btrfs_fs_devices as well. Patches on top of this patch now will be able to create the sys/fs/btrfs/fsid kobject and attributes from btrfs_fs_devices when devices are scanned and registered to the kernel. Just to note, this does not change any of the existing btrfs sysfs external kobject names and its attributes and not even the life cycle of them. Changes are internal only. And to ensure the same, this path has been tested with various device operations and, checking and comparing the sysfs kobjects and attributes with sysfs kobject and attributes with out this patch, and they remain same. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 3 -- fs/btrfs/sysfs.c | 88 ++++++++++++++++++++++++++-------------------- fs/btrfs/volumes.c | 3 +- fs/btrfs/volumes.h | 5 +++ 4 files changed, 56 insertions(+), 43 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 6f364e1d8d3d..3335245f2636 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1619,10 +1619,7 @@ struct btrfs_fs_info { struct task_struct *cleaner_kthread; int thread_pool_size; - struct kobject super_kobj; struct kobject *space_info_kobj; - struct kobject *device_dir_kobj; - struct completion kobj_unregister; int do_barriers; int closing; int log_root_recovering; diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index e71da324104a..f045c568b360 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -33,6 +33,7 @@ #include "volumes.h" static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj); +static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj); static u64 get_features(struct btrfs_fs_info *fs_info, enum btrfs_feature_set set) @@ -438,10 +439,10 @@ static const struct attribute *btrfs_attrs[] = { static void btrfs_release_super_kobj(struct kobject *kobj) { - struct btrfs_fs_info *fs_info = to_fs_info(kobj); + struct btrfs_fs_devices *fs_devs = to_fs_devs(kobj); - memset(&fs_info->super_kobj, 0, sizeof(struct kobject)); - complete(&fs_info->kobj_unregister); + memset(&fs_devs->super_kobj, 0, sizeof(struct kobject)); + complete(&fs_devs->kobj_unregister); } static struct kobj_type btrfs_ktype = { @@ -449,11 +450,18 @@ static struct kobj_type btrfs_ktype = { .release = btrfs_release_super_kobj, }; +static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj) +{ + if (kobj->ktype != &btrfs_ktype) + return NULL; + return container_of(kobj, struct btrfs_fs_devices, super_kobj); +} + static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj) { if (kobj->ktype != &btrfs_ktype) return NULL; - return container_of(kobj, struct btrfs_fs_info, super_kobj); + return to_fs_devs(kobj)->fs_info; } #define NUM_FEATURE_BITS 64 @@ -494,12 +502,12 @@ static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add) attrs[0] = &fa->kobj_attr.attr; if (add) { int ret; - ret = sysfs_merge_group(&fs_info->super_kobj, + ret = sysfs_merge_group(&fs_info->fs_devices->super_kobj, &agroup); if (ret) return ret; } else - sysfs_unmerge_group(&fs_info->super_kobj, + sysfs_unmerge_group(&fs_info->fs_devices->super_kobj, &agroup); } @@ -507,18 +515,17 @@ static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add) return 0; } -static void btrfs_sysfs_remove_fsid(struct btrfs_fs_info *fs_info) +static void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) { - if (fs_info->device_dir_kobj) { - btrfs_kobj_rm_device(fs_info, NULL); - kobject_del(fs_info->device_dir_kobj); - kobject_put(fs_info->device_dir_kobj); - fs_info->device_dir_kobj = NULL; + if (fs_devs->device_dir_kobj) { + kobject_del(fs_devs->device_dir_kobj); + kobject_put(fs_devs->device_dir_kobj); + fs_devs->device_dir_kobj = NULL; } - kobject_del(&fs_info->super_kobj); - kobject_put(&fs_info->super_kobj); - wait_for_completion(&fs_info->kobj_unregister); + kobject_del(&fs_devs->super_kobj); + kobject_put(&fs_devs->super_kobj); + wait_for_completion(&fs_devs->kobj_unregister); } void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) @@ -529,9 +536,10 @@ void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) kobject_put(fs_info->space_info_kobj); } addrm_unknown_feature_attrs(fs_info, false); - sysfs_remove_group(&fs_info->super_kobj, &btrfs_feature_attr_group); - sysfs_remove_files(&fs_info->super_kobj, btrfs_attrs); - btrfs_sysfs_remove_fsid(fs_info); + sysfs_remove_group(&fs_info->fs_devices->super_kobj, &btrfs_feature_attr_group); + sysfs_remove_files(&fs_info->fs_devices->super_kobj, btrfs_attrs); + btrfs_kobj_rm_device(fs_info, NULL); + btrfs_sysfs_remove_fsid(fs_info->fs_devices); } const char * const btrfs_feature_set_names[3] = { @@ -617,14 +625,14 @@ int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info, struct hd_struct *disk; struct kobject *disk_kobj; - if (!fs_info->device_dir_kobj) + if (!fs_info->fs_devices->device_dir_kobj) return -EINVAL; if (one_device && one_device->bdev) { disk = one_device->bdev->bd_part; disk_kobj = &part_to_dev(disk)->kobj; - sysfs_remove_link(fs_info->device_dir_kobj, + sysfs_remove_link(fs_info->fs_devices->device_dir_kobj, disk_kobj->name); } @@ -638,20 +646,20 @@ int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info, disk = one_device->bdev->bd_part; disk_kobj = &part_to_dev(disk)->kobj; - sysfs_remove_link(fs_info->device_dir_kobj, + sysfs_remove_link(fs_info->fs_devices->device_dir_kobj, disk_kobj->name); } return 0; } -int btrfs_sysfs_add_device(struct btrfs_fs_info *fs_info) +int btrfs_sysfs_add_device(struct btrfs_fs_devices *fs_devs) { - if (!fs_info->device_dir_kobj) - fs_info->device_dir_kobj = kobject_create_and_add("devices", - &fs_info->super_kobj); + if (!fs_devs->device_dir_kobj) + fs_devs->device_dir_kobj = kobject_create_and_add("devices", + &fs_devs->super_kobj); - if (!fs_info->device_dir_kobj) + if (!fs_devs->device_dir_kobj) return -ENOMEM; return 0; @@ -664,7 +672,7 @@ int btrfs_kobj_add_device(struct btrfs_fs_info *fs_info, struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; struct btrfs_device *dev; - error = btrfs_sysfs_add_device(fs_info); + error = btrfs_sysfs_add_device(fs_devices); if (error) return error; @@ -681,7 +689,7 @@ int btrfs_kobj_add_device(struct btrfs_fs_info *fs_info, disk = dev->bdev->bd_part; disk_kobj = &part_to_dev(disk)->kobj; - error = sysfs_create_link(fs_info->device_dir_kobj, + error = sysfs_create_link(fs_devices->device_dir_kobj, disk_kobj, disk_kobj->name); if (error) break; @@ -703,39 +711,41 @@ u64 btrfs_debugfs_test; * Can be called by the device discovery thread. * And parent can be specified for seed device */ -int btrfs_sysfs_add_fsid(struct btrfs_fs_info *fs_info, +static int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs, struct kobject *parent) { int error; - init_completion(&fs_info->kobj_unregister); - fs_info->super_kobj.kset = btrfs_kset; - error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL, - "%pU", fs_info->fsid); + init_completion(&fs_devs->kobj_unregister); + fs_devs->super_kobj.kset = btrfs_kset; + error = kobject_init_and_add(&fs_devs->super_kobj, &btrfs_ktype, NULL, + "%pU", fs_devs->fsid); return error; } int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) { int error; + struct btrfs_fs_devices *fs_devs = fs_info->fs_devices; + struct kobject *super_kobj = &fs_devs->super_kobj; - error = btrfs_sysfs_add_fsid(fs_info, NULL); + error = btrfs_sysfs_add_fsid(fs_devs, NULL); if (error) return error; error = btrfs_kobj_add_device(fs_info, NULL); if (error) { - btrfs_sysfs_remove_fsid(fs_info); + btrfs_sysfs_remove_fsid(fs_devs); return error; } - error = sysfs_create_files(&fs_info->super_kobj, btrfs_attrs); + error = sysfs_create_files(super_kobj, btrfs_attrs); if (error) { - btrfs_sysfs_remove_fsid(fs_info); + btrfs_sysfs_remove_fsid(fs_devs); return error; } - error = sysfs_create_group(&fs_info->super_kobj, + error = sysfs_create_group(super_kobj, &btrfs_feature_attr_group); if (error) goto failure; @@ -745,7 +755,7 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) goto failure; fs_info->space_info_kobj = kobject_create_and_add("allocation", - &fs_info->super_kobj); + super_kobj); if (!fs_info->space_info_kobj) { error = -ENOMEM; goto failure; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 174f5e1e00ab..39ff99e4b5a6 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2252,7 +2252,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) */ snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU", root->fs_info->fsid); - if (kobject_rename(&root->fs_info->super_kobj, fsid_buf)) + if (kobject_rename(&root->fs_info->fs_devices->super_kobj, + fsid_buf)) goto error_trans; } diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index ebc31331a837..e9780e9e6d97 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -253,6 +253,11 @@ struct btrfs_fs_devices { * nonrot flag set */ int rotating; + + /* sysfs kobjects */ + struct kobject super_kobj; + struct kobject *device_dir_kobj; + struct completion kobj_unregister; }; #define BTRFS_BIO_INLINE_CSUM_SIZE 64 From c73eccf75bf92e49be30884da32a169b04eb5bc9 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:30 +0800 Subject: [PATCH 12/26] Btrfs: introduce btrfs_get_fs_uuids to get fs_uuids Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 4 ++++ fs/btrfs/volumes.h | 1 + 2 files changed, 5 insertions(+) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 39ff99e4b5a6..e500bfa54dc9 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -52,6 +52,10 @@ static void btrfs_dev_stat_print_on_load(struct btrfs_device *device); DEFINE_MUTEX(uuid_mutex); static LIST_HEAD(fs_uuids); +struct list_head *btrfs_get_fs_uuids(void) +{ + return &fs_uuids; +} static struct btrfs_fs_devices *__alloc_fs_devices(void) { diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index e9780e9e6d97..ac7e938c6977 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -542,5 +542,6 @@ static inline void unlock_chunks(struct btrfs_root *root) mutex_unlock(&root->fs_info->chunk_mutex); } +struct list_head *btrfs_get_fs_uuids(void); #endif From 5a13f4308c5b4af28c01ca9cacdd8a6db777dfcb Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:31 +0800 Subject: [PATCH 13/26] Btrfs: sysfs: add pointer to access fs_info from fs_devices adds fs_info pointer with struct btrfs_fs_devices. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 4 ++++ fs/btrfs/volumes.c | 18 ++++++++++++++++++ fs/btrfs/volumes.h | 3 +++ 3 files changed, 25 insertions(+) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index f045c568b360..4b9a8df3faea 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -530,6 +530,8 @@ static void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) { + btrfs_reset_fs_info_ptr(fs_info); + if (fs_info->space_info_kobj) { sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs); kobject_del(fs_info->space_info_kobj); @@ -729,6 +731,8 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) struct btrfs_fs_devices *fs_devs = fs_info->fs_devices; struct kobject *super_kobj = &fs_devs->super_kobj; + btrfs_set_fs_info_ptr(fs_info); + error = btrfs_sysfs_add_fsid(fs_devs, NULL); if (error) return error; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index e500bfa54dc9..5719470b50cd 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6733,3 +6733,21 @@ void btrfs_update_commit_device_bytes_used(struct btrfs_root *root, } unlock_chunks(root); } + +void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info) +{ + struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; + while (fs_devices) { + fs_devices->fs_info = fs_info; + fs_devices = fs_devices->seed; + } +} + +void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info) +{ + struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; + while (fs_devices) { + fs_devices->fs_info = NULL; + fs_devices = fs_devices->seed; + } +} diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index ac7e938c6977..210a64390f40 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -254,6 +254,7 @@ struct btrfs_fs_devices { */ int rotating; + struct btrfs_fs_info *fs_info; /* sysfs kobjects */ struct kobject super_kobj; struct kobject *device_dir_kobj; @@ -543,5 +544,7 @@ static inline void unlock_chunks(struct btrfs_root *root) } struct list_head *btrfs_get_fs_uuids(void); +void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info); +void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info); #endif From 2e3e12815a296f263261b17b3a5781cbd517f7f3 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:32 +0800 Subject: [PATCH 14/26] Btrfs: sysfs: provide framework to remove all fsid sysfs kobject Just a helper function to clean up the sysfs fsid kobjects. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 4b9a8df3faea..333ed0840907 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -515,7 +515,7 @@ static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add) return 0; } -static void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) +static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) { if (fs_devs->device_dir_kobj) { kobject_del(fs_devs->device_dir_kobj); @@ -528,6 +528,21 @@ static void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) wait_for_completion(&fs_devs->kobj_unregister); } +/* when fs_devs is NULL it will remove all fsid kobject */ +static void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) +{ + struct list_head *fs_uuids = btrfs_get_fs_uuids(); + + if (fs_devs) { + __btrfs_sysfs_remove_fsid(fs_devs); + return; + } + + list_for_each_entry(fs_devs, fs_uuids, list) { + __btrfs_sysfs_remove_fsid(fs_devs); + } +} + void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) { btrfs_reset_fs_info_ptr(fs_info); From 1ba43816af921219d596c462baa7674ff0228229 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:33 +0800 Subject: [PATCH 15/26] Btrfs: sysfs btrfs_kobj_add_device() pass fs_devices instead of fs_info btrfs_kobj_add_device() does not need fs_info any more. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 2 +- fs/btrfs/sysfs.c | 7 +++---- fs/btrfs/sysfs.h | 2 +- fs/btrfs/volumes.c | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 0573848c7333..72c03adb6562 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -584,7 +584,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, /* replace the sysfs entry */ btrfs_kobj_rm_device(fs_info, src_device); - btrfs_kobj_add_device(fs_info, tgt_device); + btrfs_kobj_add_device(fs_info->fs_devices, tgt_device); btrfs_rm_dev_replace_free_srcdev(fs_info, src_device); /* write back the superblocks */ diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 333ed0840907..82e18f532958 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -682,11 +682,10 @@ int btrfs_sysfs_add_device(struct btrfs_fs_devices *fs_devs) return 0; } -int btrfs_kobj_add_device(struct btrfs_fs_info *fs_info, - struct btrfs_device *one_device) +int btrfs_kobj_add_device(struct btrfs_fs_devices *fs_devices, + struct btrfs_device *one_device) { int error = 0; - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; struct btrfs_device *dev; error = btrfs_sysfs_add_device(fs_devices); @@ -752,7 +751,7 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) if (error) return error; - error = btrfs_kobj_add_device(fs_info, NULL); + error = btrfs_kobj_add_device(fs_devs, NULL); if (error) { btrfs_sysfs_remove_fsid(fs_devs); return error; diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h index 3a4bbed723fd..f1d7c7604f6f 100644 --- a/fs/btrfs/sysfs.h +++ b/fs/btrfs/sysfs.h @@ -82,7 +82,7 @@ char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags); extern const char * const btrfs_feature_set_names[3]; extern struct kobj_type space_info_ktype; extern struct kobj_type btrfs_raid_ktype; -int btrfs_kobj_add_device(struct btrfs_fs_info *fs_info, +int btrfs_kobj_add_device(struct btrfs_fs_devices *fs_devices, struct btrfs_device *one_device); int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info, struct btrfs_device *one_device); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5719470b50cd..d68d3944af4b 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2215,7 +2215,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) tmp + 1); /* add sysfs device entry */ - btrfs_kobj_add_device(root->fs_info, device); + btrfs_kobj_add_device(root->fs_info->fs_devices, device); /* * we've got more storage, clear any full flags on the space From 6c14a1641bfaa213bb3c5bcb7f4d8cde234ada70 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:34 +0800 Subject: [PATCH 16/26] Btrfs: sysfs btrfs_kobj_rm_device() pass fs_devices instead of fs_info since btrfs_kobj_rm_device() does nothing with fs_info Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 2 +- fs/btrfs/sysfs.c | 12 ++++++------ fs/btrfs/sysfs.h | 2 +- fs/btrfs/volumes.c | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 72c03adb6562..f982ef303f1c 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -583,7 +583,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, mutex_unlock(&uuid_mutex); /* replace the sysfs entry */ - btrfs_kobj_rm_device(fs_info, src_device); + btrfs_kobj_rm_device(fs_info->fs_devices, src_device); btrfs_kobj_add_device(fs_info->fs_devices, tgt_device); btrfs_rm_dev_replace_free_srcdev(fs_info, src_device); diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 82e18f532958..0a5d1eebc27e 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -555,7 +555,7 @@ void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) addrm_unknown_feature_attrs(fs_info, false); sysfs_remove_group(&fs_info->fs_devices->super_kobj, &btrfs_feature_attr_group); sysfs_remove_files(&fs_info->fs_devices->super_kobj, btrfs_attrs); - btrfs_kobj_rm_device(fs_info, NULL); + btrfs_kobj_rm_device(fs_info->fs_devices, NULL); btrfs_sysfs_remove_fsid(fs_info->fs_devices); } @@ -636,20 +636,20 @@ static void init_feature_attrs(void) /* when one_device is NULL, it removes all device links */ -int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info, +int btrfs_kobj_rm_device(struct btrfs_fs_devices *fs_devices, struct btrfs_device *one_device) { struct hd_struct *disk; struct kobject *disk_kobj; - if (!fs_info->fs_devices->device_dir_kobj) + if (!fs_devices->device_dir_kobj) return -EINVAL; if (one_device && one_device->bdev) { disk = one_device->bdev->bd_part; disk_kobj = &part_to_dev(disk)->kobj; - sysfs_remove_link(fs_info->fs_devices->device_dir_kobj, + sysfs_remove_link(fs_devices->device_dir_kobj, disk_kobj->name); } @@ -657,13 +657,13 @@ int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info, return 0; list_for_each_entry(one_device, - &fs_info->fs_devices->devices, dev_list) { + &fs_devices->devices, dev_list) { if (!one_device->bdev) continue; disk = one_device->bdev->bd_part; disk_kobj = &part_to_dev(disk)->kobj; - sysfs_remove_link(fs_info->fs_devices->device_dir_kobj, + sysfs_remove_link(fs_devices->device_dir_kobj, disk_kobj->name); } diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h index f1d7c7604f6f..808d12ac4a5a 100644 --- a/fs/btrfs/sysfs.h +++ b/fs/btrfs/sysfs.h @@ -84,6 +84,6 @@ extern struct kobj_type space_info_ktype; extern struct kobj_type btrfs_raid_ktype; int btrfs_kobj_add_device(struct btrfs_fs_devices *fs_devices, struct btrfs_device *one_device); -int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info, +int btrfs_kobj_rm_device(struct btrfs_fs_devices *fs_devices, struct btrfs_device *one_device); #endif /* _BTRFS_SYSFS_H_ */ diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d68d3944af4b..b5cc129bfa4b 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1710,7 +1710,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) if (device->bdev) { device->fs_devices->open_devices--; /* remove sysfs entry */ - btrfs_kobj_rm_device(root->fs_info, device); + btrfs_kobj_rm_device(root->fs_info->fs_devices, device); } call_rcu(&device->rcu, free_device); @@ -2294,7 +2294,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) error_trans: btrfs_end_transaction(trans, root); rcu_string_free(device->name); - btrfs_kobj_rm_device(root->fs_info, device); + btrfs_kobj_rm_device(root->fs_info->fs_devices, device); kfree(device); error: blkdev_put(bdev, FMODE_EXCL); From 0c10e2d482ba7eafb9806f3ee071c8af5afcde55 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:35 +0800 Subject: [PATCH 17/26] Btrfs: sysfs: make btrfs_sysfs_add_fsid() non static Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 2 +- fs/btrfs/sysfs.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 0a5d1eebc27e..53a327ba75da 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -727,7 +727,7 @@ u64 btrfs_debugfs_test; * Can be called by the device discovery thread. * And parent can be specified for seed device */ -static int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs, +int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs, struct kobject *parent) { int error; diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h index 808d12ac4a5a..4edf2a7839ad 100644 --- a/fs/btrfs/sysfs.h +++ b/fs/btrfs/sysfs.h @@ -86,4 +86,6 @@ int btrfs_kobj_add_device(struct btrfs_fs_devices *fs_devices, struct btrfs_device *one_device); int btrfs_kobj_rm_device(struct btrfs_fs_devices *fs_devices, struct btrfs_device *one_device); +int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs, + struct kobject *parent); #endif /* _BTRFS_SYSFS_H_ */ From ef1a0daadf2b722fc1bb6c2d5cf39239591e78ec Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:36 +0800 Subject: [PATCH 18/26] Btrfs: sysfs: make btrfs_sysfs_add_device() non static Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h index 4edf2a7839ad..915307ff1a76 100644 --- a/fs/btrfs/sysfs.h +++ b/fs/btrfs/sysfs.h @@ -88,4 +88,5 @@ int btrfs_kobj_rm_device(struct btrfs_fs_devices *fs_devices, struct btrfs_device *one_device); int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs, struct kobject *parent); +int btrfs_sysfs_add_device(struct btrfs_fs_devices *fs_devs); #endif /* _BTRFS_SYSFS_H_ */ From 1d1c1be3720c1f4b621c5f90a4f61bdd856a0aa8 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:37 +0800 Subject: [PATCH 19/26] Btrfs: sysfs: btrfs_sysfs_remove_fsid() make it non static Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 2 +- fs/btrfs/sysfs.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 53a327ba75da..06eae456612f 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -529,7 +529,7 @@ static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) } /* when fs_devs is NULL it will remove all fsid kobject */ -static void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) +void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) { struct list_head *fs_uuids = btrfs_get_fs_uuids(); diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h index 915307ff1a76..6392527bcc15 100644 --- a/fs/btrfs/sysfs.h +++ b/fs/btrfs/sysfs.h @@ -89,4 +89,5 @@ int btrfs_kobj_rm_device(struct btrfs_fs_devices *fs_devices, int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs, struct kobject *parent); int btrfs_sysfs_add_device(struct btrfs_fs_devices *fs_devs); +void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs); #endif /* _BTRFS_SYSFS_H_ */ From b7c35e81adcd593daca2160b5ba0ec62f71a9303 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:38 +0800 Subject: [PATCH 20/26] Btrfs: sysfs: separate kobject and attribute creation Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 18 +++++++++++++++++- fs/btrfs/sysfs.c | 15 ++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c42503cf3462..d29a2515f1e8 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2873,10 +2873,22 @@ int open_ctree(struct super_block *sb, btrfs_close_extra_devices(fs_devices, 1); + ret = btrfs_sysfs_add_fsid(fs_devices, NULL); + if (ret) { + pr_err("BTRFS: failed to init sysfs fsid interface: %d\n", ret); + goto fail_block_groups; + } + + ret = btrfs_sysfs_add_device(fs_devices); + if (ret) { + pr_err("BTRFS: failed to init sysfs device interface: %d\n", ret); + goto fail_fsdev_sysfs; + } + ret = btrfs_sysfs_add_one(fs_info); if (ret) { pr_err("BTRFS: failed to init sysfs interface: %d\n", ret); - goto fail_block_groups; + goto fail_fsdev_sysfs; } ret = btrfs_init_space_info(fs_info); @@ -3054,6 +3066,9 @@ int open_ctree(struct super_block *sb, fail_sysfs: btrfs_sysfs_remove_one(fs_info); +fail_fsdev_sysfs: + btrfs_sysfs_remove_fsid(fs_info->fs_devices); + fail_block_groups: btrfs_put_block_group_cache(fs_info); btrfs_free_block_groups(fs_info); @@ -3731,6 +3746,7 @@ void close_ctree(struct btrfs_root *root) } btrfs_sysfs_remove_one(fs_info); + btrfs_sysfs_remove_fsid(fs_info->fs_devices); btrfs_free_fs_roots(fs_info); diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 06eae456612f..b35366c88d3d 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -556,7 +556,6 @@ void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) sysfs_remove_group(&fs_info->fs_devices->super_kobj, &btrfs_feature_attr_group); sysfs_remove_files(&fs_info->fs_devices->super_kobj, btrfs_attrs); btrfs_kobj_rm_device(fs_info->fs_devices, NULL); - btrfs_sysfs_remove_fsid(fs_info->fs_devices); } const char * const btrfs_feature_set_names[3] = { @@ -688,10 +687,6 @@ int btrfs_kobj_add_device(struct btrfs_fs_devices *fs_devices, int error = 0; struct btrfs_device *dev; - error = btrfs_sysfs_add_device(fs_devices); - if (error) - return error; - list_for_each_entry(dev, &fs_devices->devices, dev_list) { struct hd_struct *disk; struct kobject *disk_kobj; @@ -747,19 +742,13 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) btrfs_set_fs_info_ptr(fs_info); - error = btrfs_sysfs_add_fsid(fs_devs, NULL); + error = btrfs_kobj_add_device(fs_devs, NULL); if (error) return error; - error = btrfs_kobj_add_device(fs_devs, NULL); - if (error) { - btrfs_sysfs_remove_fsid(fs_devs); - return error; - } - error = sysfs_create_files(super_kobj, btrfs_attrs); if (error) { - btrfs_sysfs_remove_fsid(fs_devs); + btrfs_kobj_rm_device(fs_devs, NULL); return error; } From 24bd69cb0fb2d90f4ced5f6acfee3688b33bcbdd Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:39 +0800 Subject: [PATCH 21/26] Btrfs: sysfs: add support to add parent for fsid To support seed sysfs layout and represent seed fsid under the sprout we need the facility to create fsid under the specified parent. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index b35366c88d3d..ea81a057c79b 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -729,8 +729,8 @@ int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs, init_completion(&fs_devs->kobj_unregister); fs_devs->super_kobj.kset = btrfs_kset; - error = kobject_init_and_add(&fs_devs->super_kobj, &btrfs_ktype, NULL, - "%pU", fs_devs->fsid); + error = kobject_init_and_add(&fs_devs->super_kobj, + &btrfs_ktype, parent, "%pU", fs_devs->fsid); return error; } From 2421a8cd5faaa9c2c9397123c5a297bab227d965 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:40 +0800 Subject: [PATCH 22/26] Btrfs: sysfs: don't fail seeding for the sake of sysfs kobject issue Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index b5cc129bfa4b..b851964b7345 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2258,7 +2258,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) root->fs_info->fsid); if (kobject_rename(&root->fs_info->fs_devices->super_kobj, fsid_buf)) - goto error_trans; + pr_warn("BTRFS: sysfs: failed to create fsid for sprout\n"); } root->fs_info->num_tolerated_disk_barrier_failures = From 4fde46f0cc71c7aba299ee6dfb4f017fb97b6e70 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Wed, 17 Jun 2015 21:10:48 +0800 Subject: [PATCH 23/26] Btrfs: free the stale device When btrfs on a device is overwritten with a new btrfs (mkfs), the old btrfs instance in the kernel becomes stale. So with this patch, if kernel finds device is overwritten then delete the stale fsid/uuid. Signed-off-by: Anand Jain --- fs/btrfs/volumes.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index b851964b7345..ea293db89cc4 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -445,6 +445,61 @@ static void pending_bios_fn(struct btrfs_work *work) run_scheduled_bios(device); } + +void btrfs_free_stale_device(struct btrfs_device *cur_dev) +{ + struct btrfs_fs_devices *fs_devs; + struct btrfs_device *dev; + + if (!cur_dev->name) + return; + + list_for_each_entry(fs_devs, &fs_uuids, list) { + int del = 1; + + if (fs_devs->opened) + continue; + if (fs_devs->seeding) + continue; + + list_for_each_entry(dev, &fs_devs->devices, dev_list) { + + if (dev == cur_dev) + continue; + if (!dev->name) + continue; + + /* + * Todo: This won't be enough. What if the same device + * comes back (with new uuid and) with its mapper path? + * But for now, this does help as mostly an admin will + * either use mapper or non mapper path throughout. + */ + rcu_read_lock(); + del = strcmp(rcu_str_deref(dev->name), + rcu_str_deref(cur_dev->name)); + rcu_read_unlock(); + if (!del) + break; + } + + if (!del) { + /* delete the stale device */ + if (fs_devs->num_devices == 1) { + btrfs_sysfs_remove_fsid(fs_devs); + list_del(&fs_devs->list); + free_fs_devices(fs_devs); + } else { + fs_devs->num_devices--; + list_del(&dev->dev_list); + rcu_string_free(dev->name); + kfree(dev); + } + break; + } + } +} + /* * Add new device to list of registered devices * @@ -560,6 +615,12 @@ static noinline int device_list_add(const char *path, if (!fs_devices->opened) device->generation = found_transid; + /* + * if there is new btrfs on an already registered device, + * then remove the stale device entry. + */ + btrfs_free_stale_device(device); + *fs_devices_ret = fs_devices; return ret; From d2ff1b2008cb807102fc9496fadd8eddff98350c Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 10 Mar 2015 06:38:42 +0800 Subject: [PATCH 24/26] Btrfs: sysfs: add support to show replacing target in the sysfs This patch will add support to show the replacing target in sysfs during the process of replacement. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 5 ++++- fs/btrfs/volumes.c | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index f982ef303f1c..862fbc206755 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -376,6 +376,10 @@ int btrfs_dev_replace_start(struct btrfs_root *root, WARN_ON(!tgt_device); dev_replace->tgtdev = tgt_device; + ret = btrfs_kobj_add_device(tgt_device->fs_devices, tgt_device); + if (ret) + btrfs_error(root->fs_info, ret, "kobj add dev failed"); + printk_in_rcu(KERN_INFO "BTRFS: dev_replace from %s (devid %llu) to %s started\n", src_device->missing ? "" : @@ -584,7 +588,6 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, /* replace the sysfs entry */ btrfs_kobj_rm_device(fs_info->fs_devices, src_device); - btrfs_kobj_add_device(fs_info->fs_devices, tgt_device); btrfs_rm_dev_replace_free_srcdev(fs_info, src_device); /* write back the superblocks */ diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index ea293db89cc4..2d9061f078ca 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1940,6 +1940,9 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, mutex_lock(&uuid_mutex); WARN_ON(!tgtdev); mutex_lock(&fs_info->fs_devices->device_list_mutex); + + btrfs_kobj_rm_device(fs_info->fs_devices, tgtdev); + if (tgtdev->bdev) { btrfs_scratch_superblock(tgtdev); fs_info->fs_devices->open_devices--; From 24199d206a739a77edc3ff6c429b68b7bd6b2ef8 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Thu, 12 Feb 2015 07:03:37 +0800 Subject: [PATCH 25/26] lib: export symbol kobject_move() drivers/cpufreq/cpufreq.c is already using this function. And now btrfs needs it as well. Export symbol kobject_move(). Signed-off-by: Anand Jain Acked-by: Greg Kroah-Hartman Signed-off-by: David Sterba --- lib/kobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/kobject.c b/lib/kobject.c index 3b841b97fccd..53bfc853cd8c 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -548,6 +548,7 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) kfree(devpath); return error; } +EXPORT_SYMBOL_GPL(kobject_move); /** * kobject_del - unlink kobject from hierarchy. From f90fc5472882ee7e76e0f345b9642b92c8677582 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Mon, 22 Jun 2015 18:18:32 +0800 Subject: [PATCH 26/26] Btrfs: Check if kobject is initialized before put Signed-off-by: Anand Jain Tested-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index ea81a057c79b..603b0cc2b9bb 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -523,9 +523,11 @@ static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) fs_devs->device_dir_kobj = NULL; } - kobject_del(&fs_devs->super_kobj); - kobject_put(&fs_devs->super_kobj); - wait_for_completion(&fs_devs->kobj_unregister); + if (fs_devs->super_kobj.state_initialized) { + kobject_del(&fs_devs->super_kobj); + kobject_put(&fs_devs->super_kobj); + wait_for_completion(&fs_devs->kobj_unregister); + } } /* when fs_devs is NULL it will remove all fsid kobject */