Btrfs: sysfs: let default_attrs be separate from the kset
[cascardo/linux.git] / fs / btrfs / sysfs.c
index e8a4c86..11fa8e6 100644 (file)
@@ -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),
@@ -439,13 +439,14 @@ 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);
 }
 
 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)
@@ -506,8 +507,15 @@ 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);
+               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);
@@ -520,11 +528,10 @@ 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);
        }
-       kobject_del(fs_info->device_dir_kobj);
-       kobject_put(fs_info->device_dir_kobj);
        addrm_unknown_feature_attrs(fs_info, false);
        sysfs_remove_group(&fs_info->super_kobj, &btrfs_feature_attr_group);
-       __btrfs_sysfs_remove_one(fs_info);
+       sysfs_remove_files(&fs_info->super_kobj, btrfs_attrs);
+       btrfs_sysfs_remove_fsid(fs_info);
 }
 
 const char * const btrfs_feature_set_names[3] = {
@@ -602,6 +609,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)
 {
@@ -619,6 +628,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;
 }
 
@@ -667,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;
 
@@ -675,21 +703,35 @@ 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;
 
-       error = sysfs_create_group(&fs_info->super_kobj,
-                                  &btrfs_feature_attr_group);
+       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 = addrm_unknown_feature_attrs(fs_info, true);
+       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 = btrfs_kobj_add_device(fs_info, NULL);
+       error = addrm_unknown_feature_attrs(fs_info, true);
        if (error)
                goto failure;