These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / fs / btrfs / sysfs.c
index e8a4c86..e0ac859 100644 (file)
@@ -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)
@@ -428,7 +429,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),
@@ -436,23 +437,31 @@ static struct attribute *btrfs_attrs[] = {
        NULL,
 };
 
-static void btrfs_release_super_kobj(struct kobject *kobj)
+static void btrfs_release_fsid_kobj(struct kobject *kobj)
 {
-       struct btrfs_fs_info *fs_info = to_fs_info(kobj);
-       complete(&fs_info->kobj_unregister);
+       struct btrfs_fs_devices *fs_devs = to_fs_devs(kobj);
+
+       memset(&fs_devs->fsid_kobj, 0, sizeof(struct kobject));
+       complete(&fs_devs->kobj_unregister);
 }
 
 static struct kobj_type btrfs_ktype = {
        .sysfs_ops      = &kobj_sysfs_ops,
-       .release        = btrfs_release_super_kobj,
-       .default_attrs  = btrfs_attrs,
+       .release        = btrfs_release_fsid_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, fsid_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
@@ -493,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->fsid_kobj,
                                                        &agroup);
                                if (ret)
                                        return ret;
                        } else
-                               sysfs_unmerge_group(&fs_info->super_kobj,
+                               sysfs_unmerge_group(&fs_info->fs_devices->fsid_kobj,
                                                    &agroup);
                }
 
@@ -506,25 +515,49 @@ 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_devices *fs_devs)
+{
+       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;
+       }
+
+       if (fs_devs->fsid_kobj.state_initialized) {
+               kobject_del(&fs_devs->fsid_kobj);
+               kobject_put(&fs_devs->fsid_kobj);
+               wait_for_completion(&fs_devs->kobj_unregister);
+       }
+}
+
+/* when fs_devs is NULL it will remove all fsid kobject */
+void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs)
 {
-       kobject_del(&fs_info->super_kobj);
-       kobject_put(&fs_info->super_kobj);
-       wait_for_completion(&fs_info->kobj_unregister);
+       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)
+void btrfs_sysfs_remove_mounted(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);
                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_group(&fs_info->fs_devices->fsid_kobj, &btrfs_feature_attr_group);
+       sysfs_remove_files(&fs_info->fs_devices->fsid_kobj, btrfs_attrs);
+       btrfs_sysfs_rm_device_link(fs_info->fs_devices, NULL);
 }
 
 const char * const btrfs_feature_set_names[3] = {
@@ -602,40 +635,60 @@ static void init_feature_attrs(void)
        }
 }
 
-int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info,
+/* when one_device is NULL, it removes all device links */
+
+int btrfs_sysfs_rm_device_link(struct btrfs_fs_devices *fs_devices,
                struct btrfs_device *one_device)
 {
        struct hd_struct *disk;
        struct kobject *disk_kobj;
 
-       if (!fs_info->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->device_dir_kobj,
+               sysfs_remove_link(fs_devices->device_dir_kobj,
+                                               disk_kobj->name);
+       }
+
+       if (one_device)
+               return 0;
+
+       list_for_each_entry(one_device,
+                       &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_devices->device_dir_kobj,
                                                disk_kobj->name);
        }
 
        return 0;
 }
 
-int btrfs_kobj_add_device(struct btrfs_fs_info *fs_info,
-               struct btrfs_device *one_device)
+int btrfs_sysfs_add_device(struct btrfs_fs_devices *fs_devs)
 {
-       int error = 0;
-       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_devs->device_dir_kobj)
+               fs_devs->device_dir_kobj = kobject_create_and_add("devices",
+                                               &fs_devs->fsid_kobj);
 
-       if (!fs_info->device_dir_kobj)
+       if (!fs_devs->device_dir_kobj)
                return -ENOMEM;
 
+       return 0;
+}
+
+int btrfs_sysfs_add_device_link(struct btrfs_fs_devices *fs_devices,
+                               struct btrfs_device *one_device)
+{
+       int error = 0;
+       struct btrfs_device *dev;
+
        list_for_each_entry(dev, &fs_devices->devices, dev_list) {
                struct hd_struct *disk;
                struct kobject *disk_kobj;
@@ -649,7 +702,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;
@@ -667,34 +720,51 @@ 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_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->fsid_kobj.kset = btrfs_kset;
+       error = kobject_init_and_add(&fs_devs->fsid_kobj,
+                               &btrfs_ktype, parent, "%pU", fs_devs->fsid);
+       return error;
+}
+
+int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info)
+{
+       int error;
+       struct btrfs_fs_devices *fs_devs = fs_info->fs_devices;
+       struct kobject *fsid_kobj = &fs_devs->fsid_kobj;
+
+       btrfs_set_fs_info_ptr(fs_info);
+
+       error = btrfs_sysfs_add_device_link(fs_devs, NULL);
        if (error)
                return error;
 
-       error = sysfs_create_group(&fs_info->super_kobj,
-                                  &btrfs_feature_attr_group);
+       error = sysfs_create_files(fsid_kobj, btrfs_attrs);
        if (error) {
-               __btrfs_sysfs_remove_one(fs_info);
+               btrfs_sysfs_rm_device_link(fs_devs, NULL);
                return error;
        }
 
-       error = addrm_unknown_feature_attrs(fs_info, true);
+       error = sysfs_create_group(fsid_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;
 
        fs_info->space_info_kobj = kobject_create_and_add("allocation",
-                                                 &fs_info->super_kobj);
+                                                 fsid_kobj);
        if (!fs_info->space_info_kobj) {
                error = -ENOMEM;
                goto failure;
@@ -706,7 +776,7 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info)
 
        return 0;
 failure:
-       btrfs_sysfs_remove_one(fs_info);
+       btrfs_sysfs_remove_mounted(fs_info);
        return error;
 }