driver/base: implement subsys_virtual_register()
authorTejun Heo <tj@kernel.org>
Tue, 12 Mar 2013 18:30:05 +0000 (11:30 -0700)
committerTejun Heo <tj@kernel.org>
Tue, 12 Mar 2013 18:36:35 +0000 (11:36 -0700)
Kay tells me the most appropriate place to expose workqueues to
userland would be /sys/devices/virtual/workqueues/WQ_NAME which is
symlinked to /sys/bus/workqueue/devices/WQ_NAME and that we're lacking
a way to do that outside of driver core as virtual_device_parent()
isn't exported and there's no inteface to conveniently create a
virtual subsystem.

This patch implements subsys_virtual_register() by factoring out
subsys_register() from subsys_system_register() and using it with
virtual_device_parent() as the origin directory.  It's identical to
subsys_system_register() other than the origin directory but we aren't
gonna restrict the device names which should be used under it.

This will be used to expose workqueue attributes to userland.

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Kay Sievers <kay.sievers@vrfy.org>
drivers/base/base.h
drivers/base/bus.c
drivers/base/core.c
include/linux/device.h

index 6ee17bb391a93be6c9d9898d48839615f2288a2e..b8bdfe61daa616e02e475e3b58602eb5d2cc5f78 100644 (file)
@@ -101,6 +101,8 @@ static inline int hypervisor_init(void) { return 0; }
 extern int platform_bus_init(void);
 extern void cpu_dev_init(void);
 
+struct kobject *virtual_device_parent(struct device *dev);
+
 extern int bus_add_device(struct device *dev);
 extern void bus_probe_device(struct device *dev);
 extern void bus_remove_device(struct device *dev);
index 519865b53f761c6a4641433a7092d8f6b9a0d7b2..2ae2d2f92b6b74226607ac388569a1c3aed35846 100644 (file)
@@ -1205,26 +1205,10 @@ static void system_root_device_release(struct device *dev)
 {
        kfree(dev);
 }
-/**
- * subsys_system_register - register a subsystem at /sys/devices/system/
- * @subsys: system subsystem
- * @groups: default attributes for the root device
- *
- * All 'system' subsystems have a /sys/devices/system/<name> root device
- * with the name of the subsystem. The root device can carry subsystem-
- * wide attributes. All registered devices are below this single root
- * device and are named after the subsystem with a simple enumeration
- * number appended. The registered devices are not explicitely named;
- * only 'id' in the device needs to be set.
- *
- * Do not use this interface for anything new, it exists for compatibility
- * with bad ideas only. New subsystems should use plain subsystems; and
- * add the subsystem-wide attributes should be added to the subsystem
- * directory itself and not some create fake root-device placed in
- * /sys/devices/system/<name>.
- */
-int subsys_system_register(struct bus_type *subsys,
-                          const struct attribute_group **groups)
+
+static int subsys_register(struct bus_type *subsys,
+                          const struct attribute_group **groups,
+                          struct kobject *parent_of_root)
 {
        struct device *dev;
        int err;
@@ -1243,7 +1227,7 @@ int subsys_system_register(struct bus_type *subsys,
        if (err < 0)
                goto err_name;
 
-       dev->kobj.parent = &system_kset->kobj;
+       dev->kobj.parent = parent_of_root;
        dev->groups = groups;
        dev->release = system_root_device_release;
 
@@ -1263,8 +1247,55 @@ err_dev:
        bus_unregister(subsys);
        return err;
 }
+
+/**
+ * subsys_system_register - register a subsystem at /sys/devices/system/
+ * @subsys: system subsystem
+ * @groups: default attributes for the root device
+ *
+ * All 'system' subsystems have a /sys/devices/system/<name> root device
+ * with the name of the subsystem. The root device can carry subsystem-
+ * wide attributes. All registered devices are below this single root
+ * device and are named after the subsystem with a simple enumeration
+ * number appended. The registered devices are not explicitely named;
+ * only 'id' in the device needs to be set.
+ *
+ * Do not use this interface for anything new, it exists for compatibility
+ * with bad ideas only. New subsystems should use plain subsystems; and
+ * add the subsystem-wide attributes should be added to the subsystem
+ * directory itself and not some create fake root-device placed in
+ * /sys/devices/system/<name>.
+ */
+int subsys_system_register(struct bus_type *subsys,
+                          const struct attribute_group **groups)
+{
+       return subsys_register(subsys, groups, &system_kset->kobj);
+}
 EXPORT_SYMBOL_GPL(subsys_system_register);
 
+/**
+ * subsys_virtual_register - register a subsystem at /sys/devices/virtual/
+ * @subsys: virtual subsystem
+ * @groups: default attributes for the root device
+ *
+ * All 'virtual' subsystems have a /sys/devices/system/<name> root device
+ * with the name of the subystem.  The root device can carry subsystem-wide
+ * attributes.  All registered devices are below this single root device.
+ * There's no restriction on device naming.  This is for kernel software
+ * constructs which need sysfs interface.
+ */
+int subsys_virtual_register(struct bus_type *subsys,
+                           const struct attribute_group **groups)
+{
+       struct kobject *virtual_dir;
+
+       virtual_dir = virtual_device_parent(NULL);
+       if (!virtual_dir)
+               return -ENOMEM;
+
+       return subsys_register(subsys, groups, virtual_dir);
+}
+
 int __init buses_init(void)
 {
        bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
index 56536f4b0f6b9bfd6c3aa4aa603e43e75112de87..f58084a86e8cd3e4a921a26c699c920bcf121868 100644 (file)
@@ -690,7 +690,7 @@ void device_initialize(struct device *dev)
        set_dev_node(dev, -1);
 }
 
-static struct kobject *virtual_device_parent(struct device *dev)
+struct kobject *virtual_device_parent(struct device *dev)
 {
        static struct kobject *virtual_dir = NULL;
 
index 9d6464ea99c69ff6f39b5368ead86f10026717d7..ee10d4e7be1ae6da83f1ccab69f2e90b283abdb2 100644 (file)
@@ -302,6 +302,8 @@ void subsys_interface_unregister(struct subsys_interface *sif);
 
 int subsys_system_register(struct bus_type *subsys,
                           const struct attribute_group **groups);
+int subsys_virtual_register(struct bus_type *subsys,
+                           const struct attribute_group **groups);
 
 /**
  * struct class - device classes