diff options
author | Kay Sievers <kay.sievers@vrfy.org> | 2011-12-14 00:54:33 +0100 |
---|---|---|
committer | Kay Sievers <kay.sievers@vrfy.org> | 2011-12-14 00:54:33 +0100 |
commit | 33b51e22fdfb2b3856a26bba1d536508ef88da6b (patch) | |
tree | 1f5cc6b2854b9bd8eabfec43985a6d3c89112073 | |
parent | cfe9becc6e303c84b506fda154057e2517f0d926 (diff) | |
download | patches-33b51e22fdfb2b3856a26bba1d536508ef88da6b.tar.gz |
sysdev work
-rw-r--r-- | 01-core-support.patch | 864 | ||||
-rw-r--r-- | 02-cpu.patch | 1935 | ||||
-rw-r--r-- | 03-memory.patch | 948 | ||||
-rw-r--r-- | 04-rtmutex.patch | 134 | ||||
-rw-r--r-- | 05-clocksource.patch | 104 | ||||
-rw-r--r-- | 06-ibm-rtl.patch | 98 | ||||
-rw-r--r-- | 07-edac.patch | 393 | ||||
-rw-r--r-- | 08-xen.patch | 424 | ||||
-rw-r--r-- | 99-core-remove.patch | 728 | ||||
-rw-r--r-- | prctl-child_reaper.patch | 175 | ||||
-rw-r--r-- | series | 9 |
11 files changed, 5812 insertions, 0 deletions
diff --git a/01-core-support.patch b/01-core-support.patch new file mode 100644 index 0000000..d5e0a3e --- /dev/null +++ b/01-core-support.patch @@ -0,0 +1,864 @@ +From: Kay Sievers <kay.sievers@vrfy.org> +Subject: driver-core: implement 'sysdev' functionality for regular devices and buses + +All sysdev classes and sysdev devices will converted to regular devices +and buses to properly hook userspace into the event processing. + +There is no interesting difference between a 'sysdev' and 'device' which +would justify to roll an entire own subsystem with different userspace +export semantics. Userspace relies on events and generic sysfs subsystem +infrastructure from sysdev devices, which are currently not properly +available. + +Every converted sysdev class will create a regular device with the class +name in /sys/devices/system and all registered devices will becom a children +of theses devices. + +For compatibility reasons, the sysdev class-wide attributes are created +at this parent device. (Do not copy that logic for anything new, subsystem- +wide properties belong to the subsystem, not to some fake parent device +created in /sys/devices.) + +Every sysdev driver is implemented as a simple subsystem interface now, +and no longer called a driver. + +After all sysdev classes are ported to regular driver core entities, the +sysdev implementation will be entirely removed from the kernel. + +Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> +--- + drivers/base/base.h | 12 +- + drivers/base/bus.c | 291 +++++++++++++++++++++++++++++++++++++++++++++---- + drivers/base/class.c | 14 +- + drivers/base/core.c | 85 +++++++++++--- + drivers/base/init.c | 1 + drivers/base/sys.c | 10 - + include/linux/device.h | 78 ++++++++++++- + 7 files changed, 430 insertions(+), 61 deletions(-) + +--- a/drivers/base/base.h ++++ b/drivers/base/base.h +@@ -4,7 +4,9 @@ + * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure. + * + * @subsys - the struct kset that defines this subsystem +- * @devices_kset - the list of devices associated ++ * @devices_kset - the subsystem's 'devices' directory ++ * @interfaces - list of subsystem interfaces associated ++ * @mutex - protect the devices, and interfaces lists. + * + * @drivers_kset - the list of drivers associated + * @klist_devices - the klist to iterate over the @devices_kset +@@ -14,10 +16,8 @@ + * @bus - pointer back to the struct bus_type that this structure is associated + * with. + * +- * @class_interfaces - list of class_interfaces associated + * @glue_dirs - "glue" directory to put in-between the parent device to + * avoid namespace conflicts +- * @class_mutex - mutex to protect the children, devices, and interfaces lists. + * @class - pointer back to the struct class that this structure is associated + * with. + * +@@ -28,6 +28,8 @@ + struct subsys_private { + struct kset subsys; + struct kset *devices_kset; ++ struct list_head interfaces; ++ struct mutex mutex; + + struct kset *drivers_kset; + struct klist klist_devices; +@@ -36,9 +38,7 @@ struct subsys_private { + unsigned int drivers_autoprobe:1; + struct bus_type *bus; + +- struct list_head class_interfaces; + struct kset glue_dirs; +- struct mutex class_mutex; + struct class *class; + }; + #define to_subsys_private(obj) container_of(obj, struct subsys_private, subsys.kobj) +@@ -94,7 +94,6 @@ extern int hypervisor_init(void); + static inline int hypervisor_init(void) { return 0; } + #endif + extern int platform_bus_init(void); +-extern int system_bus_init(void); + extern int cpu_dev_init(void); + + extern int bus_add_device(struct device *dev); +@@ -116,6 +115,7 @@ extern char *make_class_name(const char + + extern int devres_release_all(struct device *dev); + ++/* /sys/devices directory */ + extern struct kset *devices_kset; + + #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) +--- a/drivers/base/bus.c ++++ b/drivers/base/bus.c +@@ -16,9 +16,14 @@ + #include <linux/slab.h> + #include <linux/init.h> + #include <linux/string.h> ++#include <linux/mutex.h> + #include "base.h" + #include "power/power.h" + ++/* /sys/devices/system */ ++/* FIXME: make static after drivers/base/sys.c is deleted */ ++struct kset *system_kset; ++ + #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) + + /* +@@ -360,6 +365,47 @@ struct device *bus_find_device_by_name(s + } + EXPORT_SYMBOL_GPL(bus_find_device_by_name); + ++/** ++ * subsys_find_device_by_id - find a device with a specific enumeration number ++ * @subsys: subsystem ++ * @id: index 'id' in struct device ++ * @hint: device to check first ++ * ++ * Check the hint's next object and if it is a match return it directly, ++ * otherwise, fall back to a full list search. Either way a reference for ++ * the returned object is taken. ++ */ ++struct device *subsys_find_device_by_id(struct bus_type *subsys, unsigned int id, ++ struct device *hint) ++{ ++ struct klist_iter i; ++ struct device *dev; ++ ++ if (!subsys) ++ return NULL; ++ ++ if (hint) { ++ klist_iter_init_node(&subsys->p->klist_devices, &i, &hint->p->knode_bus); ++ dev = next_device(&i); ++ if (dev && dev->id == id && get_device(dev)) { ++ klist_iter_exit(&i); ++ return dev; ++ } ++ klist_iter_exit(&i); ++ } ++ ++ klist_iter_init_node(&subsys->p->klist_devices, &i, NULL); ++ while ((dev = next_device(&i))) { ++ if (dev->id == id && get_device(dev)) { ++ klist_iter_exit(&i); ++ return dev; ++ } ++ } ++ klist_iter_exit(&i); ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(subsys_find_device_by_id); ++ + static struct device_driver *next_driver(struct klist_iter *i) + { + struct klist_node *n = klist_next(i); +@@ -487,38 +533,59 @@ out_put: + void bus_probe_device(struct device *dev) + { + struct bus_type *bus = dev->bus; ++ struct subsys_interface *sif; + int ret; + +- if (bus && bus->p->drivers_autoprobe) { ++ if (!bus) ++ return; ++ ++ if (bus->p->drivers_autoprobe) { + ret = device_attach(dev); + WARN_ON(ret < 0); + } ++ ++ mutex_lock(&bus->p->mutex); ++ list_for_each_entry(sif, &bus->p->interfaces, node) ++ if (sif->add_dev) ++ sif->add_dev(dev, sif); ++ mutex_unlock(&bus->p->mutex); + } + + /** + * bus_remove_device - remove device from bus + * @dev: device to be removed + * +- * - Remove symlink from bus's directory. ++ * - Remove device from all interfaces. ++ * - Remove symlink from bus' directory. + * - Delete device from bus's list. + * - Detach from its driver. + * - Drop reference taken in bus_add_device(). + */ + void bus_remove_device(struct device *dev) + { +- if (dev->bus) { +- sysfs_remove_link(&dev->kobj, "subsystem"); +- sysfs_remove_link(&dev->bus->p->devices_kset->kobj, +- dev_name(dev)); +- device_remove_attrs(dev->bus, dev); +- if (klist_node_attached(&dev->p->knode_bus)) +- klist_del(&dev->p->knode_bus); ++ struct bus_type *bus = dev->bus; ++ struct subsys_interface *sif; + +- pr_debug("bus: '%s': remove device %s\n", +- dev->bus->name, dev_name(dev)); +- device_release_driver(dev); +- bus_put(dev->bus); +- } ++ if (!bus) ++ return; ++ ++ mutex_lock(&bus->p->mutex); ++ list_for_each_entry(sif, &bus->p->interfaces, node) ++ if (sif->remove_dev) ++ sif->remove_dev(dev, sif); ++ mutex_unlock(&bus->p->mutex); ++ ++ sysfs_remove_link(&dev->kobj, "subsystem"); ++ sysfs_remove_link(&dev->bus->p->devices_kset->kobj, ++ dev_name(dev)); ++ device_remove_attrs(dev->bus, dev); ++ if (klist_node_attached(&dev->p->knode_bus)) ++ klist_del(&dev->p->knode_bus); ++ ++ pr_debug("bus: '%s': remove device %s\n", ++ dev->bus->name, dev_name(dev)); ++ device_release_driver(dev); ++ bus_put(dev->bus); + } + + static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv) +@@ -847,14 +914,14 @@ static ssize_t bus_uevent_store(struct b + static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); + + /** +- * bus_register - register a bus with the system. ++ * __bus_register - register a driver-core subsystem + * @bus: bus. + * + * Once we have that, we registered the bus with the kobject + * infrastructure, then register the children subsystems it has: +- * the devices and drivers that belong to the bus. ++ * the devices and drivers that belong to the subsystem. + */ +-int bus_register(struct bus_type *bus) ++int __bus_register(struct bus_type *bus, struct lock_class_key *key) + { + int retval; + struct subsys_private *priv; +@@ -898,6 +965,8 @@ int bus_register(struct bus_type *bus) + goto bus_drivers_fail; + } + ++ INIT_LIST_HEAD(&priv->interfaces); ++ __mutex_init(&priv->mutex, "subsys mutex", key); + klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); + klist_init(&priv->klist_drivers, NULL, NULL); + +@@ -927,7 +996,7 @@ out: + bus->p = NULL; + return retval; + } +-EXPORT_SYMBOL_GPL(bus_register); ++EXPORT_SYMBOL_GPL(__bus_register); + + /** + * bus_unregister - remove a bus from the system +@@ -939,6 +1008,8 @@ EXPORT_SYMBOL_GPL(bus_register); + void bus_unregister(struct bus_type *bus) + { + pr_debug("bus: '%s': unregistering\n", bus->name); ++ if (bus->dev_root) ++ device_unregister(bus->dev_root); + bus_remove_attrs(bus); + remove_probe_files(bus); + kset_unregister(bus->p->drivers_kset); +@@ -1028,10 +1099,194 @@ void bus_sort_breadthfirst(struct bus_ty + } + EXPORT_SYMBOL_GPL(bus_sort_breadthfirst); + ++/** ++ * subsys_dev_iter_init - initialize subsys device iterator ++ * @iter: subsys iterator to initialize ++ * @subsys: the subsys we wanna iterate over ++ * @start: the device to start iterating from, if any ++ * @type: device_type of the devices to iterate over, NULL for all ++ * ++ * Initialize subsys iterator @iter such that it iterates over devices ++ * of @subsys. If @start is set, the list iteration will start there, ++ * otherwise if it is NULL, the iteration starts at the beginning of ++ * the list. ++ */ ++void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys, ++ struct device *start, const struct device_type *type) ++{ ++ struct klist_node *start_knode = NULL; ++ ++ if (start) ++ start_knode = &start->p->knode_bus; ++ klist_iter_init_node(&subsys->p->klist_devices, &iter->ki, start_knode); ++ iter->type = type; ++} ++EXPORT_SYMBOL_GPL(subsys_dev_iter_init); ++ ++/** ++ * subsys_dev_iter_next - iterate to the next device ++ * @iter: subsys iterator to proceed ++ * ++ * Proceed @iter to the next device and return it. Returns NULL if ++ * iteration is complete. ++ * ++ * The returned device is referenced and won't be released till ++ * iterator is proceed to the next device or exited. The caller is ++ * free to do whatever it wants to do with the device including ++ * calling back into subsys code. ++ */ ++struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter) ++{ ++ struct klist_node *knode; ++ struct device *dev; ++ ++ for(;;) { ++ knode = klist_next(&iter->ki); ++ if (!knode) ++ return NULL; ++ dev = container_of(knode, struct device_private, knode_bus)->device; ++ if (!iter->type || iter->type == dev->type) ++ return dev; ++ } ++} ++EXPORT_SYMBOL_GPL(subsys_dev_iter_next); ++ ++/** ++ * subsys_dev_iter_exit - finish iteration ++ * @iter: subsys iterator to finish ++ * ++ * Finish an iteration. Always call this function after iteration is ++ * complete whether the iteration ran till the end or not. ++ */ ++void subsys_dev_iter_exit(struct subsys_dev_iter *iter) ++{ ++ klist_iter_exit(&iter->ki); ++} ++EXPORT_SYMBOL_GPL(subsys_dev_iter_exit); ++ ++int subsys_interface_register(struct subsys_interface *sif) ++{ ++ struct bus_type *subsys; ++ struct subsys_dev_iter iter; ++ struct device *dev; ++ ++ if (!sif || !sif->subsys) ++ return -ENODEV; ++ ++ subsys = bus_get(sif->subsys); ++ if (!subsys) ++ return -EINVAL; ++ ++ mutex_lock(&subsys->p->mutex); ++ list_add_tail(&sif->node, &subsys->p->interfaces); ++ if (sif->add_dev) { ++ subsys_dev_iter_init(&iter, subsys, NULL, NULL); ++ while ((dev = subsys_dev_iter_next(&iter))) ++ sif->add_dev(dev, sif); ++ subsys_dev_iter_exit(&iter); ++ } ++ mutex_unlock(&subsys->p->mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(subsys_interface_register); ++ ++void subsys_interface_unregister(struct subsys_interface *sif) ++{ ++ struct bus_type *subsys = sif->subsys; ++ struct subsys_dev_iter iter; ++ struct device *dev; ++ ++ if (!sif) ++ return; ++ ++ mutex_lock(&subsys->p->mutex); ++ list_del_init(&sif->node); ++ if (sif->remove_dev) { ++ subsys_dev_iter_init(&iter, subsys, NULL, NULL); ++ while ((dev = subsys_dev_iter_next(&iter))) ++ sif->remove_dev(dev, sif); ++ subsys_dev_iter_exit(&iter); ++ } ++ mutex_unlock(&subsys->p->mutex); ++ ++ bus_put(subsys); ++} ++EXPORT_SYMBOL_GPL(subsys_interface_unregister); ++ ++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) ++{ ++ struct device *dev; ++ int err; ++ ++ err = bus_register(subsys); ++ if (err < 0) ++ return err; ++ ++ dev = kzalloc(sizeof(struct device), GFP_KERNEL); ++ if (!dev) { ++ err = -ENOMEM; ++ goto err_dev; ++ } ++ ++ err = dev_set_name(dev, "%s", subsys->name); ++ if (err < 0) ++ goto err_name; ++ ++ dev->kobj.parent = &system_kset->kobj; ++ dev->groups = groups; ++ dev->release = system_root_device_release; ++ ++ err = device_register(dev); ++ if (err < 0) ++ goto err_dev_reg; ++ ++ subsys->dev_root = dev; ++ return 0; ++ ++err_dev_reg: ++ put_device(dev); ++ dev = NULL; ++err_name: ++ kfree(dev); ++err_dev: ++ bus_unregister(subsys); ++ return err; ++} ++EXPORT_SYMBOL_GPL(subsys_system_register); ++ + int __init buses_init(void) + { + bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); + if (!bus_kset) + return -ENOMEM; ++ ++ system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj); ++ if (!system_kset) ++ return -ENOMEM; ++ + return 0; + } +--- a/drivers/base/class.c ++++ b/drivers/base/class.c +@@ -184,9 +184,9 @@ int __class_register(struct class *cls, + if (!cp) + return -ENOMEM; + klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put); +- INIT_LIST_HEAD(&cp->class_interfaces); ++ INIT_LIST_HEAD(&cp->interfaces); + kset_init(&cp->glue_dirs); +- __mutex_init(&cp->class_mutex, "struct class mutex", key); ++ __mutex_init(&cp->mutex, "subsys mutex", key); + error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); + if (error) { + kfree(cp); +@@ -460,15 +460,15 @@ int class_interface_register(struct clas + if (!parent) + return -EINVAL; + +- mutex_lock(&parent->p->class_mutex); +- list_add_tail(&class_intf->node, &parent->p->class_interfaces); ++ mutex_lock(&parent->p->mutex); ++ list_add_tail(&class_intf->node, &parent->p->interfaces); + if (class_intf->add_dev) { + class_dev_iter_init(&iter, parent, NULL, NULL); + while ((dev = class_dev_iter_next(&iter))) + class_intf->add_dev(dev, class_intf); + class_dev_iter_exit(&iter); + } +- mutex_unlock(&parent->p->class_mutex); ++ mutex_unlock(&parent->p->mutex); + + return 0; + } +@@ -482,7 +482,7 @@ void class_interface_unregister(struct c + if (!parent) + return; + +- mutex_lock(&parent->p->class_mutex); ++ mutex_lock(&parent->p->mutex); + list_del_init(&class_intf->node); + if (class_intf->remove_dev) { + class_dev_iter_init(&iter, parent, NULL, NULL); +@@ -490,7 +490,7 @@ void class_interface_unregister(struct c + class_intf->remove_dev(dev, class_intf); + class_dev_iter_exit(&iter); + } +- mutex_unlock(&parent->p->class_mutex); ++ mutex_unlock(&parent->p->mutex); + + class_put(parent); + } +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -118,6 +118,56 @@ static const struct sysfs_ops dev_sysfs_ + .store = dev_attr_store, + }; + ++#define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr) ++ ++ssize_t device_store_ulong(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ struct dev_ext_attribute *ea = to_ext_attr(attr); ++ char *end; ++ unsigned long new = simple_strtoul(buf, &end, 0); ++ if (end == buf) ++ return -EINVAL; ++ *(unsigned long *)(ea->var) = new; ++ /* Always return full write size even if we didn't consume all */ ++ return size; ++} ++EXPORT_SYMBOL_GPL(device_store_ulong); ++ ++ssize_t device_show_ulong(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct dev_ext_attribute *ea = to_ext_attr(attr); ++ return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var)); ++} ++EXPORT_SYMBOL_GPL(device_show_ulong); ++ ++ssize_t device_store_int(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ struct dev_ext_attribute *ea = to_ext_attr(attr); ++ char *end; ++ long new = simple_strtol(buf, &end, 0); ++ if (end == buf || new > INT_MAX || new < INT_MIN) ++ return -EINVAL; ++ *(int *)(ea->var) = new; ++ /* Always return full write size even if we didn't consume all */ ++ return size; ++} ++EXPORT_SYMBOL_GPL(device_store_int); ++ ++ssize_t device_show_int(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct dev_ext_attribute *ea = to_ext_attr(attr); ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var)); ++} ++EXPORT_SYMBOL_GPL(device_show_int); + + /** + * device_release - free device structure. +@@ -464,7 +514,7 @@ static ssize_t show_dev(struct device *d + static struct device_attribute devt_attr = + __ATTR(dev, S_IRUGO, show_dev, NULL); + +-/* kset to create /sys/devices/ */ ++/* /sys/devices/ */ + struct kset *devices_kset; + + /** +@@ -711,6 +761,10 @@ static struct kobject *get_device_parent + return k; + } + ++ /* subsystems can specify a default root directory for their devices */ ++ if (!parent && dev->bus && dev->bus->dev_root) ++ return &dev->bus->dev_root->kobj; ++ + if (parent) + return &parent->kobj; + return NULL; +@@ -731,14 +785,6 @@ static void cleanup_device_parent(struct + cleanup_glue_dir(dev, dev->kobj.parent); + } + +-static void setup_parent(struct device *dev, struct device *parent) +-{ +- struct kobject *kobj; +- kobj = get_device_parent(dev, parent); +- if (kobj) +- dev->kobj.parent = kobj; +-} +- + static int device_add_class_symlinks(struct device *dev) + { + int error; +@@ -891,6 +937,7 @@ int device_private_init(struct device *d + int device_add(struct device *dev) + { + struct device *parent = NULL; ++ struct kobject *kobj; + struct class_interface *class_intf; + int error = -EINVAL; + +@@ -914,6 +961,10 @@ int device_add(struct device *dev) + dev->init_name = NULL; + } + ++ /* subsystems can specify simple device enumeration */ ++ if (!dev_name(dev) && dev->bus && dev->bus->dev_name) ++ dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); ++ + if (!dev_name(dev)) { + error = -EINVAL; + goto name_error; +@@ -922,7 +973,9 @@ int device_add(struct device *dev) + pr_debug("device: '%s': %s\n", dev_name(dev), __func__); + + parent = get_device(dev->parent); +- setup_parent(dev, parent); ++ kobj = get_device_parent(dev, parent); ++ if (kobj) ++ dev->kobj.parent = kobj; + + /* use parent numa_node */ + if (parent) +@@ -982,17 +1035,17 @@ int device_add(struct device *dev) + &parent->p->klist_children); + + if (dev->class) { +- mutex_lock(&dev->class->p->class_mutex); ++ mutex_lock(&dev->class->p->mutex); + /* tie the class to the device */ + klist_add_tail(&dev->knode_class, + &dev->class->p->klist_devices); + + /* notify any interfaces that the device is here */ + list_for_each_entry(class_intf, +- &dev->class->p->class_interfaces, node) ++ &dev->class->p->interfaces, node) + if (class_intf->add_dev) + class_intf->add_dev(dev, class_intf); +- mutex_unlock(&dev->class->p->class_mutex); ++ mutex_unlock(&dev->class->p->mutex); + } + done: + put_device(dev); +@@ -1107,15 +1160,15 @@ void device_del(struct device *dev) + if (dev->class) { + device_remove_class_symlinks(dev); + +- mutex_lock(&dev->class->p->class_mutex); ++ mutex_lock(&dev->class->p->mutex); + /* notify any interfaces that the device is now gone */ + list_for_each_entry(class_intf, +- &dev->class->p->class_interfaces, node) ++ &dev->class->p->interfaces, node) + if (class_intf->remove_dev) + class_intf->remove_dev(dev, class_intf); + /* remove the device from the class list */ + klist_del(&dev->knode_class); +- mutex_unlock(&dev->class->p->class_mutex); ++ mutex_unlock(&dev->class->p->mutex); + } + device_remove_file(dev, &uevent_attr); + device_remove_attrs(dev); +--- a/drivers/base/init.c ++++ b/drivers/base/init.c +@@ -31,7 +31,6 @@ void __init driver_init(void) + * core core pieces. + */ + platform_bus_init(); +- system_bus_init(); + cpu_dev_init(); + memory_dev_init(); + } +--- a/drivers/base/sys.c ++++ b/drivers/base/sys.c +@@ -126,7 +126,7 @@ void sysdev_class_remove_file(struct sys + } + EXPORT_SYMBOL_GPL(sysdev_class_remove_file); + +-static struct kset *system_kset; ++extern struct kset *system_kset; + + int sysdev_class_register(struct sysdev_class *cls) + { +@@ -331,14 +331,6 @@ void sysdev_unregister(struct sys_device + EXPORT_SYMBOL_GPL(sysdev_register); + EXPORT_SYMBOL_GPL(sysdev_unregister); + +-int __init system_bus_init(void) +-{ +- system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj); +- if (!system_kset) +- return -ENOMEM; +- return 0; +-} +- + #define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr) + + ssize_t sysdev_store_ulong(struct sys_device *sysdev, +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -53,6 +53,8 @@ extern void bus_remove_file(struct bus_t + * struct bus_type - The bus type of the device + * + * @name: The name of the bus. ++ * @dev_name: Used for subsystems to enumerate devices like ("foo%u", dev->id). ++ * @dev_root: Default device to use as the parent. + * @bus_attrs: Default attributes of the bus. + * @dev_attrs: Default attributes of the devices on the bus. + * @drv_attrs: Default attributes of the device drivers on the bus. +@@ -86,6 +88,8 @@ extern void bus_remove_file(struct bus_t + */ + struct bus_type { + const char *name; ++ const char *dev_name; ++ struct device *dev_root; + struct bus_attribute *bus_attrs; + struct device_attribute *dev_attrs; + struct driver_attribute *drv_attrs; +@@ -106,12 +110,30 @@ struct bus_type { + struct subsys_private *p; + }; + +-extern int __must_check bus_register(struct bus_type *bus); ++/* This is a #define to keep the compiler from merging different ++ * instances of the __key variable */ ++#define bus_register(subsys) \ ++({ \ ++ static struct lock_class_key __key; \ ++ __bus_register(subsys, &__key); \ ++}) ++extern int __must_check __bus_register(struct bus_type *bus, ++ struct lock_class_key *key); + extern void bus_unregister(struct bus_type *bus); + + extern int __must_check bus_rescan_devices(struct bus_type *bus); + + /* iterator helpers for buses */ ++struct subsys_dev_iter { ++ struct klist_iter ki; ++ const struct device_type *type; ++}; ++void subsys_dev_iter_init(struct subsys_dev_iter *iter, ++ struct bus_type *subsys, ++ struct device *start, ++ const struct device_type *type); ++struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter); ++void subsys_dev_iter_exit(struct subsys_dev_iter *iter); + + int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, + int (*fn)(struct device *dev, void *data)); +@@ -121,10 +143,10 @@ struct device *bus_find_device(struct bu + struct device *bus_find_device_by_name(struct bus_type *bus, + struct device *start, + const char *name); +- ++struct device *subsys_find_device_by_id(struct bus_type *bus, unsigned int id, ++ struct device *hint); + int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, + void *data, int (*fn)(struct device_driver *, void *)); +- + void bus_sort_breadthfirst(struct bus_type *bus, + int (*compare)(const struct device *a, + const struct device *b)); +@@ -256,6 +278,33 @@ struct device *driver_find_device(struct + int (*match)(struct device *dev, void *data)); + + /** ++ * struct subsys_interface - interfaces to device functions ++ * @name name of the device function ++ * @subsystem subsytem of the devices to attach to ++ * @node the list of functions registered at the subsystem ++ * @add device hookup to device function handler ++ * @remove device hookup to device function handler ++ * ++ * Simple interfaces attached to a subsystem. Multiple interfaces can ++ * attach to a subsystem and its devices. Unlike drivers, they do not ++ * exclusively claim or control devices. Interfaces usually represent ++ * a specific functionality of a subsystem/class of devices. ++ */ ++struct subsys_interface { ++ const char *name; ++ struct bus_type *subsys; ++ struct list_head node; ++ int (*add_dev)(struct device *dev, struct subsys_interface *sif); ++ int (*remove_dev)(struct device *dev, struct subsys_interface *sif); ++}; ++ ++int subsys_interface_register(struct subsys_interface *sif); ++void subsys_interface_unregister(struct subsys_interface *sif); ++ ++int subsys_system_register(struct bus_type *subsys, ++ const struct attribute_group **groups); ++ ++/** + * struct class - device classes + * @name: Name of the class. + * @owner: The module owner. +@@ -438,8 +487,28 @@ struct device_attribute { + const char *buf, size_t count); + }; + ++struct dev_ext_attribute { ++ struct device_attribute attr; ++ void *var; ++}; ++ ++ssize_t device_show_ulong(struct device *dev, struct device_attribute *attr, ++ char *buf); ++ssize_t device_store_ulong(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count); ++ssize_t device_show_int(struct device *dev, struct device_attribute *attr, ++ char *buf); ++ssize_t device_store_int(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count); ++ + #define DEVICE_ATTR(_name, _mode, _show, _store) \ +-struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) ++ struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) ++#define DEVICE_ULONG_ATTR(_name, _mode, _var) \ ++ struct dev_ext_attribute dev_attr_##_name = \ ++ { __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) } ++#define DEVICE_INT_ATTR(_name, _mode, _var) \ ++ struct dev_ext_attribute dev_attr_##_name = \ ++ { __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) } + + extern int __must_check device_create_file(struct device *device, + const struct device_attribute *entry); +@@ -600,6 +669,7 @@ struct device { + struct device_node *of_node; /* associated device tree node */ + + dev_t devt; /* dev_t, creates the sysfs "dev" */ ++ u32 id; /* device instance */ + + spinlock_t devres_lock; + struct list_head devres_head; diff --git a/02-cpu.patch b/02-cpu.patch new file mode 100644 index 0000000..4ac4f79 --- /dev/null +++ b/02-cpu.patch @@ -0,0 +1,1935 @@ +From: Kay Sievers <kay.sievers@vrfy.org> +Subject: convert 'cpu' and 'machinecheck' sysdev_class to a regular subsystem + +This moves the 'cpu sysdev_class' over to a regular 'cpu' subsystem +and converts the devices to regular devices. The sysdev drivers are +implemented as subsystem interfaces now. + +After all sysdev classes are ported to regular driver core entities, the +sysdev implementation will be entirely removed from the kernel. + +Userspace relies on events and generic sysfs subsystem infrastructure +from sysdev devices, which are made available with this conversion. + +Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> +--- + arch/x86/include/asm/mce.h | 2 + arch/x86/kernel/cpu/intel_cacheinfo.c | 25 ++--- + arch/x86/kernel/cpu/mcheck/mce-internal.h | 4 + arch/x86/kernel/cpu/mcheck/mce.c | 130 +++++++++++++------------- + arch/x86/kernel/cpu/mcheck/mce_amd.c | 11 +- + arch/x86/kernel/cpu/mcheck/therm_throt.c | 63 ++++++------ + arch/x86/kernel/microcode_core.c | 64 ++++++------- + drivers/acpi/processor_driver.c | 6 - + drivers/acpi/processor_thermal.c | 1 + drivers/base/cpu.c | 146 +++++++++++++++--------------- + drivers/base/node.c | 8 - + drivers/base/topology.c | 51 +++++----- + drivers/cpufreq/cpufreq.c | 79 ++++++++-------- + drivers/cpufreq/cpufreq_stats.c | 1 + drivers/cpuidle/cpuidle.c | 12 +- + drivers/cpuidle/cpuidle.h | 10 +- + drivers/cpuidle/sysfs.c | 78 +++++++--------- + include/linux/cpu.h | 18 +-- + kernel/sched.c | 40 +++----- + 19 files changed, 374 insertions(+), 375 deletions(-) + +--- a/arch/x86/include/asm/mce.h ++++ b/arch/x86/include/asm/mce.h +@@ -149,7 +149,7 @@ static inline void enable_p5_mce(void) { + + void mce_setup(struct mce *m); + void mce_log(struct mce *m); +-DECLARE_PER_CPU(struct sys_device, mce_sysdev); ++DECLARE_PER_CPU(struct device, mce_device); + + /* + * Maximum banks number. +--- a/arch/x86/kernel/cpu/intel_cacheinfo.c ++++ b/arch/x86/kernel/cpu/intel_cacheinfo.c +@@ -844,8 +844,7 @@ static int __cpuinit detect_cache_attrib + + #include <linux/kobject.h> + #include <linux/sysfs.h> +- +-extern struct sysdev_class cpu_sysdev_class; /* from drivers/base/cpu.c */ ++#include <linux/cpu.h> + + /* pointer to kobject for cpuX/cache */ + static DEFINE_PER_CPU(struct kobject *, ici_cache_kobject); +@@ -1073,9 +1072,9 @@ err_out: + static DECLARE_BITMAP(cache_dev_map, NR_CPUS); + + /* Add/Remove cache interface for CPU device */ +-static int __cpuinit cache_add_dev(struct sys_device * sys_dev) ++static int __cpuinit cache_add_dev(struct device *dev) + { +- unsigned int cpu = sys_dev->id; ++ unsigned int cpu = dev->id; + unsigned long i, j; + struct _index_kobject *this_object; + struct _cpuid4_info *this_leaf; +@@ -1087,7 +1086,7 @@ static int __cpuinit cache_add_dev(struc + + retval = kobject_init_and_add(per_cpu(ici_cache_kobject, cpu), + &ktype_percpu_entry, +- &sys_dev->kobj, "%s", "cache"); ++ &dev->kobj, "%s", "cache"); + if (retval < 0) { + cpuid4_cache_sysfs_exit(cpu); + return retval; +@@ -1124,9 +1123,9 @@ static int __cpuinit cache_add_dev(struc + return 0; + } + +-static void __cpuinit cache_remove_dev(struct sys_device * sys_dev) ++static void __cpuinit cache_remove_dev(struct device *dev) + { +- unsigned int cpu = sys_dev->id; ++ unsigned int cpu = dev->id; + unsigned long i; + + if (per_cpu(ici_cpuid4_info, cpu) == NULL) +@@ -1145,17 +1144,17 @@ static int __cpuinit cacheinfo_cpu_callb + unsigned long action, void *hcpu) + { + unsigned int cpu = (unsigned long)hcpu; +- struct sys_device *sys_dev; ++ struct device *dev; + +- sys_dev = get_cpu_sysdev(cpu); ++ dev = get_cpu_device(cpu); + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: +- cache_add_dev(sys_dev); ++ cache_add_dev(dev); + break; + case CPU_DEAD: + case CPU_DEAD_FROZEN: +- cache_remove_dev(sys_dev); ++ cache_remove_dev(dev); + break; + } + return NOTIFY_OK; +@@ -1174,9 +1173,9 @@ static int __cpuinit cache_sysfs_init(vo + + for_each_online_cpu(i) { + int err; +- struct sys_device *sys_dev = get_cpu_sysdev(i); ++ struct device *dev = get_cpu_device(i); + +- err = cache_add_dev(sys_dev); ++ err = cache_add_dev(dev); + if (err) + return err; + } +--- a/arch/x86/kernel/cpu/mcheck/mce-internal.h ++++ b/arch/x86/kernel/cpu/mcheck/mce-internal.h +@@ -1,4 +1,4 @@ +-#include <linux/sysdev.h> ++#include <linux/device.h> + #include <asm/mce.h> + + enum severity_level { +@@ -17,7 +17,7 @@ enum severity_level { + struct mce_bank { + u64 ctl; /* subevents to enable */ + unsigned char init; /* initialise bank? */ +- struct sysdev_attribute attr; /* sysdev attribute */ ++ struct device_attribute attr; /* device attribute */ + char attrname[ATTR_LEN]; /* attribute name */ + }; + +--- a/arch/x86/kernel/cpu/mcheck/mce.c ++++ b/arch/x86/kernel/cpu/mcheck/mce.c +@@ -19,7 +19,7 @@ + #include <linux/kernel.h> + #include <linux/percpu.h> + #include <linux/string.h> +-#include <linux/sysdev.h> ++#include <linux/device.h> + #include <linux/syscore_ops.h> + #include <linux/delay.h> + #include <linux/ctype.h> +@@ -1770,7 +1770,7 @@ static struct syscore_ops mce_syscore_op + }; + + /* +- * mce_sysdev: Sysfs support ++ * mce_device: Sysfs support + */ + + static void mce_cpu_restart(void *data) +@@ -1806,27 +1806,28 @@ static void mce_enable_ce(void *all) + __mcheck_cpu_init_timer(); + } + +-static struct sysdev_class mce_sysdev_class = { ++static struct bus_type mce_subsys = { + .name = "machinecheck", ++ .dev_name = "machinecheck", + }; + +-DEFINE_PER_CPU(struct sys_device, mce_sysdev); ++DEFINE_PER_CPU(struct device, mce_device); + + __cpuinitdata + void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); + +-static inline struct mce_bank *attr_to_bank(struct sysdev_attribute *attr) ++static inline struct mce_bank *attr_to_bank(struct device_attribute *attr) + { + return container_of(attr, struct mce_bank, attr); + } + +-static ssize_t show_bank(struct sys_device *s, struct sysdev_attribute *attr, ++static ssize_t show_bank(struct device *s, struct device_attribute *attr, + char *buf) + { + return sprintf(buf, "%llx\n", attr_to_bank(attr)->ctl); + } + +-static ssize_t set_bank(struct sys_device *s, struct sysdev_attribute *attr, ++static ssize_t set_bank(struct device *s, struct device_attribute *attr, + const char *buf, size_t size) + { + u64 new; +@@ -1841,14 +1842,14 @@ static ssize_t set_bank(struct sys_devic + } + + static ssize_t +-show_trigger(struct sys_device *s, struct sysdev_attribute *attr, char *buf) ++show_trigger(struct device *s, struct device_attribute *attr, char *buf) + { + strcpy(buf, mce_helper); + strcat(buf, "\n"); + return strlen(mce_helper) + 1; + } + +-static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr, ++static ssize_t set_trigger(struct device *s, struct device_attribute *attr, + const char *buf, size_t siz) + { + char *p; +@@ -1863,8 +1864,8 @@ static ssize_t set_trigger(struct sys_de + return strlen(mce_helper) + !!p; + } + +-static ssize_t set_ignore_ce(struct sys_device *s, +- struct sysdev_attribute *attr, ++static ssize_t set_ignore_ce(struct device *s, ++ struct device_attribute *attr, + const char *buf, size_t size) + { + u64 new; +@@ -1887,8 +1888,8 @@ static ssize_t set_ignore_ce(struct sys_ + return size; + } + +-static ssize_t set_cmci_disabled(struct sys_device *s, +- struct sysdev_attribute *attr, ++static ssize_t set_cmci_disabled(struct device *s, ++ struct device_attribute *attr, + const char *buf, size_t size) + { + u64 new; +@@ -1910,108 +1911,107 @@ static ssize_t set_cmci_disabled(struct + return size; + } + +-static ssize_t store_int_with_restart(struct sys_device *s, +- struct sysdev_attribute *attr, ++static ssize_t store_int_with_restart(struct device *s, ++ struct device_attribute *attr, + const char *buf, size_t size) + { +- ssize_t ret = sysdev_store_int(s, attr, buf, size); ++ ssize_t ret = device_store_int(s, attr, buf, size); + mce_restart(); + return ret; + } + +-static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger); +-static SYSDEV_INT_ATTR(tolerant, 0644, tolerant); +-static SYSDEV_INT_ATTR(monarch_timeout, 0644, monarch_timeout); +-static SYSDEV_INT_ATTR(dont_log_ce, 0644, mce_dont_log_ce); +- +-static struct sysdev_ext_attribute attr_check_interval = { +- _SYSDEV_ATTR(check_interval, 0644, sysdev_show_int, +- store_int_with_restart), ++static DEVICE_ATTR(trigger, 0644, show_trigger, set_trigger); ++static DEVICE_INT_ATTR(tolerant, 0644, tolerant); ++static DEVICE_INT_ATTR(monarch_timeout, 0644, monarch_timeout); ++static DEVICE_INT_ATTR(dont_log_ce, 0644, mce_dont_log_ce); ++ ++static struct dev_ext_attribute dev_attr_check_interval = { ++ __ATTR(check_interval, 0644, device_show_int, store_int_with_restart), + &check_interval + }; + +-static struct sysdev_ext_attribute attr_ignore_ce = { +- _SYSDEV_ATTR(ignore_ce, 0644, sysdev_show_int, set_ignore_ce), ++static struct dev_ext_attribute dev_attr_ignore_ce = { ++ __ATTR(ignore_ce, 0644, device_show_int, set_ignore_ce), + &mce_ignore_ce + }; + +-static struct sysdev_ext_attribute attr_cmci_disabled = { +- _SYSDEV_ATTR(cmci_disabled, 0644, sysdev_show_int, set_cmci_disabled), ++static struct dev_ext_attribute dev_attr_cmci_disabled = { ++ __ATTR(cmci_disabled, 0644, device_show_int, set_cmci_disabled), + &mce_cmci_disabled + }; + +-static struct sysdev_attribute *mce_sysdev_attrs[] = { +- &attr_tolerant.attr, +- &attr_check_interval.attr, +- &attr_trigger, +- &attr_monarch_timeout.attr, +- &attr_dont_log_ce.attr, +- &attr_ignore_ce.attr, +- &attr_cmci_disabled.attr, ++static struct device_attribute *mce_device_attrs[] = { ++ &dev_attr_tolerant.attr, ++ &dev_attr_check_interval.attr, ++ &dev_attr_trigger, ++ &dev_attr_monarch_timeout.attr, ++ &dev_attr_dont_log_ce.attr, ++ &dev_attr_ignore_ce.attr, ++ &dev_attr_cmci_disabled.attr, + NULL + }; + +-static cpumask_var_t mce_sysdev_initialized; ++static cpumask_var_t mce_device_initialized; + +-/* Per cpu sysdev init. All of the cpus still share the same ctrl bank: */ +-static __cpuinit int mce_sysdev_create(unsigned int cpu) ++/* Per cpu device init. All of the cpus still share the same ctrl bank: */ ++static __cpuinit int mce_device_create(unsigned int cpu) + { +- struct sys_device *sysdev = &per_cpu(mce_sysdev, cpu); ++ struct device *dev = &per_cpu(mce_device, cpu); + int err; + int i, j; + + if (!mce_available(&boot_cpu_data)) + return -EIO; + +- memset(&sysdev->kobj, 0, sizeof(struct kobject)); +- sysdev->id = cpu; +- sysdev->cls = &mce_sysdev_class; ++ memset(&dev->kobj, 0, sizeof(struct kobject)); ++ dev->id = cpu; ++ dev->bus = &mce_subsys; + +- err = sysdev_register(sysdev); ++ err = device_register(dev); + if (err) + return err; + +- for (i = 0; mce_sysdev_attrs[i]; i++) { +- err = sysdev_create_file(sysdev, mce_sysdev_attrs[i]); ++ for (i = 0; mce_device_attrs[i]; i++) { ++ err = device_create_file(dev, mce_device_attrs[i]); + if (err) + goto error; + } + for (j = 0; j < banks; j++) { +- err = sysdev_create_file(sysdev, &mce_banks[j].attr); ++ err = device_create_file(dev, &mce_banks[j].attr); + if (err) + goto error2; + } +- cpumask_set_cpu(cpu, mce_sysdev_initialized); ++ cpumask_set_cpu(cpu, mce_device_initialized); + + return 0; + error2: + while (--j >= 0) +- sysdev_remove_file(sysdev, &mce_banks[j].attr); ++ device_remove_file(dev, &mce_banks[j].attr); + error: + while (--i >= 0) +- sysdev_remove_file(sysdev, mce_sysdev_attrs[i]); ++ device_remove_file(dev, mce_device_attrs[i]); + +- sysdev_unregister(sysdev); ++ device_unregister(dev); + + return err; + } + +-static __cpuinit void mce_sysdev_remove(unsigned int cpu) ++static __cpuinit void mce_device_remove(unsigned int cpu) + { +- struct sys_device *sysdev = &per_cpu(mce_sysdev, cpu); ++ struct device *dev = &per_cpu(mce_device, cpu); + int i; + +- if (!cpumask_test_cpu(cpu, mce_sysdev_initialized)) ++ if (!cpumask_test_cpu(cpu, mce_device_initialized)) + return; + +- for (i = 0; mce_sysdev_attrs[i]; i++) +- sysdev_remove_file(sysdev, mce_sysdev_attrs[i]); ++ for (i = 0; mce_device_attrs[i]; i++) ++ device_remove_file(dev, mce_device_attrs[i]); + + for (i = 0; i < banks; i++) +- sysdev_remove_file(sysdev, &mce_banks[i].attr); ++ device_remove_file(dev, &mce_banks[i].attr); + +- sysdev_unregister(sysdev); +- cpumask_clear_cpu(cpu, mce_sysdev_initialized); ++ device_unregister(dev); ++ cpumask_clear_cpu(cpu, mce_device_initialized); + } + + /* Make sure there are no machine checks on offlined CPUs. */ +@@ -2061,7 +2061,7 @@ mce_cpu_callback(struct notifier_block * + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: +- mce_sysdev_create(cpu); ++ mce_device_create(cpu); + if (threshold_cpu_callback) + threshold_cpu_callback(action, cpu); + break; +@@ -2069,7 +2069,7 @@ mce_cpu_callback(struct notifier_block * + case CPU_DEAD_FROZEN: + if (threshold_cpu_callback) + threshold_cpu_callback(action, cpu); +- mce_sysdev_remove(cpu); ++ mce_device_remove(cpu); + break; + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: +@@ -2103,7 +2103,7 @@ static __init void mce_init_banks(void) + + for (i = 0; i < banks; i++) { + struct mce_bank *b = &mce_banks[i]; +- struct sysdev_attribute *a = &b->attr; ++ struct device_attribute *a = &b->attr; + + sysfs_attr_init(&a->attr); + a->attr.name = b->attrname; +@@ -2123,16 +2123,16 @@ static __init int mcheck_init_device(voi + if (!mce_available(&boot_cpu_data)) + return -EIO; + +- zalloc_cpumask_var(&mce_sysdev_initialized, GFP_KERNEL); ++ zalloc_cpumask_var(&mce_device_initialized, GFP_KERNEL); + + mce_init_banks(); + +- err = sysdev_class_register(&mce_sysdev_class); ++ err = bus_register(&mce_subsys); + if (err) + return err; + + for_each_online_cpu(i) { +- err = mce_sysdev_create(i); ++ err = mce_device_create(i); + if (err) + return err; + } +--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c ++++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c +@@ -17,7 +17,6 @@ + #include <linux/notifier.h> + #include <linux/kobject.h> + #include <linux/percpu.h> +-#include <linux/sysdev.h> + #include <linux/errno.h> + #include <linux/sched.h> + #include <linux/sysfs.h> +@@ -548,7 +547,7 @@ static __cpuinit int threshold_create_ba + if (!b) + goto out; + +- err = sysfs_create_link(&per_cpu(mce_sysdev, cpu).kobj, ++ err = sysfs_create_link(&per_cpu(mce_device, cpu).kobj, + b->kobj, name); + if (err) + goto out; +@@ -571,7 +570,7 @@ static __cpuinit int threshold_create_ba + goto out; + } + +- b->kobj = kobject_create_and_add(name, &per_cpu(mce_sysdev, cpu).kobj); ++ b->kobj = kobject_create_and_add(name, &per_cpu(mce_device, cpu).kobj); + if (!b->kobj) + goto out_free; + +@@ -591,7 +590,7 @@ static __cpuinit int threshold_create_ba + if (i == cpu) + continue; + +- err = sysfs_create_link(&per_cpu(mce_sysdev, i).kobj, ++ err = sysfs_create_link(&per_cpu(mce_device, i).kobj, + b->kobj, name); + if (err) + goto out; +@@ -669,7 +668,7 @@ static void threshold_remove_bank(unsign + #ifdef CONFIG_SMP + /* sibling symlink */ + if (shared_bank[bank] && b->blocks->cpu != cpu) { +- sysfs_remove_link(&per_cpu(mce_sysdev, cpu).kobj, name); ++ sysfs_remove_link(&per_cpu(mce_device, cpu).kobj, name); + per_cpu(threshold_banks, cpu)[bank] = NULL; + + return; +@@ -681,7 +680,7 @@ static void threshold_remove_bank(unsign + if (i == cpu) + continue; + +- sysfs_remove_link(&per_cpu(mce_sysdev, i).kobj, name); ++ sysfs_remove_link(&per_cpu(mce_device, i).kobj, name); + per_cpu(threshold_banks, i)[bank] = NULL; + } + +--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c ++++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c +@@ -19,7 +19,6 @@ + #include <linux/kernel.h> + #include <linux/percpu.h> + #include <linux/export.h> +-#include <linux/sysdev.h> + #include <linux/types.h> + #include <linux/init.h> + #include <linux/smp.h> +@@ -69,16 +68,16 @@ static atomic_t therm_throt_en = ATOMIC_ + static u32 lvtthmr_init __read_mostly; + + #ifdef CONFIG_SYSFS +-#define define_therm_throt_sysdev_one_ro(_name) \ +- static SYSDEV_ATTR(_name, 0444, \ +- therm_throt_sysdev_show_##_name, \ ++#define define_therm_throt_device_one_ro(_name) \ ++ static DEVICE_ATTR(_name, 0444, \ ++ therm_throt_device_show_##_name, \ + NULL) \ + +-#define define_therm_throt_sysdev_show_func(event, name) \ ++#define define_therm_throt_device_show_func(event, name) \ + \ +-static ssize_t therm_throt_sysdev_show_##event##_##name( \ +- struct sys_device *dev, \ +- struct sysdev_attribute *attr, \ ++static ssize_t therm_throt_device_show_##event##_##name( \ ++ struct device *dev, \ ++ struct device_attribute *attr, \ + char *buf) \ + { \ + unsigned int cpu = dev->id; \ +@@ -95,20 +94,20 @@ static ssize_t therm_throt_sysdev_show_# + return ret; \ + } + +-define_therm_throt_sysdev_show_func(core_throttle, count); +-define_therm_throt_sysdev_one_ro(core_throttle_count); ++define_therm_throt_device_show_func(core_throttle, count); ++define_therm_throt_device_one_ro(core_throttle_count); + +-define_therm_throt_sysdev_show_func(core_power_limit, count); +-define_therm_throt_sysdev_one_ro(core_power_limit_count); ++define_therm_throt_device_show_func(core_power_limit, count); ++define_therm_throt_device_one_ro(core_power_limit_count); + +-define_therm_throt_sysdev_show_func(package_throttle, count); +-define_therm_throt_sysdev_one_ro(package_throttle_count); ++define_therm_throt_device_show_func(package_throttle, count); ++define_therm_throt_device_one_ro(package_throttle_count); + +-define_therm_throt_sysdev_show_func(package_power_limit, count); +-define_therm_throt_sysdev_one_ro(package_power_limit_count); ++define_therm_throt_device_show_func(package_power_limit, count); ++define_therm_throt_device_one_ro(package_power_limit_count); + + static struct attribute *thermal_throttle_attrs[] = { +- &attr_core_throttle_count.attr, ++ &dev_attr_core_throttle_count.attr, + NULL + }; + +@@ -223,36 +222,36 @@ static int thresh_event_valid(int event) + + #ifdef CONFIG_SYSFS + /* Add/Remove thermal_throttle interface for CPU device: */ +-static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev, ++static __cpuinit int thermal_throttle_add_dev(struct device *dev, + unsigned int cpu) + { + int err; + struct cpuinfo_x86 *c = &cpu_data(cpu); + +- err = sysfs_create_group(&sys_dev->kobj, &thermal_attr_group); ++ err = sysfs_create_group(&dev->kobj, &thermal_attr_group); + if (err) + return err; + + if (cpu_has(c, X86_FEATURE_PLN)) +- err = sysfs_add_file_to_group(&sys_dev->kobj, +- &attr_core_power_limit_count.attr, ++ err = sysfs_add_file_to_group(&dev->kobj, ++ &dev_attr_core_power_limit_count.attr, + thermal_attr_group.name); + if (cpu_has(c, X86_FEATURE_PTS)) { +- err = sysfs_add_file_to_group(&sys_dev->kobj, +- &attr_package_throttle_count.attr, ++ err = sysfs_add_file_to_group(&dev->kobj, ++ &dev_attr_package_throttle_count.attr, + thermal_attr_group.name); + if (cpu_has(c, X86_FEATURE_PLN)) +- err = sysfs_add_file_to_group(&sys_dev->kobj, +- &attr_package_power_limit_count.attr, ++ err = sysfs_add_file_to_group(&dev->kobj, ++ &dev_attr_package_power_limit_count.attr, + thermal_attr_group.name); + } + + return err; + } + +-static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev) ++static __cpuinit void thermal_throttle_remove_dev(struct device *dev) + { +- sysfs_remove_group(&sys_dev->kobj, &thermal_attr_group); ++ sysfs_remove_group(&dev->kobj, &thermal_attr_group); + } + + /* Mutex protecting device creation against CPU hotplug: */ +@@ -265,16 +264,16 @@ thermal_throttle_cpu_callback(struct not + void *hcpu) + { + unsigned int cpu = (unsigned long)hcpu; +- struct sys_device *sys_dev; ++ struct device *dev; + int err = 0; + +- sys_dev = get_cpu_sysdev(cpu); ++ dev = get_cpu_device(cpu); + + switch (action) { + case CPU_UP_PREPARE: + case CPU_UP_PREPARE_FROZEN: + mutex_lock(&therm_cpu_lock); +- err = thermal_throttle_add_dev(sys_dev, cpu); ++ err = thermal_throttle_add_dev(dev, cpu); + mutex_unlock(&therm_cpu_lock); + WARN_ON(err); + break; +@@ -283,7 +282,7 @@ thermal_throttle_cpu_callback(struct not + case CPU_DEAD: + case CPU_DEAD_FROZEN: + mutex_lock(&therm_cpu_lock); +- thermal_throttle_remove_dev(sys_dev); ++ thermal_throttle_remove_dev(dev); + mutex_unlock(&therm_cpu_lock); + break; + } +@@ -310,7 +309,7 @@ static __init int thermal_throttle_init_ + #endif + /* connect live CPUs to sysfs */ + for_each_online_cpu(cpu) { +- err = thermal_throttle_add_dev(get_cpu_sysdev(cpu), cpu); ++ err = thermal_throttle_add_dev(get_cpu_device(cpu), cpu); + WARN_ON(err); + } + #ifdef CONFIG_HOTPLUG_CPU +--- a/arch/x86/kernel/microcode_core.c ++++ b/arch/x86/kernel/microcode_core.c +@@ -292,8 +292,8 @@ static int reload_for_cpu(int cpu) + return err; + } + +-static ssize_t reload_store(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t reload_store(struct device *dev, ++ struct device_attribute *attr, + const char *buf, size_t size) + { + unsigned long val; +@@ -318,30 +318,30 @@ static ssize_t reload_store(struct sys_d + return ret; + } + +-static ssize_t version_show(struct sys_device *dev, +- struct sysdev_attribute *attr, char *buf) ++static ssize_t version_show(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; + + return sprintf(buf, "0x%x\n", uci->cpu_sig.rev); + } + +-static ssize_t pf_show(struct sys_device *dev, +- struct sysdev_attribute *attr, char *buf) ++static ssize_t pf_show(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; + + return sprintf(buf, "0x%x\n", uci->cpu_sig.pf); + } + +-static SYSDEV_ATTR(reload, 0200, NULL, reload_store); +-static SYSDEV_ATTR(version, 0400, version_show, NULL); +-static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL); ++static DEVICE_ATTR(reload, 0200, NULL, reload_store); ++static DEVICE_ATTR(version, 0400, version_show, NULL); ++static DEVICE_ATTR(processor_flags, 0400, pf_show, NULL); + + static struct attribute *mc_default_attrs[] = { +- &attr_reload.attr, +- &attr_version.attr, +- &attr_processor_flags.attr, ++ &dev_attr_reload.attr, ++ &dev_attr_version.attr, ++ &dev_attr_processor_flags.attr, + NULL + }; + +@@ -405,43 +405,45 @@ static enum ucode_state microcode_update + return ustate; + } + +-static int mc_sysdev_add(struct sys_device *sys_dev) ++static int mc_device_add(struct device *dev, struct subsys_interface *sif) + { +- int err, cpu = sys_dev->id; ++ int err, cpu = dev->id; + + if (!cpu_online(cpu)) + return 0; + + pr_debug("CPU%d added\n", cpu); + +- err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group); ++ err = sysfs_create_group(&dev->kobj, &mc_attr_group); + if (err) + return err; + + if (microcode_init_cpu(cpu) == UCODE_ERROR) { +- sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); ++ sysfs_remove_group(&dev->kobj, &mc_attr_group); + return -EINVAL; + } + + return err; + } + +-static int mc_sysdev_remove(struct sys_device *sys_dev) ++static int mc_device_remove(struct device *dev, struct subsys_interface *sif) + { +- int cpu = sys_dev->id; ++ int cpu = dev->id; + + if (!cpu_online(cpu)) + return 0; + + pr_debug("CPU%d removed\n", cpu); + microcode_fini_cpu(cpu); +- sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); ++ sysfs_remove_group(&dev->kobj, &mc_attr_group); + return 0; + } + +-static struct sysdev_driver mc_sysdev_driver = { +- .add = mc_sysdev_add, +- .remove = mc_sysdev_remove, ++static struct subsys_interface mc_cpu_interface = { ++ .name = "microcode", ++ .subsys = &cpu_subsys, ++ .add_dev = mc_device_add, ++ .remove_dev = mc_device_remove, + }; + + /** +@@ -464,9 +466,9 @@ static __cpuinit int + mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) + { + unsigned int cpu = (unsigned long)hcpu; +- struct sys_device *sys_dev; ++ struct device *dev; + +- sys_dev = get_cpu_sysdev(cpu); ++ dev = get_cpu_device(cpu); + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: +@@ -474,13 +476,13 @@ mc_cpu_callback(struct notifier_block *n + case CPU_DOWN_FAILED: + case CPU_DOWN_FAILED_FROZEN: + pr_debug("CPU%d added\n", cpu); +- if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group)) ++ if (sysfs_create_group(&dev->kobj, &mc_attr_group)) + pr_err("Failed to create group for CPU%d\n", cpu); + break; + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: + /* Suspend is in progress, only remove the interface */ +- sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); ++ sysfs_remove_group(&dev->kobj, &mc_attr_group); + pr_debug("CPU%d removed\n", cpu); + break; + +@@ -525,7 +527,7 @@ static int __init microcode_init(void) + get_online_cpus(); + mutex_lock(µcode_mutex); + +- error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver); ++ error = subsys_interface_register(&mc_cpu_interface); + + mutex_unlock(µcode_mutex); + put_online_cpus(); +@@ -535,7 +537,7 @@ static int __init microcode_init(void) + + error = microcode_dev_init(); + if (error) +- goto out_sysdev_driver; ++ goto out_subsys_interface; + + register_syscore_ops(&mc_syscore_ops); + register_hotcpu_notifier(&mc_cpu_notifier); +@@ -545,11 +547,11 @@ static int __init microcode_init(void) + + return 0; + +-out_sysdev_driver: ++out_subsys_interface: + get_online_cpus(); + mutex_lock(µcode_mutex); + +- sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver); ++ subsys_interface_unregister(&mc_cpu_interface); + + mutex_unlock(µcode_mutex); + put_online_cpus(); +@@ -571,7 +573,7 @@ static void __exit microcode_exit(void) + get_online_cpus(); + mutex_lock(µcode_mutex); + +- sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver); ++ subsys_interface_unregister(&mc_cpu_interface); + + mutex_unlock(µcode_mutex); + put_online_cpus(); +--- a/drivers/acpi/processor_driver.c ++++ b/drivers/acpi/processor_driver.c +@@ -446,7 +446,7 @@ static int __cpuinit acpi_processor_add( + { + struct acpi_processor *pr = NULL; + int result = 0; +- struct sys_device *sysdev; ++ struct device *dev; + + pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); + if (!pr) +@@ -491,8 +491,8 @@ static int __cpuinit acpi_processor_add( + + per_cpu(processors, pr->id) = pr; + +- sysdev = get_cpu_sysdev(pr->id); +- if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) { ++ dev = get_cpu_device(pr->id); ++ if (sysfs_create_link(&device->dev.kobj, &dev->kobj, "sysdev")) { + result = -EFAULT; + goto err_free_cpumask; + } +--- a/drivers/acpi/processor_thermal.c ++++ b/drivers/acpi/processor_thermal.c +@@ -30,7 +30,6 @@ + #include <linux/module.h> + #include <linux/init.h> + #include <linux/cpufreq.h> +-#include <linux/sysdev.h> + + #include <asm/uaccess.h> + +--- a/drivers/base/cpu.c ++++ b/drivers/base/cpu.c +@@ -1,8 +1,7 @@ + /* +- * drivers/base/cpu.c - basic CPU class support ++ * CPU subsystem support + */ + +-#include <linux/sysdev.h> + #include <linux/module.h> + #include <linux/init.h> + #include <linux/sched.h> +@@ -14,40 +13,40 @@ + + #include "base.h" + +-static struct sysdev_class_attribute *cpu_sysdev_class_attrs[]; +- +-struct sysdev_class cpu_sysdev_class = { ++struct bus_type cpu_subsys = { + .name = "cpu", +- .attrs = cpu_sysdev_class_attrs, ++ .dev_name = "cpu", + }; +-EXPORT_SYMBOL(cpu_sysdev_class); ++EXPORT_SYMBOL_GPL(cpu_subsys); + +-static DEFINE_PER_CPU(struct sys_device *, cpu_sys_devices); ++static DEFINE_PER_CPU(struct device *, cpu_sys_devices); + + #ifdef CONFIG_HOTPLUG_CPU +-static ssize_t show_online(struct sys_device *dev, struct sysdev_attribute *attr, ++static ssize_t show_online(struct device *dev, ++ struct device_attribute *attr, + char *buf) + { +- struct cpu *cpu = container_of(dev, struct cpu, sysdev); ++ struct cpu *cpu = container_of(dev, struct cpu, dev); + +- return sprintf(buf, "%u\n", !!cpu_online(cpu->sysdev.id)); ++ return sprintf(buf, "%u\n", !!cpu_online(cpu->dev.id)); + } + +-static ssize_t __ref store_online(struct sys_device *dev, struct sysdev_attribute *attr, +- const char *buf, size_t count) ++static ssize_t __ref store_online(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) + { +- struct cpu *cpu = container_of(dev, struct cpu, sysdev); ++ struct cpu *cpu = container_of(dev, struct cpu, dev); + ssize_t ret; + + cpu_hotplug_driver_lock(); + switch (buf[0]) { + case '0': +- ret = cpu_down(cpu->sysdev.id); ++ ret = cpu_down(cpu->dev.id); + if (!ret) + kobject_uevent(&dev->kobj, KOBJ_OFFLINE); + break; + case '1': +- ret = cpu_up(cpu->sysdev.id); ++ ret = cpu_up(cpu->dev.id); + if (!ret) + kobject_uevent(&dev->kobj, KOBJ_ONLINE); + break; +@@ -60,44 +59,44 @@ static ssize_t __ref store_online(struct + ret = count; + return ret; + } +-static SYSDEV_ATTR(online, 0644, show_online, store_online); ++static DEVICE_ATTR(online, 0644, show_online, store_online); + + static void __cpuinit register_cpu_control(struct cpu *cpu) + { +- sysdev_create_file(&cpu->sysdev, &attr_online); ++ device_create_file(&cpu->dev, &dev_attr_online); + } + void unregister_cpu(struct cpu *cpu) + { +- int logical_cpu = cpu->sysdev.id; ++ int logical_cpu = cpu->dev.id; + + unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); + +- sysdev_remove_file(&cpu->sysdev, &attr_online); ++ device_remove_file(&cpu->dev, &dev_attr_online); + +- sysdev_unregister(&cpu->sysdev); ++ device_unregister(&cpu->dev); + per_cpu(cpu_sys_devices, logical_cpu) = NULL; + return; + } + + #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE +-static ssize_t cpu_probe_store(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, ++static ssize_t cpu_probe_store(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { + return arch_cpu_probe(buf, count); + } + +-static ssize_t cpu_release_store(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, ++static ssize_t cpu_release_store(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { + return arch_cpu_release(buf, count); + } + +-static SYSDEV_CLASS_ATTR(probe, S_IWUSR, NULL, cpu_probe_store); +-static SYSDEV_CLASS_ATTR(release, S_IWUSR, NULL, cpu_release_store); ++static DEVICE_ATTR(probe, S_IWUSR, NULL, cpu_probe_store); ++static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); + #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ + + #else /* ... !CONFIG_HOTPLUG_CPU */ +@@ -109,15 +108,15 @@ static inline void register_cpu_control( + #ifdef CONFIG_KEXEC + #include <linux/kexec.h> + +-static ssize_t show_crash_notes(struct sys_device *dev, struct sysdev_attribute *attr, ++static ssize_t show_crash_notes(struct device *dev, struct device_attribute *attr, + char *buf) + { +- struct cpu *cpu = container_of(dev, struct cpu, sysdev); ++ struct cpu *cpu = container_of(dev, struct cpu, dev); + ssize_t rc; + unsigned long long addr; + int cpunum; + +- cpunum = cpu->sysdev.id; ++ cpunum = cpu->dev.id; + + /* + * Might be reading other cpu's data based on which cpu read thread +@@ -129,7 +128,7 @@ static ssize_t show_crash_notes(struct s + rc = sprintf(buf, "%Lx\n", addr); + return rc; + } +-static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL); ++static DEVICE_ATTR(crash_notes, 0400, show_crash_notes, NULL); + #endif + + /* +@@ -137,12 +136,12 @@ static SYSDEV_ATTR(crash_notes, 0400, sh + */ + + struct cpu_attr { +- struct sysdev_class_attribute attr; ++ struct device_attribute attr; + const struct cpumask *const * const map; + }; + +-static ssize_t show_cpus_attr(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, ++static ssize_t show_cpus_attr(struct device *dev, ++ struct device_attribute *attr, + char *buf) + { + struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr); +@@ -153,10 +152,10 @@ static ssize_t show_cpus_attr(struct sys + return n; + } + +-#define _CPU_ATTR(name, map) \ +- { _SYSDEV_CLASS_ATTR(name, 0444, show_cpus_attr, NULL), map } ++#define _CPU_ATTR(name, map) \ ++ { __ATTR(name, 0444, show_cpus_attr, NULL), map } + +-/* Keep in sync with cpu_sysdev_class_attrs */ ++/* Keep in sync with cpu_subsys_attrs */ + static struct cpu_attr cpu_attrs[] = { + _CPU_ATTR(online, &cpu_online_mask), + _CPU_ATTR(possible, &cpu_possible_mask), +@@ -166,19 +165,19 @@ static struct cpu_attr cpu_attrs[] = { + /* + * Print values for NR_CPUS and offlined cpus + */ +-static ssize_t print_cpus_kernel_max(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, char *buf) ++static ssize_t print_cpus_kernel_max(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1); + return n; + } +-static SYSDEV_CLASS_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL); ++static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL); + + /* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */ + unsigned int total_cpus; + +-static ssize_t print_cpus_offline(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, char *buf) ++static ssize_t print_cpus_offline(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + int n = 0, len = PAGE_SIZE-2; + cpumask_var_t offline; +@@ -205,7 +204,7 @@ static ssize_t print_cpus_offline(struct + n += snprintf(&buf[n], len - n, "\n"); + return n; + } +-static SYSDEV_CLASS_ATTR(offline, 0444, print_cpus_offline, NULL); ++static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); + + /* + * register_cpu - Setup a sysfs device for a CPU. +@@ -218,57 +217,66 @@ static SYSDEV_CLASS_ATTR(offline, 0444, + int __cpuinit register_cpu(struct cpu *cpu, int num) + { + int error; +- cpu->node_id = cpu_to_node(num); +- cpu->sysdev.id = num; +- cpu->sysdev.cls = &cpu_sysdev_class; +- +- error = sysdev_register(&cpu->sysdev); + ++ cpu->node_id = cpu_to_node(num); ++ cpu->dev.id = num; ++ cpu->dev.bus = &cpu_subsys; ++ error = device_register(&cpu->dev); + if (!error && cpu->hotpluggable) + register_cpu_control(cpu); + if (!error) +- per_cpu(cpu_sys_devices, num) = &cpu->sysdev; ++ per_cpu(cpu_sys_devices, num) = &cpu->dev; + if (!error) + register_cpu_under_node(num, cpu_to_node(num)); + + #ifdef CONFIG_KEXEC + if (!error) +- error = sysdev_create_file(&cpu->sysdev, &attr_crash_notes); ++ error = device_create_file(&cpu->dev, &dev_attr_crash_notes); + #endif + return error; + } + +-struct sys_device *get_cpu_sysdev(unsigned cpu) ++struct device *get_cpu_device(unsigned cpu) + { + if (cpu < nr_cpu_ids && cpu_possible(cpu)) + return per_cpu(cpu_sys_devices, cpu); + else + return NULL; + } +-EXPORT_SYMBOL_GPL(get_cpu_sysdev); ++EXPORT_SYMBOL_GPL(get_cpu_device); ++ ++static struct attribute *cpu_root_attrs[] = { ++#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE ++ &dev_attr_probe.attr, ++ &dev_attr_release.attr, ++#endif ++ &cpu_attrs[0].attr.attr, ++ &cpu_attrs[1].attr.attr, ++ &cpu_attrs[2].attr.attr, ++ &dev_attr_kernel_max.attr, ++ &dev_attr_offline.attr, ++ NULL ++}; ++ ++static struct attribute_group cpu_root_attr_group = { ++ .attrs = cpu_root_attrs, ++}; ++ ++static const struct attribute_group *cpu_root_attr_groups[] = { ++ &cpu_root_attr_group, ++ NULL, ++}; + + int __init cpu_dev_init(void) + { + int err; + +- err = sysdev_class_register(&cpu_sysdev_class); ++ err = subsys_system_register(&cpu_subsys, cpu_root_attr_groups); ++ if (err) ++ return err; ++ + #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) +- if (!err) +- err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class); ++ err = sched_create_sysfs_power_savings_entries(cpu_subsys.dev_root); + #endif +- + return err; + } +- +-static struct sysdev_class_attribute *cpu_sysdev_class_attrs[] = { +-#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE +- &attr_probe, +- &attr_release, +-#endif +- &cpu_attrs[0].attr, +- &cpu_attrs[1].attr, +- &cpu_attrs[2].attr, +- &attr_kernel_max, +- &attr_offline, +- NULL +-}; +--- a/drivers/base/node.c ++++ b/drivers/base/node.c +@@ -317,12 +317,12 @@ struct node node_devices[MAX_NUMNODES]; + int register_cpu_under_node(unsigned int cpu, unsigned int nid) + { + int ret; +- struct sys_device *obj; ++ struct device *obj; + + if (!node_online(nid)) + return 0; + +- obj = get_cpu_sysdev(cpu); ++ obj = get_cpu_device(cpu); + if (!obj) + return 0; + +@@ -339,12 +339,12 @@ int register_cpu_under_node(unsigned int + + int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) + { +- struct sys_device *obj; ++ struct device *obj; + + if (!node_online(nid)) + return 0; + +- obj = get_cpu_sysdev(cpu); ++ obj = get_cpu_device(cpu); + if (!obj) + return 0; + +--- a/drivers/base/topology.c ++++ b/drivers/base/topology.c +@@ -23,7 +23,6 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +-#include <linux/sysdev.h> + #include <linux/init.h> + #include <linux/mm.h> + #include <linux/cpu.h> +@@ -32,14 +31,14 @@ + #include <linux/topology.h> + + #define define_one_ro_named(_name, _func) \ +-static SYSDEV_ATTR(_name, 0444, _func, NULL) ++ static DEVICE_ATTR(_name, 0444, _func, NULL) + + #define define_one_ro(_name) \ +-static SYSDEV_ATTR(_name, 0444, show_##_name, NULL) ++ static DEVICE_ATTR(_name, 0444, show_##_name, NULL) + + #define define_id_show_func(name) \ +-static ssize_t show_##name(struct sys_device *dev, \ +- struct sysdev_attribute *attr, char *buf) \ ++static ssize_t show_##name(struct device *dev, \ ++ struct device_attribute *attr, char *buf) \ + { \ + unsigned int cpu = dev->id; \ + return sprintf(buf, "%d\n", topology_##name(cpu)); \ +@@ -65,16 +64,16 @@ static ssize_t show_cpumap(int type, con + + #ifdef arch_provides_topology_pointers + #define define_siblings_show_map(name) \ +-static ssize_t show_##name(struct sys_device *dev, \ +- struct sysdev_attribute *attr, char *buf) \ ++static ssize_t show_##name(struct device *dev, \ ++ struct device_attribute *attr, char *buf) \ + { \ + unsigned int cpu = dev->id; \ + return show_cpumap(0, topology_##name(cpu), buf); \ + } + + #define define_siblings_show_list(name) \ +-static ssize_t show_##name##_list(struct sys_device *dev, \ +- struct sysdev_attribute *attr, \ ++static ssize_t show_##name##_list(struct device *dev, \ ++ struct device_attribute *attr, \ + char *buf) \ + { \ + unsigned int cpu = dev->id; \ +@@ -83,15 +82,15 @@ static ssize_t show_##name##_list(struct + + #else + #define define_siblings_show_map(name) \ +-static ssize_t show_##name(struct sys_device *dev, \ +- struct sysdev_attribute *attr, char *buf) \ ++static ssize_t show_##name(struct device *dev, \ ++ struct device_attribute *attr, char *buf) \ + { \ + return show_cpumap(0, topology_##name(dev->id), buf); \ + } + + #define define_siblings_show_list(name) \ +-static ssize_t show_##name##_list(struct sys_device *dev, \ +- struct sysdev_attribute *attr, \ ++static ssize_t show_##name##_list(struct device *dev, \ ++ struct device_attribute *attr, \ + char *buf) \ + { \ + return show_cpumap(1, topology_##name(dev->id), buf); \ +@@ -124,16 +123,16 @@ define_one_ro_named(book_siblings_list, + #endif + + static struct attribute *default_attrs[] = { +- &attr_physical_package_id.attr, +- &attr_core_id.attr, +- &attr_thread_siblings.attr, +- &attr_thread_siblings_list.attr, +- &attr_core_siblings.attr, +- &attr_core_siblings_list.attr, ++ &dev_attr_physical_package_id.attr, ++ &dev_attr_core_id.attr, ++ &dev_attr_thread_siblings.attr, ++ &dev_attr_thread_siblings_list.attr, ++ &dev_attr_core_siblings.attr, ++ &dev_attr_core_siblings_list.attr, + #ifdef CONFIG_SCHED_BOOK +- &attr_book_id.attr, +- &attr_book_siblings.attr, +- &attr_book_siblings_list.attr, ++ &dev_attr_book_id.attr, ++ &dev_attr_book_siblings.attr, ++ &dev_attr_book_siblings_list.attr, + #endif + NULL + }; +@@ -146,16 +145,16 @@ static struct attribute_group topology_a + /* Add/Remove cpu_topology interface for CPU device */ + static int __cpuinit topology_add_dev(unsigned int cpu) + { +- struct sys_device *sys_dev = get_cpu_sysdev(cpu); ++ struct device *dev = get_cpu_device(cpu); + +- return sysfs_create_group(&sys_dev->kobj, &topology_attr_group); ++ return sysfs_create_group(&dev->kobj, &topology_attr_group); + } + + static void __cpuinit topology_remove_dev(unsigned int cpu) + { +- struct sys_device *sys_dev = get_cpu_sysdev(cpu); ++ struct device *dev = get_cpu_device(cpu); + +- sysfs_remove_group(&sys_dev->kobj, &topology_attr_group); ++ sysfs_remove_group(&dev->kobj, &topology_attr_group); + } + + static int __cpuinit topology_cpu_callback(struct notifier_block *nfb, +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -679,7 +679,7 @@ static struct kobj_type ktype_cpufreq = + */ + static int cpufreq_add_dev_policy(unsigned int cpu, + struct cpufreq_policy *policy, +- struct sys_device *sys_dev) ++ struct device *dev) + { + int ret = 0; + #ifdef CONFIG_SMP +@@ -728,7 +728,7 @@ static int cpufreq_add_dev_policy(unsign + spin_unlock_irqrestore(&cpufreq_driver_lock, flags); + + pr_debug("CPU already managed, adding link\n"); +- ret = sysfs_create_link(&sys_dev->kobj, ++ ret = sysfs_create_link(&dev->kobj, + &managed_policy->kobj, + "cpufreq"); + if (ret) +@@ -761,7 +761,7 @@ static int cpufreq_add_dev_symlink(unsig + + for_each_cpu(j, policy->cpus) { + struct cpufreq_policy *managed_policy; +- struct sys_device *cpu_sys_dev; ++ struct device *cpu_dev; + + if (j == cpu) + continue; +@@ -770,8 +770,8 @@ static int cpufreq_add_dev_symlink(unsig + + pr_debug("CPU %u already managed, adding link\n", j); + managed_policy = cpufreq_cpu_get(cpu); +- cpu_sys_dev = get_cpu_sysdev(j); +- ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj, ++ cpu_dev = get_cpu_device(j); ++ ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, + "cpufreq"); + if (ret) { + cpufreq_cpu_put(managed_policy); +@@ -783,7 +783,7 @@ static int cpufreq_add_dev_symlink(unsig + + static int cpufreq_add_dev_interface(unsigned int cpu, + struct cpufreq_policy *policy, +- struct sys_device *sys_dev) ++ struct device *dev) + { + struct cpufreq_policy new_policy; + struct freq_attr **drv_attr; +@@ -793,7 +793,7 @@ static int cpufreq_add_dev_interface(uns + + /* prepare interface data */ + ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, +- &sys_dev->kobj, "cpufreq"); ++ &dev->kobj, "cpufreq"); + if (ret) + return ret; + +@@ -866,9 +866,9 @@ err_out_kobj_put: + * with with cpu hotplugging and all hell will break loose. Tried to clean this + * mess up, but more thorough testing is needed. - Mathieu + */ +-static int cpufreq_add_dev(struct sys_device *sys_dev) ++static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) + { +- unsigned int cpu = sys_dev->id; ++ unsigned int cpu = dev->id; + int ret = 0, found = 0; + struct cpufreq_policy *policy; + unsigned long flags; +@@ -947,7 +947,7 @@ static int cpufreq_add_dev(struct sys_de + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_START, policy); + +- ret = cpufreq_add_dev_policy(cpu, policy, sys_dev); ++ ret = cpufreq_add_dev_policy(cpu, policy, dev); + if (ret) { + if (ret > 0) + /* This is a managed cpu, symlink created, +@@ -956,7 +956,7 @@ static int cpufreq_add_dev(struct sys_de + goto err_unlock_policy; + } + +- ret = cpufreq_add_dev_interface(cpu, policy, sys_dev); ++ ret = cpufreq_add_dev_interface(cpu, policy, dev); + if (ret) + goto err_out_unregister; + +@@ -999,15 +999,15 @@ module_out: + * Caller should already have policy_rwsem in write mode for this CPU. + * This routine frees the rwsem before returning. + */ +-static int __cpufreq_remove_dev(struct sys_device *sys_dev) ++static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) + { +- unsigned int cpu = sys_dev->id; ++ unsigned int cpu = dev->id; + unsigned long flags; + struct cpufreq_policy *data; + struct kobject *kobj; + struct completion *cmp; + #ifdef CONFIG_SMP +- struct sys_device *cpu_sys_dev; ++ struct device *cpu_dev; + unsigned int j; + #endif + +@@ -1032,7 +1032,7 @@ static int __cpufreq_remove_dev(struct s + pr_debug("removing link\n"); + cpumask_clear_cpu(cpu, data->cpus); + spin_unlock_irqrestore(&cpufreq_driver_lock, flags); +- kobj = &sys_dev->kobj; ++ kobj = &dev->kobj; + cpufreq_cpu_put(data); + unlock_policy_rwsem_write(cpu); + sysfs_remove_link(kobj, "cpufreq"); +@@ -1071,8 +1071,8 @@ static int __cpufreq_remove_dev(struct s + strncpy(per_cpu(cpufreq_cpu_governor, j), + data->governor->name, CPUFREQ_NAME_LEN); + #endif +- cpu_sys_dev = get_cpu_sysdev(j); +- kobj = &cpu_sys_dev->kobj; ++ cpu_dev = get_cpu_device(j); ++ kobj = &cpu_dev->kobj; + unlock_policy_rwsem_write(cpu); + sysfs_remove_link(kobj, "cpufreq"); + lock_policy_rwsem_write(cpu); +@@ -1112,11 +1112,11 @@ static int __cpufreq_remove_dev(struct s + if (unlikely(cpumask_weight(data->cpus) > 1)) { + /* first sibling now owns the new sysfs dir */ + cpumask_clear_cpu(cpu, data->cpus); +- cpufreq_add_dev(get_cpu_sysdev(cpumask_first(data->cpus))); ++ cpufreq_add_dev(get_cpu_device(cpumask_first(data->cpus)), NULL); + + /* finally remove our own symlink */ + lock_policy_rwsem_write(cpu); +- __cpufreq_remove_dev(sys_dev); ++ __cpufreq_remove_dev(dev, sif); + } + #endif + +@@ -1128,9 +1128,9 @@ static int __cpufreq_remove_dev(struct s + } + + +-static int cpufreq_remove_dev(struct sys_device *sys_dev) ++static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) + { +- unsigned int cpu = sys_dev->id; ++ unsigned int cpu = dev->id; + int retval; + + if (cpu_is_offline(cpu)) +@@ -1139,7 +1139,7 @@ static int cpufreq_remove_dev(struct sys + if (unlikely(lock_policy_rwsem_write(cpu))) + BUG(); + +- retval = __cpufreq_remove_dev(sys_dev); ++ retval = __cpufreq_remove_dev(dev, sif); + return retval; + } + +@@ -1271,9 +1271,11 @@ out: + } + EXPORT_SYMBOL(cpufreq_get); + +-static struct sysdev_driver cpufreq_sysdev_driver = { +- .add = cpufreq_add_dev, +- .remove = cpufreq_remove_dev, ++static struct subsys_interface cpufreq_interface = { ++ .name = "cpufreq", ++ .subsys = &cpu_subsys, ++ .add_dev = cpufreq_add_dev, ++ .remove_dev = cpufreq_remove_dev, + }; + + +@@ -1765,25 +1767,25 @@ static int __cpuinit cpufreq_cpu_callbac + unsigned long action, void *hcpu) + { + unsigned int cpu = (unsigned long)hcpu; +- struct sys_device *sys_dev; ++ struct device *dev; + +- sys_dev = get_cpu_sysdev(cpu); +- if (sys_dev) { ++ dev = get_cpu_device(cpu); ++ if (dev) { + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: +- cpufreq_add_dev(sys_dev); ++ cpufreq_add_dev(dev, NULL); + break; + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: + if (unlikely(lock_policy_rwsem_write(cpu))) + BUG(); + +- __cpufreq_remove_dev(sys_dev); ++ __cpufreq_remove_dev(dev, NULL); + break; + case CPU_DOWN_FAILED: + case CPU_DOWN_FAILED_FROZEN: +- cpufreq_add_dev(sys_dev); ++ cpufreq_add_dev(dev, NULL); + break; + } + } +@@ -1830,8 +1832,7 @@ int cpufreq_register_driver(struct cpufr + cpufreq_driver = driver_data; + spin_unlock_irqrestore(&cpufreq_driver_lock, flags); + +- ret = sysdev_driver_register(&cpu_sysdev_class, +- &cpufreq_sysdev_driver); ++ ret = subsys_interface_register(&cpufreq_interface); + if (ret) + goto err_null_driver; + +@@ -1850,7 +1851,7 @@ int cpufreq_register_driver(struct cpufr + if (ret) { + pr_debug("no CPU initialized for driver %s\n", + driver_data->name); +- goto err_sysdev_unreg; ++ goto err_if_unreg; + } + } + +@@ -1858,9 +1859,8 @@ int cpufreq_register_driver(struct cpufr + pr_debug("driver %s up and running\n", driver_data->name); + + return 0; +-err_sysdev_unreg: +- sysdev_driver_unregister(&cpu_sysdev_class, +- &cpufreq_sysdev_driver); ++err_if_unreg: ++ subsys_interface_unregister(&cpufreq_interface); + err_null_driver: + spin_lock_irqsave(&cpufreq_driver_lock, flags); + cpufreq_driver = NULL; +@@ -1887,7 +1887,7 @@ int cpufreq_unregister_driver(struct cpu + + pr_debug("unregistering driver %s\n", driver->name); + +- sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver); ++ subsys_interface_unregister(&cpufreq_interface); + unregister_hotcpu_notifier(&cpufreq_cpu_notifier); + + spin_lock_irqsave(&cpufreq_driver_lock, flags); +@@ -1907,8 +1907,7 @@ static int __init cpufreq_core_init(void + init_rwsem(&per_cpu(cpu_policy_rwsem, cpu)); + } + +- cpufreq_global_kobject = kobject_create_and_add("cpufreq", +- &cpu_sysdev_class.kset.kobj); ++ cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj); + BUG_ON(!cpufreq_global_kobject); + register_syscore_ops(&cpufreq_syscore_ops); + +--- a/drivers/cpufreq/cpufreq_stats.c ++++ b/drivers/cpufreq/cpufreq_stats.c +@@ -11,7 +11,6 @@ + + #include <linux/kernel.h> + #include <linux/slab.h> +-#include <linux/sysdev.h> + #include <linux/cpu.h> + #include <linux/sysfs.h> + #include <linux/cpufreq.h> +--- a/drivers/cpuidle/cpuidle.c ++++ b/drivers/cpuidle/cpuidle.c +@@ -291,10 +291,10 @@ EXPORT_SYMBOL_GPL(cpuidle_disable_device + static int __cpuidle_register_device(struct cpuidle_device *dev) + { + int ret; +- struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); ++ struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); + struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); + +- if (!sys_dev) ++ if (!dev) + return -EINVAL; + if (!try_module_get(cpuidle_driver->owner)) + return -EINVAL; +@@ -303,7 +303,7 @@ static int __cpuidle_register_device(str + + per_cpu(cpuidle_devices, dev->cpu) = dev; + list_add(&dev->device_list, &cpuidle_detected_devices); +- if ((ret = cpuidle_add_sysfs(sys_dev))) { ++ if ((ret = cpuidle_add_sysfs(cpu_dev))) { + module_put(cpuidle_driver->owner); + return ret; + } +@@ -344,7 +344,7 @@ EXPORT_SYMBOL_GPL(cpuidle_register_devic + */ + void cpuidle_unregister_device(struct cpuidle_device *dev) + { +- struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); ++ struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); + struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); + + if (dev->registered == 0) +@@ -354,7 +354,7 @@ void cpuidle_unregister_device(struct cp + + cpuidle_disable_device(dev); + +- cpuidle_remove_sysfs(sys_dev); ++ cpuidle_remove_sysfs(cpu_dev); + list_del(&dev->device_list); + wait_for_completion(&dev->kobj_unregister); + per_cpu(cpuidle_devices, dev->cpu) = NULL; +@@ -411,7 +411,7 @@ static int __init cpuidle_init(void) + if (cpuidle_disabled()) + return -ENODEV; + +- ret = cpuidle_add_class_sysfs(&cpu_sysdev_class); ++ ret = cpuidle_add_interface(cpu_subsys.dev_root); + if (ret) + return ret; + +--- a/drivers/cpuidle/cpuidle.h ++++ b/drivers/cpuidle/cpuidle.h +@@ -5,7 +5,7 @@ + #ifndef __DRIVER_CPUIDLE_H + #define __DRIVER_CPUIDLE_H + +-#include <linux/sysdev.h> ++#include <linux/device.h> + + /* For internal use only */ + extern struct cpuidle_governor *cpuidle_curr_governor; +@@ -23,11 +23,11 @@ extern void cpuidle_uninstall_idle_handl + extern int cpuidle_switch_governor(struct cpuidle_governor *gov); + + /* sysfs */ +-extern int cpuidle_add_class_sysfs(struct sysdev_class *cls); +-extern void cpuidle_remove_class_sysfs(struct sysdev_class *cls); ++extern int cpuidle_add_interface(struct device *dev); ++extern void cpuidle_remove_interface(struct device *dev); + extern int cpuidle_add_state_sysfs(struct cpuidle_device *device); + extern void cpuidle_remove_state_sysfs(struct cpuidle_device *device); +-extern int cpuidle_add_sysfs(struct sys_device *sysdev); +-extern void cpuidle_remove_sysfs(struct sys_device *sysdev); ++extern int cpuidle_add_sysfs(struct device *dev); ++extern void cpuidle_remove_sysfs(struct device *dev); + + #endif /* __DRIVER_CPUIDLE_H */ +--- a/drivers/cpuidle/sysfs.c ++++ b/drivers/cpuidle/sysfs.c +@@ -22,8 +22,8 @@ static int __init cpuidle_sysfs_setup(ch + } + __setup("cpuidle_sysfs_switch", cpuidle_sysfs_setup); + +-static ssize_t show_available_governors(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, ++static ssize_t show_available_governors(struct device *dev, ++ struct device_attribute *attr, + char *buf) + { + ssize_t i = 0; +@@ -42,8 +42,8 @@ out: + return i; + } + +-static ssize_t show_current_driver(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, ++static ssize_t show_current_driver(struct device *dev, ++ struct device_attribute *attr, + char *buf) + { + ssize_t ret; +@@ -59,8 +59,8 @@ static ssize_t show_current_driver(struc + return ret; + } + +-static ssize_t show_current_governor(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, ++static ssize_t show_current_governor(struct device *dev, ++ struct device_attribute *attr, + char *buf) + { + ssize_t ret; +@@ -75,8 +75,8 @@ static ssize_t show_current_governor(str + return ret; + } + +-static ssize_t store_current_governor(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, ++static ssize_t store_current_governor(struct device *dev, ++ struct device_attribute *attr, + const char *buf, size_t count) + { + char gov_name[CPUIDLE_NAME_LEN]; +@@ -109,50 +109,48 @@ static ssize_t store_current_governor(st + return count; + } + +-static SYSDEV_CLASS_ATTR(current_driver, 0444, show_current_driver, NULL); +-static SYSDEV_CLASS_ATTR(current_governor_ro, 0444, show_current_governor, +- NULL); +- +-static struct attribute *cpuclass_default_attrs[] = { +- &attr_current_driver.attr, +- &attr_current_governor_ro.attr, ++static DEVICE_ATTR(current_driver, 0444, show_current_driver, NULL); ++static DEVICE_ATTR(current_governor_ro, 0444, show_current_governor, NULL); ++ ++static struct attribute *cpuidle_default_attrs[] = { ++ &dev_attr_current_driver.attr, ++ &dev_attr_current_governor_ro.attr, + NULL + }; + +-static SYSDEV_CLASS_ATTR(available_governors, 0444, show_available_governors, +- NULL); +-static SYSDEV_CLASS_ATTR(current_governor, 0644, show_current_governor, +- store_current_governor); +- +-static struct attribute *cpuclass_switch_attrs[] = { +- &attr_available_governors.attr, +- &attr_current_driver.attr, +- &attr_current_governor.attr, ++static DEVICE_ATTR(available_governors, 0444, show_available_governors, NULL); ++static DEVICE_ATTR(current_governor, 0644, show_current_governor, ++ store_current_governor); ++ ++static struct attribute *cpuidle_switch_attrs[] = { ++ &dev_attr_available_governors.attr, ++ &dev_attr_current_driver.attr, ++ &dev_attr_current_governor.attr, + NULL + }; + +-static struct attribute_group cpuclass_attr_group = { +- .attrs = cpuclass_default_attrs, ++static struct attribute_group cpuidle_attr_group = { ++ .attrs = cpuidle_default_attrs, + .name = "cpuidle", + }; + + /** +- * cpuidle_add_class_sysfs - add CPU global sysfs attributes ++ * cpuidle_add_interface - add CPU global sysfs attributes + */ +-int cpuidle_add_class_sysfs(struct sysdev_class *cls) ++int cpuidle_add_interface(struct device *dev) + { + if (sysfs_switch) +- cpuclass_attr_group.attrs = cpuclass_switch_attrs; ++ cpuidle_attr_group.attrs = cpuidle_switch_attrs; + +- return sysfs_create_group(&cls->kset.kobj, &cpuclass_attr_group); ++ return sysfs_create_group(&dev->kobj, &cpuidle_attr_group); + } + + /** +- * cpuidle_remove_class_sysfs - remove CPU global sysfs attributes ++ * cpuidle_remove_interface - remove CPU global sysfs attributes + */ +-void cpuidle_remove_class_sysfs(struct sysdev_class *cls) ++void cpuidle_remove_interface(struct device *dev) + { +- sysfs_remove_group(&cls->kset.kobj, &cpuclass_attr_group); ++ sysfs_remove_group(&dev->kobj, &cpuidle_attr_group); + } + + struct cpuidle_attr { +@@ -365,16 +363,16 @@ void cpuidle_remove_state_sysfs(struct c + + /** + * cpuidle_add_sysfs - creates a sysfs instance for the target device +- * @sysdev: the target device ++ * @dev: the target device + */ +-int cpuidle_add_sysfs(struct sys_device *sysdev) ++int cpuidle_add_sysfs(struct device *cpu_dev) + { +- int cpu = sysdev->id; ++ int cpu = cpu_dev->id; + struct cpuidle_device *dev; + int error; + + dev = per_cpu(cpuidle_devices, cpu); +- error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &sysdev->kobj, ++ error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj, + "cpuidle"); + if (!error) + kobject_uevent(&dev->kobj, KOBJ_ADD); +@@ -383,11 +381,11 @@ int cpuidle_add_sysfs(struct sys_device + + /** + * cpuidle_remove_sysfs - deletes a sysfs instance on the target device +- * @sysdev: the target device ++ * @dev: the target device + */ +-void cpuidle_remove_sysfs(struct sys_device *sysdev) ++void cpuidle_remove_sysfs(struct device *cpu_dev) + { +- int cpu = sysdev->id; ++ int cpu = cpu_dev->id; + struct cpuidle_device *dev; + + dev = per_cpu(cpuidle_devices, cpu); +--- a/include/linux/cpu.h ++++ b/include/linux/cpu.h +@@ -14,7 +14,7 @@ + #ifndef _LINUX_CPU_H_ + #define _LINUX_CPU_H_ + +-#include <linux/sysdev.h> ++#include <linux/device.h> + #include <linux/node.h> + #include <linux/compiler.h> + #include <linux/cpumask.h> +@@ -22,19 +22,19 @@ + struct cpu { + int node_id; /* The node which contains the CPU */ + int hotpluggable; /* creates sysfs control file if hotpluggable */ +- struct sys_device sysdev; ++ struct device dev; + }; + + extern int register_cpu(struct cpu *cpu, int num); +-extern struct sys_device *get_cpu_sysdev(unsigned cpu); ++extern struct device *get_cpu_device(unsigned cpu); + +-extern int cpu_add_sysdev_attr(struct sysdev_attribute *attr); +-extern void cpu_remove_sysdev_attr(struct sysdev_attribute *attr); ++extern int cpu_add_dev_attr(struct device_attribute *attr); ++extern void cpu_remove_dev_attr(struct device_attribute *attr); + +-extern int cpu_add_sysdev_attr_group(struct attribute_group *attrs); +-extern void cpu_remove_sysdev_attr_group(struct attribute_group *attrs); ++extern int cpu_add_dev_attr_group(struct attribute_group *attrs); ++extern void cpu_remove_dev_attr_group(struct attribute_group *attrs); + +-extern int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls); ++extern int sched_create_sysfs_power_savings_entries(struct device *dev); + + #ifdef CONFIG_HOTPLUG_CPU + extern void unregister_cpu(struct cpu *cpu); +@@ -160,7 +160,7 @@ static inline void cpu_maps_update_done( + } + + #endif /* CONFIG_SMP */ +-extern struct sysdev_class cpu_sysdev_class; ++extern struct bus_type cpu_subsys; + + #ifdef CONFIG_HOTPLUG_CPU + /* Stop CPUs going up and down. */ +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -7940,54 +7940,52 @@ static ssize_t sched_power_savings_store + } + + #ifdef CONFIG_SCHED_MC +-static ssize_t sched_mc_power_savings_show(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, +- char *page) ++static ssize_t sched_mc_power_savings_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) + { +- return sprintf(page, "%u\n", sched_mc_power_savings); ++ return sprintf(buf, "%u\n", sched_mc_power_savings); + } +-static ssize_t sched_mc_power_savings_store(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, ++static ssize_t sched_mc_power_savings_store(struct device *dev, ++ struct device_attribute *attr, + const char *buf, size_t count) + { + return sched_power_savings_store(buf, count, 0); + } +-static SYSDEV_CLASS_ATTR(sched_mc_power_savings, 0644, +- sched_mc_power_savings_show, +- sched_mc_power_savings_store); ++static DEVICE_ATTR(sched_mc_power_savings, 0644, ++ sched_mc_power_savings_show, ++ sched_mc_power_savings_store); + #endif + + #ifdef CONFIG_SCHED_SMT +-static ssize_t sched_smt_power_savings_show(struct sysdev_class *dev, +- struct sysdev_class_attribute *attr, +- char *page) ++static ssize_t sched_smt_power_savings_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) + { +- return sprintf(page, "%u\n", sched_smt_power_savings); ++ return sprintf(buf, "%u\n", sched_smt_power_savings); + } +-static ssize_t sched_smt_power_savings_store(struct sysdev_class *dev, +- struct sysdev_class_attribute *attr, ++static ssize_t sched_smt_power_savings_store(struct device *dev, ++ struct device_attribute *attr, + const char *buf, size_t count) + { + return sched_power_savings_store(buf, count, 1); + } +-static SYSDEV_CLASS_ATTR(sched_smt_power_savings, 0644, ++static DEVICE_ATTR(sched_smt_power_savings, 0644, + sched_smt_power_savings_show, + sched_smt_power_savings_store); + #endif + +-int __init sched_create_sysfs_power_savings_entries(struct sysdev_class *cls) ++int __init sched_create_sysfs_power_savings_entries(struct device *dev) + { + int err = 0; + + #ifdef CONFIG_SCHED_SMT + if (smt_capable()) +- err = sysfs_create_file(&cls->kset.kobj, +- &attr_sched_smt_power_savings.attr); ++ err = device_create_file(dev, &dev_attr_sched_smt_power_savings); + #endif + #ifdef CONFIG_SCHED_MC + if (!err && mc_capable()) +- err = sysfs_create_file(&cls->kset.kobj, +- &attr_sched_mc_power_savings.attr); ++ err = device_create_file(dev, &dev_attr_sched_mc_power_savings); + #endif + return err; + } diff --git a/03-memory.patch b/03-memory.patch new file mode 100644 index 0000000..3013096 --- /dev/null +++ b/03-memory.patch @@ -0,0 +1,948 @@ +From: Kay Sievers <kay.sievers@vrfy.org> +Subject: convert 'memory' sysdev_class to a regular subsystem + +This moves the 'cpu sysdev_class' over to a regular 'cpu' subsystem +and converts the devices to regular devices. The sysdev drivers are +implemented as subsystem interfaces now. + +After all sysdev classes are ported to regular driver core entities, the +sysdev implementation will be entirely removed from the kernel. + +Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> +--- + drivers/base/memory.c | 160 ++++++++++++++++++++----------------------------- + drivers/base/node.c | 146 +++++++++++++++++++++++--------------------- + include/linux/memory.h | 3 + include/linux/node.h | 6 - + mm/compaction.c | 10 +-- + mm/hugetlb.c | 34 +++++----- + mm/vmscan.c | 14 ++-- + 7 files changed, 175 insertions(+), 198 deletions(-) + +--- a/drivers/base/memory.c ++++ b/drivers/base/memory.c +@@ -1,5 +1,5 @@ + /* +- * drivers/base/memory.c - basic Memory class support ++ * Memory subsystem support + * + * Written by Matt Tolentino <matthew.e.tolentino@intel.com> + * Dave Hansen <haveblue@us.ibm.com> +@@ -10,7 +10,6 @@ + * SPARSEMEM should be contained here, or in mm/memory_hotplug.c. + */ + +-#include <linux/sysdev.h> + #include <linux/module.h> + #include <linux/init.h> + #include <linux/topology.h> +@@ -38,26 +37,9 @@ static inline int base_memory_block_id(i + return section_nr / sections_per_block; + } + +-static struct sysdev_class memory_sysdev_class = { ++static struct bus_type memory_subsys = { + .name = MEMORY_CLASS_NAME, +-}; +- +-static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) +-{ +- return MEMORY_CLASS_NAME; +-} +- +-static int memory_uevent(struct kset *kset, struct kobject *obj, +- struct kobj_uevent_env *env) +-{ +- int retval = 0; +- +- return retval; +-} +- +-static const struct kset_uevent_ops memory_uevent_ops = { +- .name = memory_uevent_name, +- .uevent = memory_uevent, ++ .dev_name = MEMORY_CLASS_NAME, + }; + + static BLOCKING_NOTIFIER_HEAD(memory_chain); +@@ -96,21 +78,21 @@ int register_memory(struct memory_block + { + int error; + +- memory->sysdev.cls = &memory_sysdev_class; +- memory->sysdev.id = memory->start_section_nr / sections_per_block; ++ memory->dev.bus = &memory_subsys; ++ memory->dev.id = memory->start_section_nr / sections_per_block; + +- error = sysdev_register(&memory->sysdev); ++ error = device_register(&memory->dev); + return error; + } + + static void + unregister_memory(struct memory_block *memory) + { +- BUG_ON(memory->sysdev.cls != &memory_sysdev_class); ++ BUG_ON(memory->dev.bus != &memory_subsys); + + /* drop the ref. we got in remove_memory_block() */ +- kobject_put(&memory->sysdev.kobj); +- sysdev_unregister(&memory->sysdev); ++ kobject_put(&memory->dev.kobj); ++ device_unregister(&memory->dev); + } + + unsigned long __weak memory_block_size_bytes(void) +@@ -138,22 +120,22 @@ static unsigned long get_memory_block_si + * uses. + */ + +-static ssize_t show_mem_start_phys_index(struct sys_device *dev, +- struct sysdev_attribute *attr, char *buf) ++static ssize_t show_mem_start_phys_index(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + struct memory_block *mem = +- container_of(dev, struct memory_block, sysdev); ++ container_of(dev, struct memory_block, dev); + unsigned long phys_index; + + phys_index = mem->start_section_nr / sections_per_block; + return sprintf(buf, "%08lx\n", phys_index); + } + +-static ssize_t show_mem_end_phys_index(struct sys_device *dev, +- struct sysdev_attribute *attr, char *buf) ++static ssize_t show_mem_end_phys_index(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + struct memory_block *mem = +- container_of(dev, struct memory_block, sysdev); ++ container_of(dev, struct memory_block, dev); + unsigned long phys_index; + + phys_index = mem->end_section_nr / sections_per_block; +@@ -163,13 +145,13 @@ static ssize_t show_mem_end_phys_index(s + /* + * Show whether the section of memory is likely to be hot-removable + */ +-static ssize_t show_mem_removable(struct sys_device *dev, +- struct sysdev_attribute *attr, char *buf) ++static ssize_t show_mem_removable(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + unsigned long i, pfn; + int ret = 1; + struct memory_block *mem = +- container_of(dev, struct memory_block, sysdev); ++ container_of(dev, struct memory_block, dev); + + for (i = 0; i < sections_per_block; i++) { + pfn = section_nr_to_pfn(mem->start_section_nr + i); +@@ -182,11 +164,11 @@ static ssize_t show_mem_removable(struct + /* + * online, offline, going offline, etc. + */ +-static ssize_t show_mem_state(struct sys_device *dev, +- struct sysdev_attribute *attr, char *buf) ++static ssize_t show_mem_state(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + struct memory_block *mem = +- container_of(dev, struct memory_block, sysdev); ++ container_of(dev, struct memory_block, dev); + ssize_t len = 0; + + /* +@@ -324,13 +306,13 @@ out: + } + + static ssize_t +-store_mem_state(struct sys_device *dev, +- struct sysdev_attribute *attr, const char *buf, size_t count) ++store_mem_state(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) + { + struct memory_block *mem; + int ret = -EINVAL; + +- mem = container_of(dev, struct memory_block, sysdev); ++ mem = container_of(dev, struct memory_block, dev); + + if (!strncmp(buf, "online", min((int)count, 6))) + ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); +@@ -351,41 +333,41 @@ store_mem_state(struct sys_device *dev, + * s.t. if I offline all of these sections I can then + * remove the physical device? + */ +-static ssize_t show_phys_device(struct sys_device *dev, +- struct sysdev_attribute *attr, char *buf) ++static ssize_t show_phys_device(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + struct memory_block *mem = +- container_of(dev, struct memory_block, sysdev); ++ container_of(dev, struct memory_block, dev); + return sprintf(buf, "%d\n", mem->phys_device); + } + +-static SYSDEV_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL); +-static SYSDEV_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL); +-static SYSDEV_ATTR(state, 0644, show_mem_state, store_mem_state); +-static SYSDEV_ATTR(phys_device, 0444, show_phys_device, NULL); +-static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL); ++static DEVICE_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL); ++static DEVICE_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL); ++static DEVICE_ATTR(state, 0644, show_mem_state, store_mem_state); ++static DEVICE_ATTR(phys_device, 0444, show_phys_device, NULL); ++static DEVICE_ATTR(removable, 0444, show_mem_removable, NULL); + + #define mem_create_simple_file(mem, attr_name) \ +- sysdev_create_file(&mem->sysdev, &attr_##attr_name) ++ device_create_file(&mem->dev, &dev_attr_##attr_name) + #define mem_remove_simple_file(mem, attr_name) \ +- sysdev_remove_file(&mem->sysdev, &attr_##attr_name) ++ device_remove_file(&mem->dev, &dev_attr_##attr_name) + + /* + * Block size attribute stuff + */ + static ssize_t +-print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr, ++print_block_size(struct device *dev, struct device_attribute *attr, + char *buf) + { + return sprintf(buf, "%lx\n", get_memory_block_size()); + } + +-static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL); ++static DEVICE_ATTR(block_size_bytes, 0444, print_block_size, NULL); + + static int block_size_init(void) + { +- return sysfs_create_file(&memory_sysdev_class.kset.kobj, +- &attr_block_size_bytes.attr); ++ return device_create_file(memory_subsys.dev_root, ++ &dev_attr_block_size_bytes); + } + + /* +@@ -396,7 +378,7 @@ static int block_size_init(void) + */ + #ifdef CONFIG_ARCH_MEMORY_PROBE + static ssize_t +-memory_probe_store(struct class *class, struct class_attribute *attr, ++memory_probe_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { + u64 phys_addr; +@@ -423,12 +405,11 @@ memory_probe_store(struct class *class, + out: + return ret; + } +-static CLASS_ATTR(probe, S_IWUSR, NULL, memory_probe_store); ++static DEVICE_ATTR(probe, S_IWUSR, NULL, memory_probe_store); + + static int memory_probe_init(void) + { +- return sysfs_create_file(&memory_sysdev_class.kset.kobj, +- &class_attr_probe.attr); ++ return device_create_file(memory_subsys.dev_root, &dev_attr_probe); + } + #else + static inline int memory_probe_init(void) +@@ -444,8 +425,8 @@ static inline int memory_probe_init(void + + /* Soft offline a page */ + static ssize_t +-store_soft_offline_page(struct class *class, +- struct class_attribute *attr, ++store_soft_offline_page(struct device *dev, ++ struct device_attribute *attr, + const char *buf, size_t count) + { + int ret; +@@ -463,8 +444,8 @@ store_soft_offline_page(struct class *cl + + /* Forcibly offline a page, including killing processes. */ + static ssize_t +-store_hard_offline_page(struct class *class, +- struct class_attribute *attr, ++store_hard_offline_page(struct device *dev, ++ struct device_attribute *attr, + const char *buf, size_t count) + { + int ret; +@@ -478,18 +459,18 @@ store_hard_offline_page(struct class *cl + return ret ? ret : count; + } + +-static CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page); +-static CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page); ++static DEVICE_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page); ++static DEVICE_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page); + + static __init int memory_fail_init(void) + { + int err; + +- err = sysfs_create_file(&memory_sysdev_class.kset.kobj, +- &class_attr_soft_offline_page.attr); ++ err = device_create_file(memory_susbsy.dev_root, ++ &dev_attr_soft_offline_page.attr); + if (!err) +- err = sysfs_create_file(&memory_sysdev_class.kset.kobj, +- &class_attr_hard_offline_page.attr); ++ err = device_create_file(memory_subsys.dev_root, ++ &dev_attr_hard_offline_page.attr); + return err; + } + #else +@@ -509,31 +490,23 @@ int __weak arch_get_memory_phys_device(u + return 0; + } + ++/* ++ * A reference for the returned object is held and the reference for the ++ * hinted object is released. ++ */ + struct memory_block *find_memory_block_hinted(struct mem_section *section, + struct memory_block *hint) + { +- struct kobject *kobj; +- struct sys_device *sysdev; +- struct memory_block *mem; +- char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; + int block_id = base_memory_block_id(__section_nr(section)); ++ struct device *hintdev = hint ? &hint->dev : NULL; ++ struct device *dev; + +- kobj = hint ? &hint->sysdev.kobj : NULL; +- +- /* +- * This only works because we know that section == sysdev->id +- * slightly redundant with sysdev_register() +- */ +- sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, block_id); +- +- kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj); +- if (!kobj) ++ dev = subsys_find_device_by_id(&memory_subsys, block_id, hintdev); ++ if (hint) ++ put_device(&hint->dev); ++ if (!dev) + return NULL; +- +- sysdev = container_of(kobj, struct sys_device, kobj); +- mem = container_of(sysdev, struct memory_block, sysdev); +- +- return mem; ++ return container_of(dev, struct memory_block, dev); + } + + /* +@@ -542,7 +515,7 @@ struct memory_block *find_memory_block_h + * this gets to be a real problem, we can always use a radix + * tree or something here. + * +- * This could be made generic for all sysdev classes. ++ * This could be made generic for all device subsystems. + */ + struct memory_block *find_memory_block(struct mem_section *section) + { +@@ -598,7 +571,7 @@ static int add_memory_section(int nid, s + mem = find_memory_block(section); + if (mem) { + mem->section_count++; +- kobject_put(&mem->sysdev.kobj); ++ kobject_put(&mem->dev.kobj); + } else + ret = init_memory_block(&mem, section, state); + +@@ -631,7 +604,7 @@ int remove_memory_block(unsigned long no + unregister_memory(mem); + kfree(mem); + } else +- kobject_put(&mem->sysdev.kobj); ++ kobject_put(&mem->dev.kobj); + + mutex_unlock(&mem_sysfs_mutex); + return 0; +@@ -664,8 +637,7 @@ int __init memory_dev_init(void) + int err; + unsigned long block_sz; + +- memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops; +- ret = sysdev_class_register(&memory_sysdev_class); ++ ret = subsys_system_register(&memory_subsys, NULL); + if (ret) + goto out; + +--- a/drivers/base/node.c ++++ b/drivers/base/node.c +@@ -1,8 +1,7 @@ + /* +- * drivers/base/node.c - basic Node class support ++ * Basic Node interface support + */ + +-#include <linux/sysdev.h> + #include <linux/module.h> + #include <linux/init.h> + #include <linux/mm.h> +@@ -19,18 +18,16 @@ + #include <linux/swap.h> + #include <linux/slab.h> + +-static struct sysdev_class_attribute *node_state_attrs[]; +- +-static struct sysdev_class node_class = { ++static struct bus_type node_subsys = { + .name = "node", +- .attrs = node_state_attrs, ++ .dev_name = "node", + }; + + +-static ssize_t node_read_cpumap(struct sys_device *dev, int type, char *buf) ++static ssize_t node_read_cpumap(struct device *dev, int type, char *buf) + { + struct node *node_dev = to_node(dev); +- const struct cpumask *mask = cpumask_of_node(node_dev->sysdev.id); ++ const struct cpumask *mask = cpumask_of_node(node_dev->dev.id); + int len; + + /* 2008/04/07: buf currently PAGE_SIZE, need 9 chars per 32 bits. */ +@@ -44,23 +41,23 @@ static ssize_t node_read_cpumap(struct s + return len; + } + +-static inline ssize_t node_read_cpumask(struct sys_device *dev, +- struct sysdev_attribute *attr, char *buf) ++static inline ssize_t node_read_cpumask(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + return node_read_cpumap(dev, 0, buf); + } +-static inline ssize_t node_read_cpulist(struct sys_device *dev, +- struct sysdev_attribute *attr, char *buf) ++static inline ssize_t node_read_cpulist(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + return node_read_cpumap(dev, 1, buf); + } + +-static SYSDEV_ATTR(cpumap, S_IRUGO, node_read_cpumask, NULL); +-static SYSDEV_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL); ++static DEVICE_ATTR(cpumap, S_IRUGO, node_read_cpumask, NULL); ++static DEVICE_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL); + + #define K(x) ((x) << (PAGE_SHIFT - 10)) +-static ssize_t node_read_meminfo(struct sys_device * dev, +- struct sysdev_attribute *attr, char * buf) ++static ssize_t node_read_meminfo(struct device * dev, ++ struct device_attribute *attr, char * buf) + { + int n; + int nid = dev->id; +@@ -157,10 +154,10 @@ static ssize_t node_read_meminfo(struct + } + + #undef K +-static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL); ++static DEVICE_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL); + +-static ssize_t node_read_numastat(struct sys_device * dev, +- struct sysdev_attribute *attr, char * buf) ++static ssize_t node_read_numastat(struct device * dev, ++ struct device_attribute *attr, char * buf) + { + return sprintf(buf, + "numa_hit %lu\n" +@@ -176,10 +173,10 @@ static ssize_t node_read_numastat(struct + node_page_state(dev->id, NUMA_LOCAL), + node_page_state(dev->id, NUMA_OTHER)); + } +-static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL); ++static DEVICE_ATTR(numastat, S_IRUGO, node_read_numastat, NULL); + +-static ssize_t node_read_vmstat(struct sys_device *dev, +- struct sysdev_attribute *attr, char *buf) ++static ssize_t node_read_vmstat(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + int nid = dev->id; + int i; +@@ -191,10 +188,10 @@ static ssize_t node_read_vmstat(struct s + + return n; + } +-static SYSDEV_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL); ++static DEVICE_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL); + +-static ssize_t node_read_distance(struct sys_device * dev, +- struct sysdev_attribute *attr, char * buf) ++static ssize_t node_read_distance(struct device * dev, ++ struct device_attribute *attr, char * buf) + { + int nid = dev->id; + int len = 0; +@@ -212,7 +209,7 @@ static ssize_t node_read_distance(struct + len += sprintf(buf + len, "\n"); + return len; + } +-static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL); ++static DEVICE_ATTR(distance, S_IRUGO, node_read_distance, NULL); + + #ifdef CONFIG_HUGETLBFS + /* +@@ -230,7 +227,7 @@ static node_registration_func_t __hugetl + static inline bool hugetlb_register_node(struct node *node) + { + if (__hugetlb_register_node && +- node_state(node->sysdev.id, N_HIGH_MEMORY)) { ++ node_state(node->dev.id, N_HIGH_MEMORY)) { + __hugetlb_register_node(node); + return true; + } +@@ -266,17 +263,17 @@ int register_node(struct node *node, int + { + int error; + +- node->sysdev.id = num; +- node->sysdev.cls = &node_class; +- error = sysdev_register(&node->sysdev); ++ node->dev.id = num; ++ node->dev.bus = &node_subsys; ++ error = device_register(&node->dev); + + if (!error){ +- sysdev_create_file(&node->sysdev, &attr_cpumap); +- sysdev_create_file(&node->sysdev, &attr_cpulist); +- sysdev_create_file(&node->sysdev, &attr_meminfo); +- sysdev_create_file(&node->sysdev, &attr_numastat); +- sysdev_create_file(&node->sysdev, &attr_distance); +- sysdev_create_file(&node->sysdev, &attr_vmstat); ++ device_create_file(&node->dev, &dev_attr_cpumap); ++ device_create_file(&node->dev, &dev_attr_cpulist); ++ device_create_file(&node->dev, &dev_attr_meminfo); ++ device_create_file(&node->dev, &dev_attr_numastat); ++ device_create_file(&node->dev, &dev_attr_distance); ++ device_create_file(&node->dev, &dev_attr_vmstat); + + scan_unevictable_register_node(node); + +@@ -296,17 +293,17 @@ int register_node(struct node *node, int + */ + void unregister_node(struct node *node) + { +- sysdev_remove_file(&node->sysdev, &attr_cpumap); +- sysdev_remove_file(&node->sysdev, &attr_cpulist); +- sysdev_remove_file(&node->sysdev, &attr_meminfo); +- sysdev_remove_file(&node->sysdev, &attr_numastat); +- sysdev_remove_file(&node->sysdev, &attr_distance); +- sysdev_remove_file(&node->sysdev, &attr_vmstat); ++ device_remove_file(&node->dev, &dev_attr_cpumap); ++ device_remove_file(&node->dev, &dev_attr_cpulist); ++ device_remove_file(&node->dev, &dev_attr_meminfo); ++ device_remove_file(&node->dev, &dev_attr_numastat); ++ device_remove_file(&node->dev, &dev_attr_distance); ++ device_remove_file(&node->dev, &dev_attr_vmstat); + + scan_unevictable_unregister_node(node); + hugetlb_unregister_node(node); /* no-op, if memoryless node */ + +- sysdev_unregister(&node->sysdev); ++ device_unregister(&node->dev); + } + + struct node node_devices[MAX_NUMNODES]; +@@ -326,15 +323,15 @@ int register_cpu_under_node(unsigned int + if (!obj) + return 0; + +- ret = sysfs_create_link(&node_devices[nid].sysdev.kobj, ++ ret = sysfs_create_link(&node_devices[nid].dev.kobj, + &obj->kobj, + kobject_name(&obj->kobj)); + if (ret) + return ret; + + return sysfs_create_link(&obj->kobj, +- &node_devices[nid].sysdev.kobj, +- kobject_name(&node_devices[nid].sysdev.kobj)); ++ &node_devices[nid].dev.kobj, ++ kobject_name(&node_devices[nid].dev.kobj)); + } + + int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) +@@ -348,10 +345,10 @@ int unregister_cpu_under_node(unsigned i + if (!obj) + return 0; + +- sysfs_remove_link(&node_devices[nid].sysdev.kobj, ++ sysfs_remove_link(&node_devices[nid].dev.kobj, + kobject_name(&obj->kobj)); + sysfs_remove_link(&obj->kobj, +- kobject_name(&node_devices[nid].sysdev.kobj)); ++ kobject_name(&node_devices[nid].dev.kobj)); + + return 0; + } +@@ -393,15 +390,15 @@ int register_mem_sect_under_node(struct + continue; + if (page_nid != nid) + continue; +- ret = sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj, +- &mem_blk->sysdev.kobj, +- kobject_name(&mem_blk->sysdev.kobj)); ++ ret = sysfs_create_link_nowarn(&node_devices[nid].dev.kobj, ++ &mem_blk->dev.kobj, ++ kobject_name(&mem_blk->dev.kobj)); + if (ret) + return ret; + +- return sysfs_create_link_nowarn(&mem_blk->sysdev.kobj, +- &node_devices[nid].sysdev.kobj, +- kobject_name(&node_devices[nid].sysdev.kobj)); ++ return sysfs_create_link_nowarn(&mem_blk->dev.kobj, ++ &node_devices[nid].dev.kobj, ++ kobject_name(&node_devices[nid].dev.kobj)); + } + /* mem section does not span the specified node */ + return 0; +@@ -434,10 +431,10 @@ int unregister_mem_sect_under_nodes(stru + continue; + if (node_test_and_set(nid, *unlinked_nodes)) + continue; +- sysfs_remove_link(&node_devices[nid].sysdev.kobj, +- kobject_name(&mem_blk->sysdev.kobj)); +- sysfs_remove_link(&mem_blk->sysdev.kobj, +- kobject_name(&node_devices[nid].sysdev.kobj)); ++ sysfs_remove_link(&node_devices[nid].dev.kobj, ++ kobject_name(&mem_blk->dev.kobj)); ++ sysfs_remove_link(&mem_blk->dev.kobj, ++ kobject_name(&node_devices[nid].dev.kobj)); + } + NODEMASK_FREE(unlinked_nodes); + return 0; +@@ -468,7 +465,7 @@ static int link_mem_sections(int nid) + } + + if (mem_blk) +- kobject_put(&mem_blk->sysdev.kobj); ++ kobject_put(&mem_blk->dev.kobj); + return err; + } + +@@ -596,19 +593,19 @@ static ssize_t print_nodes_state(enum no + } + + struct node_attr { +- struct sysdev_class_attribute attr; ++ struct device_attribute attr; + enum node_states state; + }; + +-static ssize_t show_node_state(struct sysdev_class *class, +- struct sysdev_class_attribute *attr, char *buf) ++static ssize_t show_node_state(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + struct node_attr *na = container_of(attr, struct node_attr, attr); + return print_nodes_state(na->state, buf); + } + + #define _NODE_ATTR(name, state) \ +- { _SYSDEV_CLASS_ATTR(name, 0444, show_node_state, NULL), state } ++ { __ATTR(name, 0444, show_node_state, NULL), state } + + static struct node_attr node_state_attr[] = { + _NODE_ATTR(possible, N_POSSIBLE), +@@ -620,17 +617,26 @@ static struct node_attr node_state_attr[ + #endif + }; + +-static struct sysdev_class_attribute *node_state_attrs[] = { +- &node_state_attr[0].attr, +- &node_state_attr[1].attr, +- &node_state_attr[2].attr, +- &node_state_attr[3].attr, ++static struct attribute *node_state_attrs[] = { ++ &node_state_attr[0].attr.attr, ++ &node_state_attr[1].attr.attr, ++ &node_state_attr[2].attr.attr, ++ &node_state_attr[3].attr.attr, + #ifdef CONFIG_HIGHMEM +- &node_state_attr[4].attr, ++ &node_state_attr[4].attr.attr, + #endif + NULL + }; + ++static struct attribute_group memory_root_attr_group = { ++ .attrs = node_state_attrs, ++}; ++ ++static const struct attribute_group *cpu_root_attr_groups[] = { ++ &memory_root_attr_group, ++ NULL, ++}; ++ + #define NODE_CALLBACK_PRI 2 /* lower than SLAB */ + static int __init register_node_type(void) + { +@@ -639,7 +645,7 @@ static int __init register_node_type(voi + BUILD_BUG_ON(ARRAY_SIZE(node_state_attr) != NR_NODE_STATES); + BUILD_BUG_ON(ARRAY_SIZE(node_state_attrs)-1 != NR_NODE_STATES); + +- ret = sysdev_class_register(&node_class); ++ ret = subsys_system_register(&node_subsys, cpu_root_attr_groups); + if (!ret) { + hotplug_memory_notifier(node_memory_callback, + NODE_CALLBACK_PRI); +--- a/include/linux/memory.h ++++ b/include/linux/memory.h +@@ -15,7 +15,6 @@ + #ifndef _LINUX_MEMORY_H_ + #define _LINUX_MEMORY_H_ + +-#include <linux/sysdev.h> + #include <linux/node.h> + #include <linux/compiler.h> + #include <linux/mutex.h> +@@ -38,7 +37,7 @@ struct memory_block { + int phys_device; /* to which fru does this belong? */ + void *hw; /* optional pointer to fw/hw data */ + int (*phys_callback)(struct memory_block *); +- struct sys_device sysdev; ++ struct device dev; + }; + + int arch_get_memory_phys_device(unsigned long start_pfn); +--- a/include/linux/node.h ++++ b/include/linux/node.h +@@ -14,12 +14,12 @@ + #ifndef _LINUX_NODE_H_ + #define _LINUX_NODE_H_ + +-#include <linux/sysdev.h> ++#include <linux/device.h> + #include <linux/cpumask.h> + #include <linux/workqueue.h> + + struct node { +- struct sys_device sysdev; ++ struct device dev; + + #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HUGETLBFS) + struct work_struct node_work; +@@ -80,6 +80,6 @@ static inline void register_hugetlbfs_wi + } + #endif + +-#define to_node(sys_device) container_of(sys_device, struct node, sysdev) ++#define to_node(device) container_of(device, struct node, dev) + + #endif /* _LINUX_NODE_H_ */ +--- a/mm/compaction.c ++++ b/mm/compaction.c +@@ -721,23 +721,23 @@ int sysctl_extfrag_handler(struct ctl_ta + } + + #if defined(CONFIG_SYSFS) && defined(CONFIG_NUMA) +-ssize_t sysfs_compact_node(struct sys_device *dev, +- struct sysdev_attribute *attr, ++ssize_t sysfs_compact_node(struct device *dev, ++ struct device_attribute *attr, + const char *buf, size_t count) + { + compact_node(dev->id); + + return count; + } +-static SYSDEV_ATTR(compact, S_IWUSR, NULL, sysfs_compact_node); ++static DEVICE_ATTR(compact, S_IWUSR, NULL, sysfs_compact_node); + + int compaction_register_node(struct node *node) + { +- return sysdev_create_file(&node->sysdev, &attr_compact); ++ return device_create_file(&node->dev, &dev_attr_compact); + } + + void compaction_unregister_node(struct node *node) + { +- return sysdev_remove_file(&node->sysdev, &attr_compact); ++ return device_remove_file(&node->dev, &dev_attr_compact); + } + #endif /* CONFIG_SYSFS && CONFIG_NUMA */ +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -1592,9 +1592,9 @@ static void __init hugetlb_sysfs_init(vo + + /* + * node_hstate/s - associate per node hstate attributes, via their kobjects, +- * with node sysdevs in node_devices[] using a parallel array. The array +- * index of a node sysdev or _hstate == node id. +- * This is here to avoid any static dependency of the node sysdev driver, in ++ * with node devices in node_devices[] using a parallel array. The array ++ * index of a node device or _hstate == node id. ++ * This is here to avoid any static dependency of the node device driver, in + * the base kernel, on the hugetlb module. + */ + struct node_hstate { +@@ -1604,7 +1604,7 @@ struct node_hstate { + struct node_hstate node_hstates[MAX_NUMNODES]; + + /* +- * A subset of global hstate attributes for node sysdevs ++ * A subset of global hstate attributes for node devices + */ + static struct attribute *per_node_hstate_attrs[] = { + &nr_hugepages_attr.attr, +@@ -1618,7 +1618,7 @@ static struct attribute_group per_node_h + }; + + /* +- * kobj_to_node_hstate - lookup global hstate for node sysdev hstate attr kobj. ++ * kobj_to_node_hstate - lookup global hstate for node device hstate attr kobj. + * Returns node id via non-NULL nidp. + */ + static struct hstate *kobj_to_node_hstate(struct kobject *kobj, int *nidp) +@@ -1641,13 +1641,13 @@ static struct hstate *kobj_to_node_hstat + } + + /* +- * Unregister hstate attributes from a single node sysdev. ++ * Unregister hstate attributes from a single node device. + * No-op if no hstate attributes attached. + */ + void hugetlb_unregister_node(struct node *node) + { + struct hstate *h; +- struct node_hstate *nhs = &node_hstates[node->sysdev.id]; ++ struct node_hstate *nhs = &node_hstates[node->dev.id]; + + if (!nhs->hugepages_kobj) + return; /* no hstate attributes */ +@@ -1663,7 +1663,7 @@ void hugetlb_unregister_node(struct node + } + + /* +- * hugetlb module exit: unregister hstate attributes from node sysdevs ++ * hugetlb module exit: unregister hstate attributes from node devices + * that have them. + */ + static void hugetlb_unregister_all_nodes(void) +@@ -1671,7 +1671,7 @@ static void hugetlb_unregister_all_nodes + int nid; + + /* +- * disable node sysdev registrations. ++ * disable node device registrations. + */ + register_hugetlbfs_with_node(NULL, NULL); + +@@ -1683,20 +1683,20 @@ static void hugetlb_unregister_all_nodes + } + + /* +- * Register hstate attributes for a single node sysdev. ++ * Register hstate attributes for a single node device. + * No-op if attributes already registered. + */ + void hugetlb_register_node(struct node *node) + { + struct hstate *h; +- struct node_hstate *nhs = &node_hstates[node->sysdev.id]; ++ struct node_hstate *nhs = &node_hstates[node->dev.id]; + int err; + + if (nhs->hugepages_kobj) + return; /* already allocated */ + + nhs->hugepages_kobj = kobject_create_and_add("hugepages", +- &node->sysdev.kobj); ++ &node->dev.kobj); + if (!nhs->hugepages_kobj) + return; + +@@ -1707,7 +1707,7 @@ void hugetlb_register_node(struct node * + if (err) { + printk(KERN_ERR "Hugetlb: Unable to add hstate %s" + " for node %d\n", +- h->name, node->sysdev.id); ++ h->name, node->dev.id); + hugetlb_unregister_node(node); + break; + } +@@ -1716,8 +1716,8 @@ void hugetlb_register_node(struct node * + + /* + * hugetlb init time: register hstate attributes for all registered node +- * sysdevs of nodes that have memory. All on-line nodes should have +- * registered their associated sysdev by this time. ++ * devices of nodes that have memory. All on-line nodes should have ++ * registered their associated device by this time. + */ + static void hugetlb_register_all_nodes(void) + { +@@ -1725,12 +1725,12 @@ static void hugetlb_register_all_nodes(v + + for_each_node_state(nid, N_HIGH_MEMORY) { + struct node *node = &node_devices[nid]; +- if (node->sysdev.id == nid) ++ if (node->dev.id == nid) + hugetlb_register_node(node); + } + + /* +- * Let the node sysdev driver know we're here so it can ++ * Let the node device driver know we're here so it can + * [un]register hstate attributes on node hotplug. + */ + register_hugetlbfs_with_node(hugetlb_register_node, +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3475,16 +3475,16 @@ int scan_unevictable_handler(struct ctl_ + * a specified node's per zone unevictable lists for evictable pages. + */ + +-static ssize_t read_scan_unevictable_node(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t read_scan_unevictable_node(struct device *dev, ++ struct device_attribute *attr, + char *buf) + { + warn_scan_unevictable_pages(); + return sprintf(buf, "0\n"); /* always zero; should fit... */ + } + +-static ssize_t write_scan_unevictable_node(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t write_scan_unevictable_node(struct device *dev, ++ struct device_attribute *attr, + const char *buf, size_t count) + { + warn_scan_unevictable_pages(); +@@ -3492,17 +3492,17 @@ static ssize_t write_scan_unevictable_no + } + + +-static SYSDEV_ATTR(scan_unevictable_pages, S_IRUGO | S_IWUSR, ++static DEVICE_ATTR(scan_unevictable_pages, S_IRUGO | S_IWUSR, + read_scan_unevictable_node, + write_scan_unevictable_node); + + int scan_unevictable_register_node(struct node *node) + { +- return sysdev_create_file(&node->sysdev, &attr_scan_unevictable_pages); ++ return device_create_file(&node->dev, &dev_attr_scan_unevictable_pages); + } + + void scan_unevictable_unregister_node(struct node *node) + { +- sysdev_remove_file(&node->sysdev, &attr_scan_unevictable_pages); ++ device_remove_file(&node->dev, &dev_attr_scan_unevictable_pages); + } + #endif diff --git a/04-rtmutex.patch b/04-rtmutex.patch new file mode 100644 index 0000000..73a21dd --- /dev/null +++ b/04-rtmutex.patch @@ -0,0 +1,134 @@ +From: Kay Sievers <kay.sievers@vrfy.org> +Subject: rtmutex-tester: convert sysdev_class to a regular subsystem + +After all sysdev classes are ported to regular driver core entities, the +sysdev implementation will be entirely removed from the kernel. + +Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> +--- + kernel/rtmutex-tester.c | 37 +++++++++++++++++++------------------ + 1 file changed, 19 insertions(+), 18 deletions(-) + +--- a/kernel/rtmutex-tester.c ++++ b/kernel/rtmutex-tester.c +@@ -6,11 +6,11 @@ + * Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com> + * + */ ++#include <linux/device.h> + #include <linux/kthread.h> + #include <linux/export.h> + #include <linux/sched.h> + #include <linux/spinlock.h> +-#include <linux/sysdev.h> + #include <linux/timer.h> + #include <linux/freezer.h> + +@@ -27,7 +27,7 @@ struct test_thread_data { + int opdata; + int mutexes[MAX_RT_TEST_MUTEXES]; + int event; +- struct sys_device sysdev; ++ struct device dev; + }; + + static struct test_thread_data thread_data[MAX_RT_TEST_THREADS]; +@@ -271,7 +271,7 @@ static int test_func(void *data) + * + * opcode:data + */ +-static ssize_t sysfs_test_command(struct sys_device *dev, struct sysdev_attribute *attr, ++static ssize_t sysfs_test_command(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { + struct sched_param schedpar; +@@ -279,8 +279,8 @@ static ssize_t sysfs_test_command(struct + char cmdbuf[32]; + int op, dat, tid, ret; + +- td = container_of(dev, struct test_thread_data, sysdev); +- tid = td->sysdev.id; ++ td = container_of(dev, struct test_thread_data, dev); ++ tid = td->dev.id; + + /* strings from sysfs write are not 0 terminated! */ + if (count >= sizeof(cmdbuf)) +@@ -334,7 +334,7 @@ static ssize_t sysfs_test_command(struct + * @dev: thread to query + * @buf: char buffer to be filled with thread status info + */ +-static ssize_t sysfs_test_status(struct sys_device *dev, struct sysdev_attribute *attr, ++static ssize_t sysfs_test_status(struct device *dev, struct device_attribute *attr, + char *buf) + { + struct test_thread_data *td; +@@ -342,8 +342,8 @@ static ssize_t sysfs_test_status(struct + char *curr = buf; + int i; + +- td = container_of(dev, struct test_thread_data, sysdev); +- tsk = threads[td->sysdev.id]; ++ td = container_of(dev, struct test_thread_data, dev); ++ tsk = threads[td->dev.id]; + + spin_lock(&rttest_lock); + +@@ -360,28 +360,29 @@ static ssize_t sysfs_test_status(struct + spin_unlock(&rttest_lock); + + curr += sprintf(curr, ", T: %p, R: %p\n", tsk, +- mutexes[td->sysdev.id].owner); ++ mutexes[td->dev.id].owner); + + return curr - buf; + } + +-static SYSDEV_ATTR(status, 0600, sysfs_test_status, NULL); +-static SYSDEV_ATTR(command, 0600, NULL, sysfs_test_command); ++static DEVICE_ATTR(status, 0600, sysfs_test_status, NULL); ++static DEVICE_ATTR(command, 0600, NULL, sysfs_test_command); + +-static struct sysdev_class rttest_sysclass = { ++static struct bus_type rttest_subsys = { + .name = "rttest", ++ .dev_name = "rttest", + }; + + static int init_test_thread(int id) + { +- thread_data[id].sysdev.cls = &rttest_sysclass; +- thread_data[id].sysdev.id = id; ++ thread_data[id].dev.bus = &rttest_subsys; ++ thread_data[id].dev.id = id; + + threads[id] = kthread_run(test_func, &thread_data[id], "rt-test-%d", id); + if (IS_ERR(threads[id])) + return PTR_ERR(threads[id]); + +- return sysdev_register(&thread_data[id].sysdev); ++ return device_register(&thread_data[id].dev); + } + + static int init_rttest(void) +@@ -393,7 +394,7 @@ static int init_rttest(void) + for (i = 0; i < MAX_RT_TEST_MUTEXES; i++) + rt_mutex_init(&mutexes[i]); + +- ret = sysdev_class_register(&rttest_sysclass); ++ ret = subsys_system_register(&rttest_subsys, NULL); + if (ret) + return ret; + +@@ -401,10 +402,10 @@ static int init_rttest(void) + ret = init_test_thread(i); + if (ret) + break; +- ret = sysdev_create_file(&thread_data[i].sysdev, &attr_status); ++ ret = device_create_file(&thread_data[i].dev, &dev_attr_status); + if (ret) + break; +- ret = sysdev_create_file(&thread_data[i].sysdev, &attr_command); ++ ret = device_create_file(&thread_data[i].dev, &dev_attr_command); + if (ret) + break; + } diff --git a/05-clocksource.patch b/05-clocksource.patch new file mode 100644 index 0000000..4853a4f --- /dev/null +++ b/05-clocksource.patch @@ -0,0 +1,104 @@ +From: Kay Sievers <kay.sievers@vrfy.org> +Subject: clocksource: convert sysdev_class to a regular subsystem + +After all sysdev classes are ported to regular driver core entities, the +sysdev implementation will be entirely removed from the kernel. + +Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> +--- + kernel/time/clocksource.c | 37 +++++++++++++++++++------------------ + 1 file changed, 19 insertions(+), 18 deletions(-) + +--- a/kernel/time/clocksource.c ++++ b/kernel/time/clocksource.c +@@ -23,8 +23,8 @@ + * o Allow clocksource drivers to be unregistered + */ + ++#include <linux/device.h> + #include <linux/clocksource.h> +-#include <linux/sysdev.h> + #include <linux/init.h> + #include <linux/module.h> + #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */ +@@ -792,8 +792,8 @@ EXPORT_SYMBOL(clocksource_unregister); + * Provides sysfs interface for listing current clocksource. + */ + static ssize_t +-sysfs_show_current_clocksources(struct sys_device *dev, +- struct sysdev_attribute *attr, char *buf) ++sysfs_show_current_clocksources(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + ssize_t count = 0; + +@@ -813,8 +813,8 @@ sysfs_show_current_clocksources(struct s + * Takes input from sysfs interface for manually overriding the default + * clocksource selection. + */ +-static ssize_t sysfs_override_clocksource(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t sysfs_override_clocksource(struct device *dev, ++ struct device_attribute *attr, + const char *buf, size_t count) + { + size_t ret = count; +@@ -847,8 +847,8 @@ static ssize_t sysfs_override_clocksourc + * Provides sysfs interface for listing registered clocksources + */ + static ssize_t +-sysfs_show_available_clocksources(struct sys_device *dev, +- struct sysdev_attribute *attr, ++sysfs_show_available_clocksources(struct device *dev, ++ struct device_attribute *attr, + char *buf) + { + struct clocksource *src; +@@ -877,35 +877,36 @@ sysfs_show_available_clocksources(struct + /* + * Sysfs setup bits: + */ +-static SYSDEV_ATTR(current_clocksource, 0644, sysfs_show_current_clocksources, ++static DEVICE_ATTR(current_clocksource, 0644, sysfs_show_current_clocksources, + sysfs_override_clocksource); + +-static SYSDEV_ATTR(available_clocksource, 0444, ++static DEVICE_ATTR(available_clocksource, 0444, + sysfs_show_available_clocksources, NULL); + +-static struct sysdev_class clocksource_sysclass = { ++static struct bus_type clocksource_subsys = { + .name = "clocksource", ++ .dev_name = "clocksource", + }; + +-static struct sys_device device_clocksource = { ++static struct device device_clocksource = { + .id = 0, +- .cls = &clocksource_sysclass, ++ .bus = &clocksource_subsys, + }; + + static int __init init_clocksource_sysfs(void) + { +- int error = sysdev_class_register(&clocksource_sysclass); ++ int error = subsys_system_register(&clocksource_subsys, NULL); + + if (!error) +- error = sysdev_register(&device_clocksource); ++ error = device_register(&device_clocksource); + if (!error) +- error = sysdev_create_file( ++ error = device_create_file( + &device_clocksource, +- &attr_current_clocksource); ++ &dev_attr_current_clocksource); + if (!error) +- error = sysdev_create_file( ++ error = device_create_file( + &device_clocksource, +- &attr_available_clocksource); ++ &dev_attr_available_clocksource); + return error; + } + diff --git a/06-ibm-rtl.patch b/06-ibm-rtl.patch new file mode 100644 index 0000000..2583768 --- /dev/null +++ b/06-ibm-rtl.patch @@ -0,0 +1,98 @@ +From: Kay Sievers <kay.sievers@vrfy.org> +Subject: ibm_rtl: convert sysdev_class to a regular subsystem + +After all sysdev classes are ported to regular driver core entities, the +sysdev implementation will be entirely removed from the kernel. + +Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> +--- + drivers/platform/x86/ibm_rtl.c | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + +--- a/drivers/platform/x86/ibm_rtl.c ++++ b/drivers/platform/x86/ibm_rtl.c +@@ -28,7 +28,6 @@ + #include <linux/delay.h> + #include <linux/module.h> + #include <linux/io.h> +-#include <linux/sysdev.h> + #include <linux/dmi.h> + #include <linux/efi.h> + #include <linux/mutex.h> +@@ -165,22 +164,22 @@ static int ibm_rtl_write(u8 value) + return ret; + } + +-static ssize_t rtl_show_version(struct sysdev_class * dev, +- struct sysdev_class_attribute *attr, ++static ssize_t rtl_show_version(struct device * dev, ++ struct device_attribute *attr, + char *buf) + { + return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version)); + } + +-static ssize_t rtl_show_state(struct sysdev_class *dev, +- struct sysdev_class_attribute *attr, ++static ssize_t rtl_show_state(struct device *dev, ++ struct device_attribute *attr, + char *buf) + { + return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status)); + } + +-static ssize_t rtl_set_state(struct sysdev_class *dev, +- struct sysdev_class_attribute *attr, ++static ssize_t rtl_set_state(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { +@@ -205,27 +204,28 @@ static ssize_t rtl_set_state(struct sysd + return ret; + } + +-static struct sysdev_class class_rtl = { ++static struct bus_type rtl_subsys = { + .name = "ibm_rtl", ++ .dev_name = "ibm_rtl", + }; + +-static SYSDEV_CLASS_ATTR(version, S_IRUGO, rtl_show_version, NULL); +-static SYSDEV_CLASS_ATTR(state, 0600, rtl_show_state, rtl_set_state); ++static DEVICE_ATTR(version, S_IRUGO, rtl_show_version, NULL); ++static DEVICE_ATTR(state, 0600, rtl_show_state, rtl_set_state); + +-static struct sysdev_class_attribute *rtl_attributes[] = { +- &attr_version, +- &attr_state, ++static struct device_attribute *rtl_attributes[] = { ++ &dev_attr_version, ++ &dev_attr_state, + NULL + }; + + + static int rtl_setup_sysfs(void) { + int ret, i; +- ret = sysdev_class_register(&class_rtl); + ++ ret = subsys_system_register(&rtl_subsys, NULL); + if (!ret) { + for (i = 0; rtl_attributes[i]; i ++) +- sysdev_class_create_file(&class_rtl, rtl_attributes[i]); ++ device_create_file(rtl_subsys.dev_root, rtl_attributes[i]); + } + return ret; + } +@@ -233,8 +233,8 @@ static int rtl_setup_sysfs(void) { + static void rtl_teardown_sysfs(void) { + int i; + for (i = 0; rtl_attributes[i]; i ++) +- sysdev_class_remove_file(&class_rtl, rtl_attributes[i]); +- sysdev_class_unregister(&class_rtl); ++ device_remove_file(rtl_subsys.dev_root, rtl_attributes[i]); ++ bus_unregister(&rtl_subsys); + } + + diff --git a/07-edac.patch b/07-edac.patch new file mode 100644 index 0000000..9a42764 --- /dev/null +++ b/07-edac.patch @@ -0,0 +1,393 @@ +From: Kay Sievers <kay.sievers@vrfy.org> +Subject: edac: convert sysdev_class to a regular subsystem + +After all sysdev classes are ported to regular driver core entities, the +sysdev implementation will be entirely removed from the kernel. + +Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> +--- + drivers/edac/edac_core.h | 7 +++---- + drivers/edac/edac_device.c | 1 - + drivers/edac/edac_device_sysfs.c | 20 ++++++++++---------- + drivers/edac/edac_mc.c | 1 - + drivers/edac/edac_mc_sysfs.c | 16 ++++++++-------- + drivers/edac/edac_module.h | 2 -- + drivers/edac/edac_pci.c | 1 - + drivers/edac/edac_pci_sysfs.c | 16 ++++++++-------- + drivers/edac/edac_stub.c | 27 ++++++++++++++------------- + drivers/edac/mce_amd_inj.c | 13 ++++++------- + include/linux/edac.h | 8 ++++---- + 11 files changed, 53 insertions(+), 59 deletions(-) + +--- a/drivers/edac/edac_core.h ++++ b/drivers/edac/edac_core.h +@@ -32,7 +32,6 @@ + #include <linux/completion.h> + #include <linux/kobject.h> + #include <linux/platform_device.h> +-#include <linux/sysdev.h> + #include <linux/workqueue.h> + #include <linux/edac.h> + +@@ -243,8 +242,8 @@ struct edac_device_ctl_info { + */ + struct edac_dev_sysfs_attribute *sysfs_attributes; + +- /* pointer to main 'edac' class in sysfs */ +- struct sysdev_class *edac_class; ++ /* pointer to main 'edac' subsys in sysfs */ ++ struct bus_type *edac_subsys; + + /* the internal state of this controller instance */ + int op_state; +@@ -342,7 +341,7 @@ struct edac_pci_ctl_info { + + int pci_idx; + +- struct sysdev_class *edac_class; /* pointer to class */ ++ struct bus_type *edac_subsys; /* pointer to subsystem */ + + /* the internal state of this controller instance */ + int op_state; +--- a/drivers/edac/edac_device.c ++++ b/drivers/edac/edac_device.c +@@ -23,7 +23,6 @@ + #include <linux/jiffies.h> + #include <linux/spinlock.h> + #include <linux/list.h> +-#include <linux/sysdev.h> + #include <linux/ctype.h> + #include <linux/workqueue.h> + #include <asm/uaccess.h> +--- a/drivers/edac/edac_device_sysfs.c ++++ b/drivers/edac/edac_device_sysfs.c +@@ -1,5 +1,5 @@ + /* +- * file for managing the edac_device class of devices for EDAC ++ * file for managing the edac_device subsystem of devices for EDAC + * + * (C) 2007 SoftwareBitMaker + * +@@ -230,21 +230,21 @@ static struct kobj_type ktype_device_ctr + */ + int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) + { +- struct sysdev_class *edac_class; ++ struct bus_type *edac_subsys; + int err; + + debugf1("%s()\n", __func__); + + /* get the /sys/devices/system/edac reference */ +- edac_class = edac_get_sysfs_class(); +- if (edac_class == NULL) { +- debugf1("%s() no edac_class error\n", __func__); ++ edac_subsys = edac_get_sysfs_subsys(); ++ if (edac_subsys == NULL) { ++ debugf1("%s() no edac_subsys error\n", __func__); + err = -ENODEV; + goto err_out; + } + +- /* Point to the 'edac_class' this instance 'reports' to */ +- edac_dev->edac_class = edac_class; ++ /* Point to the 'edac_subsys' this instance 'reports' to */ ++ edac_dev->edac_subsys = edac_subsys; + + /* Init the devices's kobject */ + memset(&edac_dev->kobj, 0, sizeof(struct kobject)); +@@ -261,7 +261,7 @@ int edac_device_register_sysfs_main_kobj + + /* register */ + err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl, +- &edac_class->kset.kobj, ++ &edac_subsys->dev_root->kobj, + "%s", edac_dev->name); + if (err) { + debugf1("%s()Failed to register '.../edac/%s'\n", +@@ -284,7 +284,7 @@ err_kobj_reg: + module_put(edac_dev->owner); + + err_mod_get: +- edac_put_sysfs_class(); ++ edac_put_sysfs_subsys(); + + err_out: + return err; +@@ -308,7 +308,7 @@ void edac_device_unregister_sysfs_main_k + * b) 'kfree' the memory + */ + kobject_put(&dev->kobj); +- edac_put_sysfs_class(); ++ edac_put_sysfs_subsys(); + } + + /* edac_dev -> instance information */ +--- a/drivers/edac/edac_mc.c ++++ b/drivers/edac/edac_mc.c +@@ -25,7 +25,6 @@ + #include <linux/jiffies.h> + #include <linux/spinlock.h> + #include <linux/list.h> +-#include <linux/sysdev.h> + #include <linux/ctype.h> + #include <linux/edac.h> + #include <asm/uaccess.h> +--- a/drivers/edac/edac_mc_sysfs.c ++++ b/drivers/edac/edac_mc_sysfs.c +@@ -1021,19 +1021,19 @@ void edac_remove_sysfs_mci_device(struct + int edac_sysfs_setup_mc_kset(void) + { + int err = -EINVAL; +- struct sysdev_class *edac_class; ++ struct bus_type *edac_subsys; + + debugf1("%s()\n", __func__); + +- /* get the /sys/devices/system/edac class reference */ +- edac_class = edac_get_sysfs_class(); +- if (edac_class == NULL) { +- debugf1("%s() no edac_class error=%d\n", __func__, err); ++ /* get the /sys/devices/system/edac subsys reference */ ++ edac_subsys = edac_get_sysfs_subsys(); ++ if (edac_subsys == NULL) { ++ debugf1("%s() no edac_subsys error=%d\n", __func__, err); + goto fail_out; + } + + /* Init the MC's kobject */ +- mc_kset = kset_create_and_add("mc", NULL, &edac_class->kset.kobj); ++ mc_kset = kset_create_and_add("mc", NULL, &edac_subsys->dev_root->kobj); + if (!mc_kset) { + err = -ENOMEM; + debugf1("%s() Failed to register '.../edac/mc'\n", __func__); +@@ -1045,7 +1045,7 @@ int edac_sysfs_setup_mc_kset(void) + return 0; + + fail_kset: +- edac_put_sysfs_class(); ++ edac_put_sysfs_subsys(); + + fail_out: + return err; +@@ -1059,6 +1059,6 @@ fail_out: + void edac_sysfs_teardown_mc_kset(void) + { + kset_unregister(mc_kset); +- edac_put_sysfs_class(); ++ edac_put_sysfs_subsys(); + } + +--- a/drivers/edac/edac_module.h ++++ b/drivers/edac/edac_module.h +@@ -10,8 +10,6 @@ + #ifndef __EDAC_MODULE_H__ + #define __EDAC_MODULE_H__ + +-#include <linux/sysdev.h> +- + #include "edac_core.h" + + /* +--- a/drivers/edac/edac_pci.c ++++ b/drivers/edac/edac_pci.c +@@ -19,7 +19,6 @@ + #include <linux/slab.h> + #include <linux/spinlock.h> + #include <linux/list.h> +-#include <linux/sysdev.h> + #include <linux/ctype.h> + #include <linux/workqueue.h> + #include <asm/uaccess.h> +--- a/drivers/edac/edac_pci_sysfs.c ++++ b/drivers/edac/edac_pci_sysfs.c +@@ -338,12 +338,12 @@ static struct kobj_type ktype_edac_pci_m + * edac_pci_main_kobj_setup() + * + * setup the sysfs for EDAC PCI attributes +- * assumes edac_class has already been initialized ++ * assumes edac_subsys has already been initialized + */ + static int edac_pci_main_kobj_setup(void) + { + int err; +- struct sysdev_class *edac_class; ++ struct bus_type *edac_subsys; + + debugf0("%s()\n", __func__); + +@@ -354,9 +354,9 @@ static int edac_pci_main_kobj_setup(void + /* First time, so create the main kobject and its + * controls and attributes + */ +- edac_class = edac_get_sysfs_class(); +- if (edac_class == NULL) { +- debugf1("%s() no edac_class\n", __func__); ++ edac_subsys = edac_get_sysfs_subsys(); ++ if (edac_subsys == NULL) { ++ debugf1("%s() no edac_subsys\n", __func__); + err = -ENODEV; + goto decrement_count_fail; + } +@@ -381,7 +381,7 @@ static int edac_pci_main_kobj_setup(void + /* Instanstiate the pci object */ + err = kobject_init_and_add(edac_pci_top_main_kobj, + &ktype_edac_pci_main_kobj, +- &edac_class->kset.kobj, "pci"); ++ &edac_subsys->dev_root->kobj, "pci"); + if (err) { + debugf1("Failed to register '.../edac/pci'\n"); + goto kobject_init_and_add_fail; +@@ -404,7 +404,7 @@ kzalloc_fail: + module_put(THIS_MODULE); + + mod_get_fail: +- edac_put_sysfs_class(); ++ edac_put_sysfs_subsys(); + + decrement_count_fail: + /* if are on this error exit, nothing to tear down */ +@@ -432,7 +432,7 @@ static void edac_pci_main_kobj_teardown( + __func__); + kobject_put(edac_pci_top_main_kobj); + } +- edac_put_sysfs_class(); ++ edac_put_sysfs_subsys(); + } + + /* +--- a/drivers/edac/edac_stub.c ++++ b/drivers/edac/edac_stub.c +@@ -26,7 +26,7 @@ EXPORT_SYMBOL_GPL(edac_handlers); + int edac_err_assert = 0; + EXPORT_SYMBOL_GPL(edac_err_assert); + +-static atomic_t edac_class_valid = ATOMIC_INIT(0); ++static atomic_t edac_subsys_valid = ATOMIC_INIT(0); + + /* + * called to determine if there is an EDAC driver interested in +@@ -54,36 +54,37 @@ EXPORT_SYMBOL_GPL(edac_atomic_assert_err + * sysfs object: /sys/devices/system/edac + * need to export to other files + */ +-struct sysdev_class edac_class = { ++struct bus_type edac_subsys = { + .name = "edac", ++ .dev_name = "edac", + }; +-EXPORT_SYMBOL_GPL(edac_class); ++EXPORT_SYMBOL_GPL(edac_subsys); + + /* return pointer to the 'edac' node in sysfs */ +-struct sysdev_class *edac_get_sysfs_class(void) ++struct bus_type *edac_get_sysfs_subsys(void) + { + int err = 0; + +- if (atomic_read(&edac_class_valid)) ++ if (atomic_read(&edac_subsys_valid)) + goto out; + + /* create the /sys/devices/system/edac directory */ +- err = sysdev_class_register(&edac_class); ++ err = subsys_system_register(&edac_subsys, NULL); + if (err) { + printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n"); + return NULL; + } + + out: +- atomic_inc(&edac_class_valid); +- return &edac_class; ++ atomic_inc(&edac_subsys_valid); ++ return &edac_subsys; + } +-EXPORT_SYMBOL_GPL(edac_get_sysfs_class); ++EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys); + +-void edac_put_sysfs_class(void) ++void edac_put_sysfs_subsys(void) + { + /* last user unregisters it */ +- if (atomic_dec_and_test(&edac_class_valid)) +- sysdev_class_unregister(&edac_class); ++ if (atomic_dec_and_test(&edac_subsys_valid)) ++ bus_unregister(&edac_subsys); + } +-EXPORT_SYMBOL_GPL(edac_put_sysfs_class); ++EXPORT_SYMBOL_GPL(edac_put_sysfs_subsys); +--- a/drivers/edac/mce_amd_inj.c ++++ b/drivers/edac/mce_amd_inj.c +@@ -11,7 +11,6 @@ + */ + + #include <linux/kobject.h> +-#include <linux/sysdev.h> + #include <linux/edac.h> + #include <linux/module.h> + #include <asm/mce.h> +@@ -116,14 +115,14 @@ static struct edac_mce_attr *sysfs_attrs + + static int __init edac_init_mce_inject(void) + { +- struct sysdev_class *edac_class = NULL; ++ struct bus_type *edac_subsys = NULL; + int i, err = 0; + +- edac_class = edac_get_sysfs_class(); +- if (!edac_class) ++ edac_subsys = edac_get_sysfs_subsys(); ++ if (!edac_subsys) + return -EINVAL; + +- mce_kobj = kobject_create_and_add("mce", &edac_class->kset.kobj); ++ mce_kobj = kobject_create_and_add("mce", &edac_subsys->dev_root->kobj); + if (!mce_kobj) { + printk(KERN_ERR "Error creating a mce kset.\n"); + err = -ENOMEM; +@@ -147,7 +146,7 @@ err_sysfs_create: + kobject_del(mce_kobj); + + err_mce_kobj: +- edac_put_sysfs_class(); ++ edac_put_sysfs_subsys(); + + return err; + } +@@ -161,7 +160,7 @@ static void __exit edac_exit_mce_inject( + + kobject_del(mce_kobj); + +- edac_put_sysfs_class(); ++ edac_put_sysfs_subsys(); + } + + module_init(edac_init_mce_inject); +--- a/include/linux/edac.h ++++ b/include/linux/edac.h +@@ -13,7 +13,7 @@ + #define _LINUX_EDAC_H_ + + #include <linux/atomic.h> +-#include <linux/sysdev.h> ++#include <linux/device.h> + + #define EDAC_OPSTATE_INVAL -1 + #define EDAC_OPSTATE_POLL 0 +@@ -23,12 +23,12 @@ + extern int edac_op_state; + extern int edac_err_assert; + extern atomic_t edac_handlers; +-extern struct sysdev_class edac_class; ++extern struct bus_type edac_subsys; + + extern int edac_handler_set(void); + extern void edac_atomic_assert_error(void); +-extern struct sysdev_class *edac_get_sysfs_class(void); +-extern void edac_put_sysfs_class(void); ++extern struct bus_type *edac_get_sysfs_subsys(void); ++extern void edac_put_sysfs_subsys(void); + + static inline void opstate_init(void) + { diff --git a/08-xen.patch b/08-xen.patch new file mode 100644 index 0000000..7ea3fd1 --- /dev/null +++ b/08-xen.patch @@ -0,0 +1,424 @@ +From: Kay Sievers <kay.sievers@vrfy.org> +Subject: xen-balloon: convert sysdev_class to a regular subsystem + +After all sysdev classes are ported to regular driver core entities, the +sysdev implementation will be entirely removed from the kernel. + +Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> +--- + drivers/xen/xen-balloon.c | 86 +++++++++++++++++++++--------------------- + drivers/xen/xen-selfballoon.c | 75 ++++++++++++++++++------------------ + include/xen/balloon.h | 6 +- + 3 files changed, 83 insertions(+), 84 deletions(-) + +--- a/drivers/xen/xen-balloon.c ++++ b/drivers/xen/xen-balloon.c +@@ -32,7 +32,6 @@ + + #include <linux/kernel.h> + #include <linux/module.h> +-#include <linux/sysdev.h> + #include <linux/capability.h> + + #include <xen/xen.h> +@@ -46,9 +45,9 @@ + + #define BALLOON_CLASS_NAME "xen_memory" + +-static struct sys_device balloon_sysdev; ++static struct device balloon_dev; + +-static int register_balloon(struct sys_device *sysdev); ++static int register_balloon(struct device *dev); + + /* React to a change in the target key */ + static void watch_target(struct xenbus_watch *watch, +@@ -98,9 +97,9 @@ static int __init balloon_init(void) + + pr_info("xen-balloon: Initialising balloon driver.\n"); + +- register_balloon(&balloon_sysdev); ++ register_balloon(&balloon_dev); + +- register_xen_selfballooning(&balloon_sysdev); ++ register_xen_selfballooning(&balloon_dev); + + register_xenstore_notifier(&xenstore_notifier); + +@@ -117,31 +116,31 @@ static void balloon_exit(void) + module_exit(balloon_exit); + + #define BALLOON_SHOW(name, format, args...) \ +- static ssize_t show_##name(struct sys_device *dev, \ +- struct sysdev_attribute *attr, \ ++ static ssize_t show_##name(struct device *dev, \ ++ struct device_attribute *attr, \ + char *buf) \ + { \ + return sprintf(buf, format, ##args); \ + } \ +- static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL) ++ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + + BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages)); + BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low)); + BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high)); + +-static SYSDEV_ULONG_ATTR(schedule_delay, 0444, balloon_stats.schedule_delay); +-static SYSDEV_ULONG_ATTR(max_schedule_delay, 0644, balloon_stats.max_schedule_delay); +-static SYSDEV_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count); +-static SYSDEV_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count); ++static DEVICE_ULONG_ATTR(schedule_delay, 0444, balloon_stats.schedule_delay); ++static DEVICE_ULONG_ATTR(max_schedule_delay, 0644, balloon_stats.max_schedule_delay); ++static DEVICE_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count); ++static DEVICE_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count); + +-static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr, ++static ssize_t show_target_kb(struct device *dev, struct device_attribute *attr, + char *buf) + { + return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages)); + } + +-static ssize_t store_target_kb(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t store_target_kb(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { +@@ -158,11 +157,11 @@ static ssize_t store_target_kb(struct sy + return count; + } + +-static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR, ++static DEVICE_ATTR(target_kb, S_IRUGO | S_IWUSR, + show_target_kb, store_target_kb); + + +-static ssize_t show_target(struct sys_device *dev, struct sysdev_attribute *attr, ++static ssize_t show_target(struct device *dev, struct device_attribute *attr, + char *buf) + { + return sprintf(buf, "%llu\n", +@@ -170,8 +169,8 @@ static ssize_t show_target(struct sys_de + << PAGE_SHIFT); + } + +-static ssize_t store_target(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t store_target(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { +@@ -188,23 +187,23 @@ static ssize_t store_target(struct sys_d + return count; + } + +-static SYSDEV_ATTR(target, S_IRUGO | S_IWUSR, ++static DEVICE_ATTR(target, S_IRUGO | S_IWUSR, + show_target, store_target); + + +-static struct sysdev_attribute *balloon_attrs[] = { +- &attr_target_kb, +- &attr_target, +- &attr_schedule_delay.attr, +- &attr_max_schedule_delay.attr, +- &attr_retry_count.attr, +- &attr_max_retry_count.attr ++static struct device_attribute *balloon_attrs[] = { ++ &dev_attr_target_kb, ++ &dev_attr_target, ++ &dev_attr_schedule_delay.attr, ++ &dev_attr_max_schedule_delay.attr, ++ &dev_attr_retry_count.attr, ++ &dev_attr_max_retry_count.attr + }; + + static struct attribute *balloon_info_attrs[] = { +- &attr_current_kb.attr, +- &attr_low_kb.attr, +- &attr_high_kb.attr, ++ &dev_attr_current_kb.attr, ++ &dev_attr_low_kb.attr, ++ &dev_attr_high_kb.attr, + NULL + }; + +@@ -213,34 +212,35 @@ static struct attribute_group balloon_in + .attrs = balloon_info_attrs + }; + +-static struct sysdev_class balloon_sysdev_class = { +- .name = BALLOON_CLASS_NAME ++static struct bus_type balloon_subsys = { ++ .name = BALLOON_CLASS_NAME, ++ .dev_name = BALLOON_CLASS_NAME, + }; + +-static int register_balloon(struct sys_device *sysdev) ++static int register_balloon(struct device *dev) + { + int i, error; + +- error = sysdev_class_register(&balloon_sysdev_class); ++ error = bus_register(&balloon_subsys); + if (error) + return error; + +- sysdev->id = 0; +- sysdev->cls = &balloon_sysdev_class; ++ dev->id = 0; ++ dev->bus = &balloon_subsys; + +- error = sysdev_register(sysdev); ++ error = device_register(dev); + if (error) { +- sysdev_class_unregister(&balloon_sysdev_class); ++ bus_unregister(&balloon_subsys); + return error; + } + + for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) { +- error = sysdev_create_file(sysdev, balloon_attrs[i]); ++ error = device_create_file(dev, balloon_attrs[i]); + if (error) + goto fail; + } + +- error = sysfs_create_group(&sysdev->kobj, &balloon_info_group); ++ error = sysfs_create_group(&dev->kobj, &balloon_info_group); + if (error) + goto fail; + +@@ -248,9 +248,9 @@ static int register_balloon(struct sys_d + + fail: + while (--i >= 0) +- sysdev_remove_file(sysdev, balloon_attrs[i]); +- sysdev_unregister(sysdev); +- sysdev_class_unregister(&balloon_sysdev_class); ++ device_remove_file(dev, balloon_attrs[i]); ++ device_unregister(dev); ++ bus_unregister(&balloon_subsys); + return error; + } + +--- a/drivers/xen/xen-selfballoon.c ++++ b/drivers/xen/xen-selfballoon.c +@@ -266,21 +266,20 @@ static void selfballoon_process(struct w + + #ifdef CONFIG_SYSFS + +-#include <linux/sysdev.h> + #include <linux/capability.h> + + #define SELFBALLOON_SHOW(name, format, args...) \ +- static ssize_t show_##name(struct sys_device *dev, \ +- struct sysdev_attribute *attr, \ +- char *buf) \ ++ static ssize_t show_##name(struct device *dev, \ ++ struct device_attribute *attr, \ ++ char *buf) \ + { \ + return sprintf(buf, format, ##args); \ + } + + SELFBALLOON_SHOW(selfballooning, "%d\n", xen_selfballooning_enabled); + +-static ssize_t store_selfballooning(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t store_selfballooning(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { +@@ -303,13 +302,13 @@ static ssize_t store_selfballooning(stru + return count; + } + +-static SYSDEV_ATTR(selfballooning, S_IRUGO | S_IWUSR, ++static DEVICE_ATTR(selfballooning, S_IRUGO | S_IWUSR, + show_selfballooning, store_selfballooning); + + SELFBALLOON_SHOW(selfballoon_interval, "%d\n", selfballoon_interval); + +-static ssize_t store_selfballoon_interval(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t store_selfballoon_interval(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { +@@ -325,13 +324,13 @@ static ssize_t store_selfballoon_interva + return count; + } + +-static SYSDEV_ATTR(selfballoon_interval, S_IRUGO | S_IWUSR, ++static DEVICE_ATTR(selfballoon_interval, S_IRUGO | S_IWUSR, + show_selfballoon_interval, store_selfballoon_interval); + + SELFBALLOON_SHOW(selfballoon_downhys, "%d\n", selfballoon_downhysteresis); + +-static ssize_t store_selfballoon_downhys(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t store_selfballoon_downhys(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { +@@ -347,14 +346,14 @@ static ssize_t store_selfballoon_downhys + return count; + } + +-static SYSDEV_ATTR(selfballoon_downhysteresis, S_IRUGO | S_IWUSR, ++static DEVICE_ATTR(selfballoon_downhysteresis, S_IRUGO | S_IWUSR, + show_selfballoon_downhys, store_selfballoon_downhys); + + + SELFBALLOON_SHOW(selfballoon_uphys, "%d\n", selfballoon_uphysteresis); + +-static ssize_t store_selfballoon_uphys(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t store_selfballoon_uphys(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { +@@ -370,14 +369,14 @@ static ssize_t store_selfballoon_uphys(s + return count; + } + +-static SYSDEV_ATTR(selfballoon_uphysteresis, S_IRUGO | S_IWUSR, ++static DEVICE_ATTR(selfballoon_uphysteresis, S_IRUGO | S_IWUSR, + show_selfballoon_uphys, store_selfballoon_uphys); + + SELFBALLOON_SHOW(selfballoon_min_usable_mb, "%d\n", + selfballoon_min_usable_mb); + +-static ssize_t store_selfballoon_min_usable_mb(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t store_selfballoon_min_usable_mb(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { +@@ -393,7 +392,7 @@ static ssize_t store_selfballoon_min_usa + return count; + } + +-static SYSDEV_ATTR(selfballoon_min_usable_mb, S_IRUGO | S_IWUSR, ++static DEVICE_ATTR(selfballoon_min_usable_mb, S_IRUGO | S_IWUSR, + show_selfballoon_min_usable_mb, + store_selfballoon_min_usable_mb); + +@@ -401,8 +400,8 @@ static SYSDEV_ATTR(selfballoon_min_usabl + #ifdef CONFIG_FRONTSWAP + SELFBALLOON_SHOW(frontswap_selfshrinking, "%d\n", frontswap_selfshrinking); + +-static ssize_t store_frontswap_selfshrinking(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t store_frontswap_selfshrinking(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { +@@ -424,13 +423,13 @@ static ssize_t store_frontswap_selfshrin + return count; + } + +-static SYSDEV_ATTR(frontswap_selfshrinking, S_IRUGO | S_IWUSR, ++static DEVICE_ATTR(frontswap_selfshrinking, S_IRUGO | S_IWUSR, + show_frontswap_selfshrinking, store_frontswap_selfshrinking); + + SELFBALLOON_SHOW(frontswap_inertia, "%d\n", frontswap_inertia); + +-static ssize_t store_frontswap_inertia(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t store_frontswap_inertia(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { +@@ -447,13 +446,13 @@ static ssize_t store_frontswap_inertia(s + return count; + } + +-static SYSDEV_ATTR(frontswap_inertia, S_IRUGO | S_IWUSR, ++static DEVICE_ATTR(frontswap_inertia, S_IRUGO | S_IWUSR, + show_frontswap_inertia, store_frontswap_inertia); + + SELFBALLOON_SHOW(frontswap_hysteresis, "%d\n", frontswap_hysteresis); + +-static ssize_t store_frontswap_hysteresis(struct sys_device *dev, +- struct sysdev_attribute *attr, ++static ssize_t store_frontswap_hysteresis(struct device *dev, ++ struct device_attribute *attr, + const char *buf, + size_t count) + { +@@ -469,21 +468,21 @@ static ssize_t store_frontswap_hysteresi + return count; + } + +-static SYSDEV_ATTR(frontswap_hysteresis, S_IRUGO | S_IWUSR, ++static DEVICE_ATTR(frontswap_hysteresis, S_IRUGO | S_IWUSR, + show_frontswap_hysteresis, store_frontswap_hysteresis); + + #endif /* CONFIG_FRONTSWAP */ + + static struct attribute *selfballoon_attrs[] = { +- &attr_selfballooning.attr, +- &attr_selfballoon_interval.attr, +- &attr_selfballoon_downhysteresis.attr, +- &attr_selfballoon_uphysteresis.attr, +- &attr_selfballoon_min_usable_mb.attr, ++ &dev_attr_selfballooning.attr, ++ &dev_attr_selfballoon_interval.attr, ++ &dev_attr_selfballoon_downhysteresis.attr, ++ &dev_attr_selfballoon_uphysteresis.attr, ++ &dev_attr_selfballoon_min_usable_mb.attr, + #ifdef CONFIG_FRONTSWAP +- &attr_frontswap_selfshrinking.attr, +- &attr_frontswap_hysteresis.attr, +- &attr_frontswap_inertia.attr, ++ &dev_attr_frontswap_selfshrinking.attr, ++ &dev_attr_frontswap_hysteresis.attr, ++ &dev_attr_frontswap_inertia.attr, + #endif + NULL + }; +@@ -494,12 +493,12 @@ static struct attribute_group selfballoo + }; + #endif + +-int register_xen_selfballooning(struct sys_device *sysdev) ++int register_xen_selfballooning(struct device *dev) + { + int error = -1; + + #ifdef CONFIG_SYSFS +- error = sysfs_create_group(&sysdev->kobj, &selfballoon_group); ++ error = sysfs_create_group(&dev->kobj, &selfballoon_group); + #endif + return error; + } +--- a/include/xen/balloon.h ++++ b/include/xen/balloon.h +@@ -29,11 +29,11 @@ int alloc_xenballooned_pages(int nr_page + bool highmem); + void free_xenballooned_pages(int nr_pages, struct page **pages); + +-struct sys_device; ++struct device; + #ifdef CONFIG_XEN_SELFBALLOONING +-extern int register_xen_selfballooning(struct sys_device *sysdev); ++extern int register_xen_selfballooning(struct device *dev); + #else +-static inline int register_xen_selfballooning(struct sys_device *sysdev) ++static inline int register_xen_selfballooning(struct device *dev) + { + return -ENOSYS; + } diff --git a/99-core-remove.patch b/99-core-remove.patch new file mode 100644 index 0000000..a77373c --- /dev/null +++ b/99-core-remove.patch @@ -0,0 +1,728 @@ +From: Kay Sievers <kay.sievers@vrfy.org> +Subject: driver-core: remove sysdev implementation + +Delete the needless special case of 'system devices'. They never +made much sense and they are now just regular subsytems and devices, +like everything else in the system. + +Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> +--- + arch/x86/kernel/hpet.c | 1 + arch/x86/kernel/irqinit.c | 2 + arch/x86/platform/uv/uv_sysfs.c | 2 + drivers/base/Makefile | 2 + drivers/base/sys.c | 383 --------------------------------------- + drivers/leds/led-class.c | 1 + drivers/leds/led-triggers.c | 1 + drivers/net/bonding/bond_sysfs.c | 1 + include/linux/kobject.h | 2 + include/linux/sysdev.h | 164 ---------------- + kernel/time/clockevents.c | 1 + lib/kobject.c | 37 --- + 12 files changed, 3 insertions(+), 594 deletions(-) + +--- a/arch/x86/kernel/hpet.c ++++ b/arch/x86/kernel/hpet.c +@@ -2,7 +2,6 @@ + #include <linux/clockchips.h> + #include <linux/interrupt.h> + #include <linux/export.h> +-#include <linux/sysdev.h> + #include <linux/delay.h> + #include <linux/errno.h> + #include <linux/i8253.h> +--- a/arch/x86/kernel/irqinit.c ++++ b/arch/x86/kernel/irqinit.c +@@ -9,7 +9,7 @@ + #include <linux/kprobes.h> + #include <linux/init.h> + #include <linux/kernel_stat.h> +-#include <linux/sysdev.h> ++#include <linux/device.h> + #include <linux/bitops.h> + #include <linux/acpi.h> + #include <linux/io.h> +--- a/arch/x86/platform/uv/uv_sysfs.c ++++ b/arch/x86/platform/uv/uv_sysfs.c +@@ -19,7 +19,7 @@ + * Copyright (c) Russ Anderson + */ + +-#include <linux/sysdev.h> ++#include <linux/device.h> + #include <asm/uv/bios.h> + #include <asm/uv/uv.h> + +--- a/drivers/base/Makefile ++++ b/drivers/base/Makefile +@@ -1,6 +1,6 @@ + # Makefile for the Linux device tree + +-obj-y := core.o sys.o bus.o dd.o syscore.o \ ++obj-y := core.o bus.o dd.o syscore.o \ + driver.o class.o platform.o \ + cpu.o firmware.o init.o map.o devres.o \ + attribute_container.o transport_class.o +--- a/drivers/base/sys.c ++++ /dev/null +@@ -1,383 +0,0 @@ +-/* +- * sys.c - pseudo-bus for system 'devices' (cpus, PICs, timers, etc) +- * +- * Copyright (c) 2002-3 Patrick Mochel +- * 2002-3 Open Source Development Lab +- * +- * This file is released under the GPLv2 +- * +- * This exports a 'system' bus type. +- * By default, a 'sys' bus gets added to the root of the system. There will +- * always be core system devices. Devices can use sysdev_register() to +- * add themselves as children of the system bus. +- */ +- +-#include <linux/sysdev.h> +-#include <linux/err.h> +-#include <linux/module.h> +-#include <linux/kernel.h> +-#include <linux/init.h> +-#include <linux/string.h> +-#include <linux/pm.h> +-#include <linux/device.h> +-#include <linux/mutex.h> +-#include <linux/interrupt.h> +- +-#include "base.h" +- +-#define to_sysdev(k) container_of(k, struct sys_device, kobj) +-#define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr) +- +- +-static ssize_t +-sysdev_show(struct kobject *kobj, struct attribute *attr, char *buffer) +-{ +- struct sys_device *sysdev = to_sysdev(kobj); +- struct sysdev_attribute *sysdev_attr = to_sysdev_attr(attr); +- +- if (sysdev_attr->show) +- return sysdev_attr->show(sysdev, sysdev_attr, buffer); +- return -EIO; +-} +- +- +-static ssize_t +-sysdev_store(struct kobject *kobj, struct attribute *attr, +- const char *buffer, size_t count) +-{ +- struct sys_device *sysdev = to_sysdev(kobj); +- struct sysdev_attribute *sysdev_attr = to_sysdev_attr(attr); +- +- if (sysdev_attr->store) +- return sysdev_attr->store(sysdev, sysdev_attr, buffer, count); +- return -EIO; +-} +- +-static const struct sysfs_ops sysfs_ops = { +- .show = sysdev_show, +- .store = sysdev_store, +-}; +- +-static struct kobj_type ktype_sysdev = { +- .sysfs_ops = &sysfs_ops, +-}; +- +- +-int sysdev_create_file(struct sys_device *s, struct sysdev_attribute *a) +-{ +- return sysfs_create_file(&s->kobj, &a->attr); +-} +- +- +-void sysdev_remove_file(struct sys_device *s, struct sysdev_attribute *a) +-{ +- sysfs_remove_file(&s->kobj, &a->attr); +-} +- +-EXPORT_SYMBOL_GPL(sysdev_create_file); +-EXPORT_SYMBOL_GPL(sysdev_remove_file); +- +-#define to_sysdev_class(k) container_of(k, struct sysdev_class, kset.kobj) +-#define to_sysdev_class_attr(a) container_of(a, \ +- struct sysdev_class_attribute, attr) +- +-static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr, +- char *buffer) +-{ +- struct sysdev_class *class = to_sysdev_class(kobj); +- struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr); +- +- if (class_attr->show) +- return class_attr->show(class, class_attr, buffer); +- return -EIO; +-} +- +-static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr, +- const char *buffer, size_t count) +-{ +- struct sysdev_class *class = to_sysdev_class(kobj); +- struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr); +- +- if (class_attr->store) +- return class_attr->store(class, class_attr, buffer, count); +- return -EIO; +-} +- +-static const struct sysfs_ops sysfs_class_ops = { +- .show = sysdev_class_show, +- .store = sysdev_class_store, +-}; +- +-static struct kobj_type ktype_sysdev_class = { +- .sysfs_ops = &sysfs_class_ops, +-}; +- +-int sysdev_class_create_file(struct sysdev_class *c, +- struct sysdev_class_attribute *a) +-{ +- return sysfs_create_file(&c->kset.kobj, &a->attr); +-} +-EXPORT_SYMBOL_GPL(sysdev_class_create_file); +- +-void sysdev_class_remove_file(struct sysdev_class *c, +- struct sysdev_class_attribute *a) +-{ +- sysfs_remove_file(&c->kset.kobj, &a->attr); +-} +-EXPORT_SYMBOL_GPL(sysdev_class_remove_file); +- +-extern struct kset *system_kset; +- +-int sysdev_class_register(struct sysdev_class *cls) +-{ +- int retval; +- +- pr_debug("Registering sysdev class '%s'\n", cls->name); +- +- INIT_LIST_HEAD(&cls->drivers); +- memset(&cls->kset.kobj, 0x00, sizeof(struct kobject)); +- cls->kset.kobj.parent = &system_kset->kobj; +- cls->kset.kobj.ktype = &ktype_sysdev_class; +- cls->kset.kobj.kset = system_kset; +- +- retval = kobject_set_name(&cls->kset.kobj, "%s", cls->name); +- if (retval) +- return retval; +- +- retval = kset_register(&cls->kset); +- if (!retval && cls->attrs) +- retval = sysfs_create_files(&cls->kset.kobj, +- (const struct attribute **)cls->attrs); +- return retval; +-} +- +-void sysdev_class_unregister(struct sysdev_class *cls) +-{ +- pr_debug("Unregistering sysdev class '%s'\n", +- kobject_name(&cls->kset.kobj)); +- if (cls->attrs) +- sysfs_remove_files(&cls->kset.kobj, +- (const struct attribute **)cls->attrs); +- kset_unregister(&cls->kset); +-} +- +-EXPORT_SYMBOL_GPL(sysdev_class_register); +-EXPORT_SYMBOL_GPL(sysdev_class_unregister); +- +-static DEFINE_MUTEX(sysdev_drivers_lock); +- +-/* +- * @dev != NULL means that we're unwinding because some drv->add() +- * failed for some reason. You need to grab sysdev_drivers_lock before +- * calling this. +- */ +-static void __sysdev_driver_remove(struct sysdev_class *cls, +- struct sysdev_driver *drv, +- struct sys_device *from_dev) +-{ +- struct sys_device *dev = from_dev; +- +- list_del_init(&drv->entry); +- if (!cls) +- return; +- +- if (!drv->remove) +- goto kset_put; +- +- if (dev) +- list_for_each_entry_continue_reverse(dev, &cls->kset.list, +- kobj.entry) +- drv->remove(dev); +- else +- list_for_each_entry(dev, &cls->kset.list, kobj.entry) +- drv->remove(dev); +- +-kset_put: +- kset_put(&cls->kset); +-} +- +-/** +- * sysdev_driver_register - Register auxiliary driver +- * @cls: Device class driver belongs to. +- * @drv: Driver. +- * +- * @drv is inserted into @cls->drivers to be +- * called on each operation on devices of that class. The refcount +- * of @cls is incremented. +- */ +-int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) +-{ +- struct sys_device *dev = NULL; +- int err = 0; +- +- if (!cls) { +- WARN(1, KERN_WARNING "sysdev: invalid class passed to %s!\n", +- __func__); +- return -EINVAL; +- } +- +- /* Check whether this driver has already been added to a class. */ +- if (drv->entry.next && !list_empty(&drv->entry)) +- WARN(1, KERN_WARNING "sysdev: class %s: driver (%p) has already" +- " been registered to a class, something is wrong, but " +- "will forge on!\n", cls->name, drv); +- +- mutex_lock(&sysdev_drivers_lock); +- if (cls && kset_get(&cls->kset)) { +- list_add_tail(&drv->entry, &cls->drivers); +- +- /* If devices of this class already exist, tell the driver */ +- if (drv->add) { +- list_for_each_entry(dev, &cls->kset.list, kobj.entry) { +- err = drv->add(dev); +- if (err) +- goto unwind; +- } +- } +- } else { +- err = -EINVAL; +- WARN(1, KERN_ERR "%s: invalid device class\n", __func__); +- } +- +- goto unlock; +- +-unwind: +- __sysdev_driver_remove(cls, drv, dev); +- +-unlock: +- mutex_unlock(&sysdev_drivers_lock); +- return err; +-} +- +-/** +- * sysdev_driver_unregister - Remove an auxiliary driver. +- * @cls: Class driver belongs to. +- * @drv: Driver. +- */ +-void sysdev_driver_unregister(struct sysdev_class *cls, +- struct sysdev_driver *drv) +-{ +- mutex_lock(&sysdev_drivers_lock); +- __sysdev_driver_remove(cls, drv, NULL); +- mutex_unlock(&sysdev_drivers_lock); +-} +-EXPORT_SYMBOL_GPL(sysdev_driver_register); +-EXPORT_SYMBOL_GPL(sysdev_driver_unregister); +- +-/** +- * sysdev_register - add a system device to the tree +- * @sysdev: device in question +- * +- */ +-int sysdev_register(struct sys_device *sysdev) +-{ +- int error; +- struct sysdev_class *cls = sysdev->cls; +- +- if (!cls) +- return -EINVAL; +- +- pr_debug("Registering sys device of class '%s'\n", +- kobject_name(&cls->kset.kobj)); +- +- /* initialize the kobject to 0, in case it had previously been used */ +- memset(&sysdev->kobj, 0x00, sizeof(struct kobject)); +- +- /* Make sure the kset is set */ +- sysdev->kobj.kset = &cls->kset; +- +- /* Register the object */ +- error = kobject_init_and_add(&sysdev->kobj, &ktype_sysdev, NULL, +- "%s%d", kobject_name(&cls->kset.kobj), +- sysdev->id); +- +- if (!error) { +- struct sysdev_driver *drv; +- +- pr_debug("Registering sys device '%s'\n", +- kobject_name(&sysdev->kobj)); +- +- mutex_lock(&sysdev_drivers_lock); +- /* Generic notification is implicit, because it's that +- * code that should have called us. +- */ +- +- /* Notify class auxiliary drivers */ +- list_for_each_entry(drv, &cls->drivers, entry) { +- if (drv->add) +- drv->add(sysdev); +- } +- mutex_unlock(&sysdev_drivers_lock); +- kobject_uevent(&sysdev->kobj, KOBJ_ADD); +- } +- +- return error; +-} +- +-void sysdev_unregister(struct sys_device *sysdev) +-{ +- struct sysdev_driver *drv; +- +- mutex_lock(&sysdev_drivers_lock); +- list_for_each_entry(drv, &sysdev->cls->drivers, entry) { +- if (drv->remove) +- drv->remove(sysdev); +- } +- mutex_unlock(&sysdev_drivers_lock); +- +- kobject_put(&sysdev->kobj); +-} +- +-EXPORT_SYMBOL_GPL(sysdev_register); +-EXPORT_SYMBOL_GPL(sysdev_unregister); +- +-#define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr) +- +-ssize_t sysdev_store_ulong(struct sys_device *sysdev, +- struct sysdev_attribute *attr, +- const char *buf, size_t size) +-{ +- struct sysdev_ext_attribute *ea = to_ext_attr(attr); +- char *end; +- unsigned long new = simple_strtoul(buf, &end, 0); +- if (end == buf) +- return -EINVAL; +- *(unsigned long *)(ea->var) = new; +- /* Always return full write size even if we didn't consume all */ +- return size; +-} +-EXPORT_SYMBOL_GPL(sysdev_store_ulong); +- +-ssize_t sysdev_show_ulong(struct sys_device *sysdev, +- struct sysdev_attribute *attr, +- char *buf) +-{ +- struct sysdev_ext_attribute *ea = to_ext_attr(attr); +- return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var)); +-} +-EXPORT_SYMBOL_GPL(sysdev_show_ulong); +- +-ssize_t sysdev_store_int(struct sys_device *sysdev, +- struct sysdev_attribute *attr, +- const char *buf, size_t size) +-{ +- struct sysdev_ext_attribute *ea = to_ext_attr(attr); +- char *end; +- long new = simple_strtol(buf, &end, 0); +- if (end == buf || new > INT_MAX || new < INT_MIN) +- return -EINVAL; +- *(int *)(ea->var) = new; +- /* Always return full write size even if we didn't consume all */ +- return size; +-} +-EXPORT_SYMBOL_GPL(sysdev_store_int); +- +-ssize_t sysdev_show_int(struct sys_device *sysdev, +- struct sysdev_attribute *attr, +- char *buf) +-{ +- struct sysdev_ext_attribute *ea = to_ext_attr(attr); +- return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var)); +-} +-EXPORT_SYMBOL_GPL(sysdev_show_int); +- +--- a/drivers/leds/led-class.c ++++ b/drivers/leds/led-class.c +@@ -15,7 +15,6 @@ + #include <linux/list.h> + #include <linux/spinlock.h> + #include <linux/device.h> +-#include <linux/sysdev.h> + #include <linux/timer.h> + #include <linux/err.h> + #include <linux/ctype.h> +--- a/drivers/leds/led-triggers.c ++++ b/drivers/leds/led-triggers.c +@@ -17,7 +17,6 @@ + #include <linux/list.h> + #include <linux/spinlock.h> + #include <linux/device.h> +-#include <linux/sysdev.h> + #include <linux/timer.h> + #include <linux/rwsem.h> + #include <linux/leds.h> +--- a/drivers/net/bonding/bond_sysfs.c ++++ b/drivers/net/bonding/bond_sysfs.c +@@ -26,7 +26,6 @@ + #include <linux/module.h> + #include <linux/device.h> + #include <linux/sched.h> +-#include <linux/sysdev.h> + #include <linux/fs.h> + #include <linux/types.h> + #include <linux/string.h> +--- a/include/linux/kobject.h ++++ b/include/linux/kobject.h +@@ -191,8 +191,6 @@ static inline struct kobj_type *get_ktyp + } + + extern struct kobject *kset_find_obj(struct kset *, const char *); +-extern struct kobject *kset_find_obj_hinted(struct kset *, const char *, +- struct kobject *); + + /* The global /sys/kernel/ kobject for people to chain off of */ + extern struct kobject *kernel_kobj; +--- a/include/linux/sysdev.h ++++ /dev/null +@@ -1,164 +0,0 @@ +-/** +- * System devices follow a slightly different driver model. +- * They don't need to do dynammic driver binding, can't be probed, +- * and don't reside on any type of peripheral bus. +- * So, we represent and treat them a little differently. +- * +- * We still have a notion of a driver for a system device, because we still +- * want to perform basic operations on these devices. +- * +- * We also support auxiliary drivers binding to devices of a certain class. +- * +- * This allows configurable drivers to register themselves for devices of +- * a certain type. And, it allows class definitions to reside in generic +- * code while arch-specific code can register specific drivers. +- * +- * Auxiliary drivers registered with a NULL cls are registered as drivers +- * for all system devices, and get notification calls for each device. +- */ +- +- +-#ifndef _SYSDEV_H_ +-#define _SYSDEV_H_ +- +-#include <linux/kobject.h> +-#include <linux/pm.h> +- +- +-struct sys_device; +-struct sysdev_class_attribute; +- +-struct sysdev_class { +- const char *name; +- struct list_head drivers; +- struct sysdev_class_attribute **attrs; +- struct kset kset; +-}; +- +-struct sysdev_class_attribute { +- struct attribute attr; +- ssize_t (*show)(struct sysdev_class *, struct sysdev_class_attribute *, +- char *); +- ssize_t (*store)(struct sysdev_class *, struct sysdev_class_attribute *, +- const char *, size_t); +-}; +- +-#define _SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) \ +-{ \ +- .attr = {.name = __stringify(_name), .mode = _mode }, \ +- .show = _show, \ +- .store = _store, \ +-} +- +-#define SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) \ +- struct sysdev_class_attribute attr_##_name = \ +- _SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) +- +- +-extern int sysdev_class_register(struct sysdev_class *); +-extern void sysdev_class_unregister(struct sysdev_class *); +- +-extern int sysdev_class_create_file(struct sysdev_class *, +- struct sysdev_class_attribute *); +-extern void sysdev_class_remove_file(struct sysdev_class *, +- struct sysdev_class_attribute *); +-/** +- * Auxiliary system device drivers. +- */ +- +-struct sysdev_driver { +- struct list_head entry; +- int (*add)(struct sys_device *); +- int (*remove)(struct sys_device *); +-}; +- +- +-extern int sysdev_driver_register(struct sysdev_class *, struct sysdev_driver *); +-extern void sysdev_driver_unregister(struct sysdev_class *, struct sysdev_driver *); +- +- +-/** +- * sys_devices can be simplified a lot from regular devices, because they're +- * simply not as versatile. +- */ +- +-struct sys_device { +- u32 id; +- struct sysdev_class * cls; +- struct kobject kobj; +-}; +- +-extern int sysdev_register(struct sys_device *); +-extern void sysdev_unregister(struct sys_device *); +- +- +-struct sysdev_attribute { +- struct attribute attr; +- ssize_t (*show)(struct sys_device *, struct sysdev_attribute *, char *); +- ssize_t (*store)(struct sys_device *, struct sysdev_attribute *, +- const char *, size_t); +-}; +- +- +-#define _SYSDEV_ATTR(_name, _mode, _show, _store) \ +-{ \ +- .attr = { .name = __stringify(_name), .mode = _mode }, \ +- .show = _show, \ +- .store = _store, \ +-} +- +-#define SYSDEV_ATTR(_name, _mode, _show, _store) \ +- struct sysdev_attribute attr_##_name = \ +- _SYSDEV_ATTR(_name, _mode, _show, _store); +- +-extern int sysdev_create_file(struct sys_device *, struct sysdev_attribute *); +-extern void sysdev_remove_file(struct sys_device *, struct sysdev_attribute *); +- +-/* Create/remove NULL terminated attribute list */ +-static inline int +-sysdev_create_files(struct sys_device *d, struct sysdev_attribute **a) +-{ +- return sysfs_create_files(&d->kobj, (const struct attribute **)a); +-} +- +-static inline void +-sysdev_remove_files(struct sys_device *d, struct sysdev_attribute **a) +-{ +- return sysfs_remove_files(&d->kobj, (const struct attribute **)a); +-} +- +-struct sysdev_ext_attribute { +- struct sysdev_attribute attr; +- void *var; +-}; +- +-/* +- * Support for simple variable sysdev attributes. +- * The pointer to the variable is stored in a sysdev_ext_attribute +- */ +- +-/* Add more types as needed */ +- +-extern ssize_t sysdev_show_ulong(struct sys_device *, struct sysdev_attribute *, +- char *); +-extern ssize_t sysdev_store_ulong(struct sys_device *, +- struct sysdev_attribute *, const char *, size_t); +-extern ssize_t sysdev_show_int(struct sys_device *, struct sysdev_attribute *, +- char *); +-extern ssize_t sysdev_store_int(struct sys_device *, +- struct sysdev_attribute *, const char *, size_t); +- +-#define _SYSDEV_ULONG_ATTR(_name, _mode, _var) \ +- { _SYSDEV_ATTR(_name, _mode, sysdev_show_ulong, sysdev_store_ulong), \ +- &(_var) } +-#define SYSDEV_ULONG_ATTR(_name, _mode, _var) \ +- struct sysdev_ext_attribute attr_##_name = \ +- _SYSDEV_ULONG_ATTR(_name, _mode, _var); +-#define _SYSDEV_INT_ATTR(_name, _mode, _var) \ +- { _SYSDEV_ATTR(_name, _mode, sysdev_show_int, sysdev_store_int), \ +- &(_var) } +-#define SYSDEV_INT_ATTR(_name, _mode, _var) \ +- struct sysdev_ext_attribute attr_##_name = \ +- _SYSDEV_INT_ATTR(_name, _mode, _var); +- +-#endif /* _SYSDEV_H_ */ +--- a/kernel/time/clockevents.c ++++ b/kernel/time/clockevents.c +@@ -17,7 +17,6 @@ + #include <linux/module.h> + #include <linux/notifier.h> + #include <linux/smp.h> +-#include <linux/sysdev.h> + + #include "tick-internal.h" + +--- a/lib/kobject.c ++++ b/lib/kobject.c +@@ -746,43 +746,11 @@ void kset_unregister(struct kset *k) + */ + struct kobject *kset_find_obj(struct kset *kset, const char *name) + { +- return kset_find_obj_hinted(kset, name, NULL); +-} +- +-/** +- * kset_find_obj_hinted - search for object in kset given a predecessor hint. +- * @kset: kset we're looking in. +- * @name: object's name. +- * @hint: hint to possible object's predecessor. +- * +- * Check the hint's next object and if it is a match return it directly, +- * otherwise, fall back to the behavior of kset_find_obj(). Either way +- * a reference for the returned object is held and the reference on the +- * hinted object is released. +- */ +-struct kobject *kset_find_obj_hinted(struct kset *kset, const char *name, +- struct kobject *hint) +-{ + struct kobject *k; + struct kobject *ret = NULL; + + spin_lock(&kset->list_lock); + +- if (!hint) +- goto slow_search; +- +- /* end of list detection */ +- if (hint->entry.next == kset->list.next) +- goto slow_search; +- +- k = container_of(hint->entry.next, struct kobject, entry); +- if (!kobject_name(k) || strcmp(kobject_name(k), name)) +- goto slow_search; +- +- ret = kobject_get(k); +- goto unlock_exit; +- +-slow_search: + list_for_each_entry(k, &kset->list, entry) { + if (kobject_name(k) && !strcmp(kobject_name(k), name)) { + ret = kobject_get(k); +@@ -790,12 +758,7 @@ slow_search: + } + } + +-unlock_exit: + spin_unlock(&kset->list_lock); +- +- if (hint) +- kobject_put(hint); +- + return ret; + } + diff --git a/prctl-child_reaper.patch b/prctl-child_reaper.patch new file mode 100644 index 0000000..52bd372 --- /dev/null +++ b/prctl-child_reaper.patch @@ -0,0 +1,175 @@ +From: Lennart Poettering <lennart@poettering.net> +Subject: prctl: add PR_{SET,GET}_CHILD_SUBREAPER to allow simple process supervision + +Userspace service managers/supervisors need to track their started +services. Many services daemonize by double-forking and get implicitely +re-parented to PID 1. The service manager will no longer be able to +receive the SIGCHLD signals for them, and is no longer in charge of +reaping the children with wait(). All information about the children +is lost at the moment PID 1 cleans up the re-parented processes. + +With this prctl, a service manager process can mark itself as a sort of +'sub-init', able to stay as the parent for all orphaned processes +created by the started services. All SIGCHLD signals will be delivered +to the service manager. + +Receiving SIGCHLD and doing wait() is in cases of a service-manager +much preferred over any possible asynchronous notification about +specific PIDs, because the service manager has full access to the +child process data in /proc and the PID can not be re-used until +the wait(), the service-manager itself is in charge of, has happended. + +As a side effect, the relevant parent PID information does not get lost +by a double-fork, which results in a more elaborate process tree and 'ps' +output: + +before: + # ps afx + 253 ? Ss 0:00 /bin/dbus-daemon --system --nofork + 294 ? Sl 0:00 /usr/libexec/polkit-1/polkitd + 328 ? S 0:00 /usr/sbin/modem-manager + 608 ? Sl 0:00 /usr/libexec/colord + 658 ? Sl 0:00 /usr/libexec/upowerd + 819 ? Sl 0:00 /usr/libexec/imsettings-daemon + 916 ? Sl 0:00 /usr/libexec/udisks-daemon + 917 ? S 0:00 \_ udisks-daemon: not polling any devices + +after: + # ps afx + 294 ? Ss 0:00 /bin/dbus-daemon --system --nofork + 426 ? Sl 0:00 \_ /usr/libexec/polkit-1/polkitd + 449 ? S 0:00 \_ /usr/sbin/modem-manager + 635 ? Sl 0:00 \_ /usr/libexec/colord + 705 ? Sl 0:00 \_ /usr/libexec/upowerd + 959 ? Sl 0:00 \_ /usr/libexec/udisks-daemon + 960 ? S 0:00 | \_ udisks-daemon: not polling any devices + 977 ? Sl 0:00 \_ /usr/libexec/packagekitd + +This prctl is orthogonal to PID namespaces. PID namespaces are isolated +from each other, while a service management process usually requires +the services to live in the same namespace, to be able to talk to each +other. + +Users of this will be the systemd per-user instance, which provides +init-like functionality for the user's login session and D-Bus, which +activates bus services on-demand. Both need init-like capabilities +to be able to properly keep track of the services they start. + +Many thanks to Oleg for several rounds of review and insights. + +Reviewed-by: Oleg Nesterov <oleg@redhat.com> +Signed-off-by: Lennart Poettering <lennart@poettering.net> +Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> +--- + + include/linux/prctl.h | 3 +++ + include/linux/sched.h | 12 ++++++++++++ + kernel/exit.c | 28 +++++++++++++++++++++++----- + kernel/fork.c | 3 +++ + kernel/sys.c | 8 ++++++++ + 5 files changed, 49 insertions(+), 5 deletions(-) + +--- a/include/linux/prctl.h ++++ b/include/linux/prctl.h +@@ -102,4 +102,7 @@ + + #define PR_MCE_KILL_GET 34 + ++#define PR_SET_CHILD_SUBREAPER 35 ++#define PR_GET_CHILD_SUBREAPER 36 ++ + #endif /* _LINUX_PRCTL_H */ +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -550,6 +550,18 @@ struct signal_struct { + int group_stop_count; + unsigned int flags; /* see SIGNAL_* flags below */ + ++ /* ++ * PR_SET_CHILD_SUBREAPER marks a process, like a service ++ * manager, to re-parent orphan (double-forking) child processes ++ * to this process instead of 'init'. The service manager is ++ * able to receive SIGCHLD signals and is able to investigate ++ * the process until it calls wait(). All children of this ++ * process will inherit a flag if they should look for a ++ * child_subreaper process at exit. ++ */ ++ unsigned int is_child_subreaper:1; ++ unsigned int has_child_subreaper:1; ++ + /* POSIX.1b Interval Timers */ + struct list_head posix_timers; + +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -689,11 +689,12 @@ static void exit_mm(struct task_struct * + } + + /* +- * When we die, we re-parent all our children. +- * Try to give them to another thread in our thread +- * group, and if no such member exists, give it to +- * the child reaper process (ie "init") in our pid +- * space. ++ * When we die, we re-parent all our children, and try to: ++ * 1. give them to another thread in our thread group, if such a ++ * member exists ++ * 2. give it to the first anchestor process which prctl'd itself ++ * as a child_subreaper for its children (like a service manager) ++ * 3. give it to the init process (PID 1) in our pid namespace + */ + static struct task_struct *find_new_reaper(struct task_struct *father) + __releases(&tasklist_lock) +@@ -724,6 +725,23 @@ static struct task_struct *find_new_reap + * forget_original_parent() must move them somewhere. + */ + pid_ns->child_reaper = init_pid_ns.child_reaper; ++ } else if (father->signal->has_child_subreaper) { ++ struct task_struct *reaper; ++ ++ /* find the first ancestor marked as child_subreaper */ ++ for (reaper = father->real_parent; ++ reaper != &init_task; ++ reaper = reaper->real_parent) { ++ if (same_thread_group(reaper, pid_ns->child_reaper)) ++ break; ++ if (!reaper->signal->is_child_subreaper) ++ continue; ++ thread = reaper; ++ do { ++ if (!(thread->flags & PF_EXITING)) ++ return reaper; ++ } while_each_thread(reaper, thread); ++ } + } + + return pid_ns->child_reaper; +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -987,6 +987,9 @@ static int copy_signal(unsigned long clo + sig->oom_score_adj = current->signal->oom_score_adj; + sig->oom_score_adj_min = current->signal->oom_score_adj_min; + ++ sig->has_child_subreaper = current->signal->has_child_subreaper || ++ current->signal->is_child_subreaper; ++ + mutex_init(&sig->cred_guard_mutex); + + return 0; +--- a/kernel/sys.c ++++ b/kernel/sys.c +@@ -1799,6 +1799,14 @@ SYSCALL_DEFINE5(prctl, int, option, unsi + else + error = PR_MCE_KILL_DEFAULT; + break; ++ case PR_SET_CHILD_SUBREAPER: ++ me->signal->is_child_subreaper = !!arg2; ++ error = 0; ++ break; ++ case PR_GET_CHILD_SUBREAPER: ++ error = put_user(me->signal->is_child_subreaper, ++ (int __user *) arg2); ++ break; + default: + error = -EINVAL; + break; @@ -0,0 +1,9 @@ +01-core-support.patch +02-cpu.patch +03-memory.patch +04-rtmutex.patch +05-clocksource.patch +06-ibm-rtl.patch +07-edac.patch +08-xen.patch +99-core-remove.patch |