diff options
72 files changed, 1712 insertions, 1704 deletions
diff --git a/Documentation/DocBook/filesystems.tmpl b/Documentation/DocBook/filesystems.tmpl index 25b58efd955d..4f676838da06 100644 --- a/Documentation/DocBook/filesystems.tmpl +++ b/Documentation/DocBook/filesystems.tmpl | |||
| @@ -91,7 +91,6 @@ | |||
| 91 | <title>The Filesystem for Exporting Kernel Objects</title> | 91 | <title>The Filesystem for Exporting Kernel Objects</title> |
| 92 | !Efs/sysfs/file.c | 92 | !Efs/sysfs/file.c |
| 93 | !Efs/sysfs/symlink.c | 93 | !Efs/sysfs/symlink.c |
| 94 | !Efs/sysfs/bin.c | ||
| 95 | </chapter> | 94 | </chapter> |
| 96 | 95 | ||
| 97 | <chapter id="debugfs"> | 96 | <chapter id="debugfs"> |
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 16a7c2326d48..1114d13ac19f 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c | |||
| @@ -292,6 +292,7 @@ out: | |||
| 292 | return rc; | 292 | return rc; |
| 293 | return count; | 293 | return count; |
| 294 | } | 294 | } |
| 295 | static BUS_ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe); | ||
| 295 | 296 | ||
| 296 | static ssize_t ibmebus_store_remove(struct bus_type *bus, | 297 | static ssize_t ibmebus_store_remove(struct bus_type *bus, |
| 297 | const char *buf, size_t count) | 298 | const char *buf, size_t count) |
| @@ -317,13 +318,14 @@ static ssize_t ibmebus_store_remove(struct bus_type *bus, | |||
| 317 | return -ENODEV; | 318 | return -ENODEV; |
| 318 | } | 319 | } |
| 319 | } | 320 | } |
| 321 | static BUS_ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove); | ||
| 320 | 322 | ||
| 321 | 323 | static struct attribute *ibmbus_bus_attrs[] = { | |
| 322 | static struct bus_attribute ibmebus_bus_attrs[] = { | 324 | &bus_attr_probe.attr, |
| 323 | __ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe), | 325 | &bus_attr_remove.attr, |
| 324 | __ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove), | 326 | NULL, |
| 325 | __ATTR_NULL | ||
| 326 | }; | 327 | }; |
| 328 | ATTRIBUTE_GROUPS(ibmbus_bus); | ||
| 327 | 329 | ||
| 328 | static int ibmebus_bus_bus_match(struct device *dev, struct device_driver *drv) | 330 | static int ibmebus_bus_bus_match(struct device *dev, struct device_driver *drv) |
| 329 | { | 331 | { |
| @@ -713,7 +715,7 @@ static struct dev_pm_ops ibmebus_bus_dev_pm_ops = { | |||
| 713 | struct bus_type ibmebus_bus_type = { | 715 | struct bus_type ibmebus_bus_type = { |
| 714 | .name = "ibmebus", | 716 | .name = "ibmebus", |
| 715 | .uevent = of_device_uevent_modalias, | 717 | .uevent = of_device_uevent_modalias, |
| 716 | .bus_attrs = ibmebus_bus_attrs, | 718 | .bus_groups = ibmbus_bus_groups, |
| 717 | .match = ibmebus_bus_bus_match, | 719 | .match = ibmebus_bus_bus_match, |
| 718 | .probe = ibmebus_bus_device_probe, | 720 | .probe = ibmebus_bus_device_probe, |
| 719 | .remove = ibmebus_bus_device_remove, | 721 | .remove = ibmebus_bus_device_remove, |
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index d38cc08b16c7..408956fbf4f6 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c | |||
| @@ -997,21 +997,36 @@ static struct device_attribute vio_cmo_dev_attrs[] = { | |||
| 997 | /* sysfs bus functions and data structures for CMO */ | 997 | /* sysfs bus functions and data structures for CMO */ |
| 998 | 998 | ||
| 999 | #define viobus_cmo_rd_attr(name) \ | 999 | #define viobus_cmo_rd_attr(name) \ |
| 1000 | static ssize_t \ | 1000 | static ssize_t cmo_##name##_show(struct bus_type *bt, char *buf) \ |
| 1001 | viobus_cmo_##name##_show(struct bus_type *bt, char *buf) \ | ||
| 1002 | { \ | 1001 | { \ |
| 1003 | return sprintf(buf, "%lu\n", vio_cmo.name); \ | 1002 | return sprintf(buf, "%lu\n", vio_cmo.name); \ |
| 1004 | } | 1003 | } \ |
| 1004 | static BUS_ATTR_RO(cmo_##name) | ||
| 1005 | 1005 | ||
| 1006 | #define viobus_cmo_pool_rd_attr(name, var) \ | 1006 | #define viobus_cmo_pool_rd_attr(name, var) \ |
| 1007 | static ssize_t \ | 1007 | static ssize_t \ |
| 1008 | viobus_cmo_##name##_pool_show_##var(struct bus_type *bt, char *buf) \ | 1008 | cmo_##name##_##var##_show(struct bus_type *bt, char *buf) \ |
| 1009 | { \ | 1009 | { \ |
| 1010 | return sprintf(buf, "%lu\n", vio_cmo.name.var); \ | 1010 | return sprintf(buf, "%lu\n", vio_cmo.name.var); \ |
| 1011 | } \ | ||
| 1012 | static BUS_ATTR_RO(cmo_##name##_##var) | ||
| 1013 | |||
| 1014 | viobus_cmo_rd_attr(entitled); | ||
| 1015 | viobus_cmo_rd_attr(spare); | ||
| 1016 | viobus_cmo_rd_attr(min); | ||
| 1017 | viobus_cmo_rd_attr(desired); | ||
| 1018 | viobus_cmo_rd_attr(curr); | ||
| 1019 | viobus_cmo_pool_rd_attr(reserve, size); | ||
| 1020 | viobus_cmo_pool_rd_attr(excess, size); | ||
| 1021 | viobus_cmo_pool_rd_attr(excess, free); | ||
| 1022 | |||
| 1023 | static ssize_t cmo_high_show(struct bus_type *bt, char *buf) | ||
| 1024 | { | ||
| 1025 | return sprintf(buf, "%lu\n", vio_cmo.high); | ||
| 1011 | } | 1026 | } |
| 1012 | 1027 | ||
| 1013 | static ssize_t viobus_cmo_high_reset(struct bus_type *bt, const char *buf, | 1028 | static ssize_t cmo_high_store(struct bus_type *bt, const char *buf, |
| 1014 | size_t count) | 1029 | size_t count) |
| 1015 | { | 1030 | { |
| 1016 | unsigned long flags; | 1031 | unsigned long flags; |
| 1017 | 1032 | ||
| @@ -1021,35 +1036,26 @@ static ssize_t viobus_cmo_high_reset(struct bus_type *bt, const char *buf, | |||
| 1021 | 1036 | ||
| 1022 | return count; | 1037 | return count; |
| 1023 | } | 1038 | } |
| 1024 | 1039 | static BUS_ATTR_RW(cmo_high); | |
| 1025 | viobus_cmo_rd_attr(entitled); | 1040 | |
| 1026 | viobus_cmo_pool_rd_attr(reserve, size); | 1041 | static struct attribute *vio_bus_attrs[] = { |
| 1027 | viobus_cmo_pool_rd_attr(excess, size); | 1042 | &bus_attr_cmo_entitled.attr, |
| 1028 | viobus_cmo_pool_rd_attr(excess, free); | 1043 | &bus_attr_cmo_spare.attr, |
| 1029 | viobus_cmo_rd_attr(spare); | 1044 | &bus_attr_cmo_min.attr, |
| 1030 | viobus_cmo_rd_attr(min); | 1045 | &bus_attr_cmo_desired.attr, |
| 1031 | viobus_cmo_rd_attr(desired); | 1046 | &bus_attr_cmo_curr.attr, |
| 1032 | viobus_cmo_rd_attr(curr); | 1047 | &bus_attr_cmo_high.attr, |
| 1033 | viobus_cmo_rd_attr(high); | 1048 | &bus_attr_cmo_reserve_size.attr, |
| 1034 | 1049 | &bus_attr_cmo_excess_size.attr, | |
| 1035 | static struct bus_attribute vio_cmo_bus_attrs[] = { | 1050 | &bus_attr_cmo_excess_free.attr, |
| 1036 | __ATTR(cmo_entitled, S_IRUGO, viobus_cmo_entitled_show, NULL), | 1051 | NULL, |
| 1037 | __ATTR(cmo_reserve_size, S_IRUGO, viobus_cmo_reserve_pool_show_size, NULL), | ||
| 1038 | __ATTR(cmo_excess_size, S_IRUGO, viobus_cmo_excess_pool_show_size, NULL), | ||
| 1039 | __ATTR(cmo_excess_free, S_IRUGO, viobus_cmo_excess_pool_show_free, NULL), | ||
| 1040 | __ATTR(cmo_spare, S_IRUGO, viobus_cmo_spare_show, NULL), | ||
| 1041 | __ATTR(cmo_min, S_IRUGO, viobus_cmo_min_show, NULL), | ||
| 1042 | __ATTR(cmo_desired, S_IRUGO, viobus_cmo_desired_show, NULL), | ||
| 1043 | __ATTR(cmo_curr, S_IRUGO, viobus_cmo_curr_show, NULL), | ||
| 1044 | __ATTR(cmo_high, S_IWUSR|S_IRUSR|S_IWGRP|S_IRGRP|S_IROTH, | ||
| 1045 | viobus_cmo_high_show, viobus_cmo_high_reset), | ||
| 1046 | __ATTR_NULL | ||
| 1047 | }; | 1052 | }; |
| 1053 | ATTRIBUTE_GROUPS(vio_bus); | ||
| 1048 | 1054 | ||
| 1049 | static void vio_cmo_sysfs_init(void) | 1055 | static void vio_cmo_sysfs_init(void) |
| 1050 | { | 1056 | { |
| 1051 | vio_bus_type.dev_attrs = vio_cmo_dev_attrs; | 1057 | vio_bus_type.dev_attrs = vio_cmo_dev_attrs; |
| 1052 | vio_bus_type.bus_attrs = vio_cmo_bus_attrs; | 1058 | vio_bus_type.bus_groups = vio_bus_groups; |
| 1053 | } | 1059 | } |
| 1054 | #else /* CONFIG_PPC_SMLPAR */ | 1060 | #else /* CONFIG_PPC_SMLPAR */ |
| 1055 | int vio_cmo_entitlement_update(size_t new_entitlement) { return 0; } | 1061 | int vio_cmo_entitlement_update(size_t new_entitlement) { return 0; } |
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 4c289ab91357..73f6c2925281 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
| @@ -591,37 +591,6 @@ void bus_remove_device(struct device *dev) | |||
| 591 | bus_put(dev->bus); | 591 | bus_put(dev->bus); |
| 592 | } | 592 | } |
| 593 | 593 | ||
| 594 | static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv) | ||
| 595 | { | ||
| 596 | int error = 0; | ||
| 597 | int i; | ||
| 598 | |||
| 599 | if (bus->drv_attrs) { | ||
| 600 | for (i = 0; bus->drv_attrs[i].attr.name; i++) { | ||
| 601 | error = driver_create_file(drv, &bus->drv_attrs[i]); | ||
| 602 | if (error) | ||
| 603 | goto err; | ||
| 604 | } | ||
| 605 | } | ||
| 606 | done: | ||
| 607 | return error; | ||
| 608 | err: | ||
| 609 | while (--i >= 0) | ||
| 610 | driver_remove_file(drv, &bus->drv_attrs[i]); | ||
| 611 | goto done; | ||
| 612 | } | ||
| 613 | |||
| 614 | static void driver_remove_attrs(struct bus_type *bus, | ||
| 615 | struct device_driver *drv) | ||
| 616 | { | ||
| 617 | int i; | ||
| 618 | |||
| 619 | if (bus->drv_attrs) { | ||
| 620 | for (i = 0; bus->drv_attrs[i].attr.name; i++) | ||
| 621 | driver_remove_file(drv, &bus->drv_attrs[i]); | ||
| 622 | } | ||
| 623 | } | ||
| 624 | |||
| 625 | static int __must_check add_bind_files(struct device_driver *drv) | 594 | static int __must_check add_bind_files(struct device_driver *drv) |
| 626 | { | 595 | { |
| 627 | int ret; | 596 | int ret; |
| @@ -720,16 +689,12 @@ int bus_add_driver(struct device_driver *drv) | |||
| 720 | printk(KERN_ERR "%s: uevent attr (%s) failed\n", | 689 | printk(KERN_ERR "%s: uevent attr (%s) failed\n", |
| 721 | __func__, drv->name); | 690 | __func__, drv->name); |
| 722 | } | 691 | } |
| 723 | error = driver_add_attrs(bus, drv); | 692 | error = driver_add_groups(drv, bus->drv_groups); |
| 724 | if (error) { | 693 | if (error) { |
| 725 | /* How the hell do we get out of this pickle? Give up */ | 694 | /* How the hell do we get out of this pickle? Give up */ |
| 726 | printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n", | ||
| 727 | __func__, drv->name); | ||
| 728 | } | ||
| 729 | error = driver_add_groups(drv, bus->drv_groups); | ||
| 730 | if (error) | ||
| 731 | printk(KERN_ERR "%s: driver_create_groups(%s) failed\n", | 695 | printk(KERN_ERR "%s: driver_create_groups(%s) failed\n", |
| 732 | __func__, drv->name); | 696 | __func__, drv->name); |
| 697 | } | ||
| 733 | 698 | ||
| 734 | if (!drv->suppress_bind_attrs) { | 699 | if (!drv->suppress_bind_attrs) { |
| 735 | error = add_bind_files(drv); | 700 | error = add_bind_files(drv); |
| @@ -766,7 +731,6 @@ void bus_remove_driver(struct device_driver *drv) | |||
| 766 | 731 | ||
| 767 | if (!drv->suppress_bind_attrs) | 732 | if (!drv->suppress_bind_attrs) |
| 768 | remove_bind_files(drv); | 733 | remove_bind_files(drv); |
| 769 | driver_remove_attrs(drv->bus, drv); | ||
| 770 | driver_remove_groups(drv, drv->bus->drv_groups); | 734 | driver_remove_groups(drv, drv->bus->drv_groups); |
| 771 | driver_remove_file(drv, &driver_attr_uevent); | 735 | driver_remove_file(drv, &driver_attr_uevent); |
| 772 | klist_remove(&drv->p->knode_bus); | 736 | klist_remove(&drv->p->knode_bus); |
| @@ -846,42 +810,6 @@ struct bus_type *find_bus(char *name) | |||
| 846 | } | 810 | } |
| 847 | #endif /* 0 */ | 811 | #endif /* 0 */ |
| 848 | 812 | ||
| 849 | |||
| 850 | /** | ||
| 851 | * bus_add_attrs - Add default attributes for this bus. | ||
| 852 | * @bus: Bus that has just been registered. | ||
| 853 | */ | ||
| 854 | |||
| 855 | static int bus_add_attrs(struct bus_type *bus) | ||
| 856 | { | ||
| 857 | int error = 0; | ||
| 858 | int i; | ||
| 859 | |||
| 860 | if (bus->bus_attrs) { | ||
| 861 | for (i = 0; bus->bus_attrs[i].attr.name; i++) { | ||
| 862 | error = bus_create_file(bus, &bus->bus_attrs[i]); | ||
| 863 | if (error) | ||
| 864 | goto err; | ||
| 865 | } | ||
| 866 | } | ||
| 867 | done: | ||
| 868 | return error; | ||
| 869 | err: | ||
| 870 | while (--i >= 0) | ||
| 871 | bus_remove_file(bus, &bus->bus_attrs[i]); | ||
| 872 | goto done; | ||
| 873 | } | ||
| 874 | |||
| 875 | static void bus_remove_attrs(struct bus_type *bus) | ||
| 876 | { | ||
| 877 | int i; | ||
| 878 | |||
| 879 | if (bus->bus_attrs) { | ||
| 880 | for (i = 0; bus->bus_attrs[i].attr.name; i++) | ||
| 881 | bus_remove_file(bus, &bus->bus_attrs[i]); | ||
| 882 | } | ||
| 883 | } | ||
| 884 | |||
| 885 | static int bus_add_groups(struct bus_type *bus, | 813 | static int bus_add_groups(struct bus_type *bus, |
| 886 | const struct attribute_group **groups) | 814 | const struct attribute_group **groups) |
| 887 | { | 815 | { |
| @@ -983,9 +911,6 @@ int bus_register(struct bus_type *bus) | |||
| 983 | if (retval) | 911 | if (retval) |
| 984 | goto bus_probe_files_fail; | 912 | goto bus_probe_files_fail; |
| 985 | 913 | ||
| 986 | retval = bus_add_attrs(bus); | ||
| 987 | if (retval) | ||
| 988 | goto bus_attrs_fail; | ||
| 989 | retval = bus_add_groups(bus, bus->bus_groups); | 914 | retval = bus_add_groups(bus, bus->bus_groups); |
| 990 | if (retval) | 915 | if (retval) |
| 991 | goto bus_groups_fail; | 916 | goto bus_groups_fail; |
| @@ -994,8 +919,6 @@ int bus_register(struct bus_type *bus) | |||
| 994 | return 0; | 919 | return 0; |
| 995 | 920 | ||
| 996 | bus_groups_fail: | 921 | bus_groups_fail: |
| 997 | bus_remove_attrs(bus); | ||
| 998 | bus_attrs_fail: | ||
| 999 | remove_probe_files(bus); | 922 | remove_probe_files(bus); |
| 1000 | bus_probe_files_fail: | 923 | bus_probe_files_fail: |
| 1001 | kset_unregister(bus->p->drivers_kset); | 924 | kset_unregister(bus->p->drivers_kset); |
| @@ -1024,7 +947,6 @@ void bus_unregister(struct bus_type *bus) | |||
| 1024 | pr_debug("bus: '%s': unregistering\n", bus->name); | 947 | pr_debug("bus: '%s': unregistering\n", bus->name); |
| 1025 | if (bus->dev_root) | 948 | if (bus->dev_root) |
| 1026 | device_unregister(bus->dev_root); | 949 | device_unregister(bus->dev_root); |
| 1027 | bus_remove_attrs(bus); | ||
| 1028 | bus_remove_groups(bus, bus->bus_groups); | 950 | bus_remove_groups(bus, bus->bus_groups); |
| 1029 | remove_probe_files(bus); | 951 | remove_probe_files(bus); |
| 1030 | kset_unregister(bus->p->drivers_kset); | 952 | kset_unregister(bus->p->drivers_kset); |
diff --git a/drivers/base/class.c b/drivers/base/class.c index 8b7818b80056..f96f70419a78 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
| @@ -47,18 +47,6 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, | |||
| 47 | return ret; | 47 | return ret; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static const void *class_attr_namespace(struct kobject *kobj, | ||
| 51 | const struct attribute *attr) | ||
| 52 | { | ||
| 53 | struct class_attribute *class_attr = to_class_attr(attr); | ||
| 54 | struct subsys_private *cp = to_subsys_private(kobj); | ||
| 55 | const void *ns = NULL; | ||
| 56 | |||
| 57 | if (class_attr->namespace) | ||
| 58 | ns = class_attr->namespace(cp->class, class_attr); | ||
| 59 | return ns; | ||
| 60 | } | ||
| 61 | |||
| 62 | static void class_release(struct kobject *kobj) | 50 | static void class_release(struct kobject *kobj) |
| 63 | { | 51 | { |
| 64 | struct subsys_private *cp = to_subsys_private(kobj); | 52 | struct subsys_private *cp = to_subsys_private(kobj); |
| @@ -86,7 +74,6 @@ static const struct kobj_ns_type_operations *class_child_ns_type(struct kobject | |||
| 86 | static const struct sysfs_ops class_sysfs_ops = { | 74 | static const struct sysfs_ops class_sysfs_ops = { |
| 87 | .show = class_attr_show, | 75 | .show = class_attr_show, |
| 88 | .store = class_attr_store, | 76 | .store = class_attr_store, |
| 89 | .namespace = class_attr_namespace, | ||
| 90 | }; | 77 | }; |
| 91 | 78 | ||
| 92 | static struct kobj_type class_ktype = { | 79 | static struct kobj_type class_ktype = { |
| @@ -99,21 +86,23 @@ static struct kobj_type class_ktype = { | |||
| 99 | static struct kset *class_kset; | 86 | static struct kset *class_kset; |
| 100 | 87 | ||
| 101 | 88 | ||
| 102 | int class_create_file(struct class *cls, const struct class_attribute *attr) | 89 | int class_create_file_ns(struct class *cls, const struct class_attribute *attr, |
| 90 | const void *ns) | ||
| 103 | { | 91 | { |
| 104 | int error; | 92 | int error; |
| 105 | if (cls) | 93 | if (cls) |
| 106 | error = sysfs_create_file(&cls->p->subsys.kobj, | 94 | error = sysfs_create_file_ns(&cls->p->subsys.kobj, |
| 107 | &attr->attr); | 95 | &attr->attr, ns); |
| 108 | else | 96 | else |
| 109 | error = -EINVAL; | 97 | error = -EINVAL; |
| 110 | return error; | 98 | return error; |
| 111 | } | 99 | } |
| 112 | 100 | ||
| 113 | void class_remove_file(struct class *cls, const struct class_attribute *attr) | 101 | void class_remove_file_ns(struct class *cls, const struct class_attribute *attr, |
| 102 | const void *ns) | ||
| 114 | { | 103 | { |
| 115 | if (cls) | 104 | if (cls) |
| 116 | sysfs_remove_file(&cls->p->subsys.kobj, &attr->attr); | 105 | sysfs_remove_file_ns(&cls->p->subsys.kobj, &attr->attr, ns); |
| 117 | } | 106 | } |
| 118 | 107 | ||
| 119 | static struct class *class_get(struct class *cls) | 108 | static struct class *class_get(struct class *cls) |
| @@ -600,8 +589,8 @@ int __init classes_init(void) | |||
| 600 | return 0; | 589 | return 0; |
| 601 | } | 590 | } |
| 602 | 591 | ||
| 603 | EXPORT_SYMBOL_GPL(class_create_file); | 592 | EXPORT_SYMBOL_GPL(class_create_file_ns); |
| 604 | EXPORT_SYMBOL_GPL(class_remove_file); | 593 | EXPORT_SYMBOL_GPL(class_remove_file_ns); |
| 605 | EXPORT_SYMBOL_GPL(class_unregister); | 594 | EXPORT_SYMBOL_GPL(class_unregister); |
| 606 | EXPORT_SYMBOL_GPL(class_destroy); | 595 | EXPORT_SYMBOL_GPL(class_destroy); |
| 607 | 596 | ||
diff --git a/drivers/base/core.c b/drivers/base/core.c index 34abf4d8a45f..67b180d855b2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
| @@ -455,64 +455,6 @@ static ssize_t online_store(struct device *dev, struct device_attribute *attr, | |||
| 455 | } | 455 | } |
| 456 | static DEVICE_ATTR_RW(online); | 456 | static DEVICE_ATTR_RW(online); |
| 457 | 457 | ||
| 458 | static int device_add_attributes(struct device *dev, | ||
| 459 | struct device_attribute *attrs) | ||
| 460 | { | ||
| 461 | int error = 0; | ||
| 462 | int i; | ||
| 463 | |||
| 464 | if (attrs) { | ||
| 465 | for (i = 0; attrs[i].attr.name; i++) { | ||
| 466 | error = device_create_file(dev, &attrs[i]); | ||
| 467 | if (error) | ||
| 468 | break; | ||
| 469 | } | ||
| 470 | if (error) | ||
| 471 | while (--i >= 0) | ||
| 472 | device_remove_file(dev, &attrs[i]); | ||
| 473 | } | ||
| 474 | return error; | ||
| 475 | } | ||
| 476 | |||
| 477 | static void device_remove_attributes(struct device *dev, | ||
| 478 | struct device_attribute *attrs) | ||
| 479 | { | ||
| 480 | int i; | ||
| 481 | |||
| 482 | if (attrs) | ||
| 483 | for (i = 0; attrs[i].attr.name; i++) | ||
| 484 | device_remove_file(dev, &attrs[i]); | ||
| 485 | } | ||
| 486 | |||
| 487 | static int device_add_bin_attributes(struct device *dev, | ||
| 488 | struct bin_attribute *attrs) | ||
| 489 | { | ||
| 490 | int error = 0; | ||
| 491 | int i; | ||
| 492 | |||
| 493 | if (attrs) { | ||
| 494 | for (i = 0; attrs[i].attr.name; i++) { | ||
| 495 | error = device_create_bin_file(dev, &attrs[i]); | ||
| 496 | if (error) | ||
| 497 | break; | ||
| 498 | } | ||
| 499 | if (error) | ||
| 500 | while (--i >= 0) | ||
| 501 | device_remove_bin_file(dev, &attrs[i]); | ||
| 502 | } | ||
| 503 | return error; | ||
| 504 | } | ||
| 505 | |||
| 506 | static void device_remove_bin_attributes(struct device *dev, | ||
| 507 | struct bin_attribute *attrs) | ||
| 508 | { | ||
| 509 | int i; | ||
| 510 | |||
| 511 | if (attrs) | ||
| 512 | for (i = 0; attrs[i].attr.name; i++) | ||
| 513 | device_remove_bin_file(dev, &attrs[i]); | ||
| 514 | } | ||
| 515 | |||
| 516 | int device_add_groups(struct device *dev, const struct attribute_group **groups) | 458 | int device_add_groups(struct device *dev, const struct attribute_group **groups) |
| 517 | { | 459 | { |
| 518 | return sysfs_create_groups(&dev->kobj, groups); | 460 | return sysfs_create_groups(&dev->kobj, groups); |
| @@ -534,18 +476,12 @@ static int device_add_attrs(struct device *dev) | |||
| 534 | error = device_add_groups(dev, class->dev_groups); | 476 | error = device_add_groups(dev, class->dev_groups); |
| 535 | if (error) | 477 | if (error) |
| 536 | return error; | 478 | return error; |
| 537 | error = device_add_attributes(dev, class->dev_attrs); | ||
| 538 | if (error) | ||
| 539 | goto err_remove_class_groups; | ||
| 540 | error = device_add_bin_attributes(dev, class->dev_bin_attrs); | ||
| 541 | if (error) | ||
| 542 | goto err_remove_class_attrs; | ||
| 543 | } | 479 | } |
| 544 | 480 | ||
| 545 | if (type) { | 481 | if (type) { |
| 546 | error = device_add_groups(dev, type->groups); | 482 | error = device_add_groups(dev, type->groups); |
| 547 | if (error) | 483 | if (error) |
| 548 | goto err_remove_class_bin_attrs; | 484 | goto err_remove_class_groups; |
| 549 | } | 485 | } |
| 550 | 486 | ||
| 551 | error = device_add_groups(dev, dev->groups); | 487 | error = device_add_groups(dev, dev->groups); |
| @@ -563,12 +499,6 @@ static int device_add_attrs(struct device *dev) | |||
| 563 | err_remove_type_groups: | 499 | err_remove_type_groups: |
| 564 | if (type) | 500 | if (type) |
| 565 | device_remove_groups(dev, type->groups); | 501 | device_remove_groups(dev, type->groups); |
| 566 | err_remove_class_bin_attrs: | ||
| 567 | if (class) | ||
| 568 | device_remove_bin_attributes(dev, class->dev_bin_attrs); | ||
| 569 | err_remove_class_attrs: | ||
| 570 | if (class) | ||
| 571 | device_remove_attributes(dev, class->dev_attrs); | ||
| 572 | err_remove_class_groups: | 502 | err_remove_class_groups: |
| 573 | if (class) | 503 | if (class) |
| 574 | device_remove_groups(dev, class->dev_groups); | 504 | device_remove_groups(dev, class->dev_groups); |
| @@ -587,11 +517,8 @@ static void device_remove_attrs(struct device *dev) | |||
| 587 | if (type) | 517 | if (type) |
| 588 | device_remove_groups(dev, type->groups); | 518 | device_remove_groups(dev, type->groups); |
| 589 | 519 | ||
| 590 | if (class) { | 520 | if (class) |
| 591 | device_remove_attributes(dev, class->dev_attrs); | ||
| 592 | device_remove_bin_attributes(dev, class->dev_bin_attrs); | ||
| 593 | device_remove_groups(dev, class->dev_groups); | 521 | device_remove_groups(dev, class->dev_groups); |
| 594 | } | ||
| 595 | } | 522 | } |
| 596 | 523 | ||
| 597 | static ssize_t dev_show(struct device *dev, struct device_attribute *attr, | 524 | static ssize_t dev_show(struct device *dev, struct device_attribute *attr, |
| @@ -1881,6 +1808,7 @@ EXPORT_SYMBOL_GPL(device_destroy); | |||
| 1881 | */ | 1808 | */ |
| 1882 | int device_rename(struct device *dev, const char *new_name) | 1809 | int device_rename(struct device *dev, const char *new_name) |
| 1883 | { | 1810 | { |
| 1811 | struct kobject *kobj = &dev->kobj; | ||
| 1884 | char *old_device_name = NULL; | 1812 | char *old_device_name = NULL; |
| 1885 | int error; | 1813 | int error; |
| 1886 | 1814 | ||
| @@ -1888,8 +1816,7 @@ int device_rename(struct device *dev, const char *new_name) | |||
| 1888 | if (!dev) | 1816 | if (!dev) |
| 1889 | return -EINVAL; | 1817 | return -EINVAL; |
| 1890 | 1818 | ||
| 1891 | pr_debug("device: '%s': %s: renaming to '%s'\n", dev_name(dev), | 1819 | dev_dbg(dev, "renaming to %s\n", new_name); |
| 1892 | __func__, new_name); | ||
| 1893 | 1820 | ||
| 1894 | old_device_name = kstrdup(dev_name(dev), GFP_KERNEL); | 1821 | old_device_name = kstrdup(dev_name(dev), GFP_KERNEL); |
| 1895 | if (!old_device_name) { | 1822 | if (!old_device_name) { |
| @@ -1898,13 +1825,14 @@ int device_rename(struct device *dev, const char *new_name) | |||
| 1898 | } | 1825 | } |
| 1899 | 1826 | ||
| 1900 | if (dev->class) { | 1827 | if (dev->class) { |
| 1901 | error = sysfs_rename_link(&dev->class->p->subsys.kobj, | 1828 | error = sysfs_rename_link_ns(&dev->class->p->subsys.kobj, |
| 1902 | &dev->kobj, old_device_name, new_name); | 1829 | kobj, old_device_name, |
| 1830 | new_name, kobject_namespace(kobj)); | ||
| 1903 | if (error) | 1831 | if (error) |
| 1904 | goto out; | 1832 | goto out; |
| 1905 | } | 1833 | } |
| 1906 | 1834 | ||
| 1907 | error = kobject_rename(&dev->kobj, new_name); | 1835 | error = kobject_rename(kobj, new_name); |
| 1908 | if (error) | 1836 | if (error) |
| 1909 | goto out; | 1837 | goto out; |
| 1910 | 1838 | ||
diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 507379e7b763..545c4de412c3 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c | |||
| @@ -91,7 +91,8 @@ static __always_inline struct devres * alloc_dr(dr_release_t release, | |||
| 91 | if (unlikely(!dr)) | 91 | if (unlikely(!dr)) |
| 92 | return NULL; | 92 | return NULL; |
| 93 | 93 | ||
| 94 | memset(dr, 0, tot_size); | 94 | memset(dr, 0, offsetof(struct devres, data)); |
| 95 | |||
| 95 | INIT_LIST_HEAD(&dr->node.entry); | 96 | INIT_LIST_HEAD(&dr->node.entry); |
| 96 | dr->node.release = release; | 97 | dr->node.release = release; |
| 97 | return dr; | 98 | return dr; |
| @@ -110,7 +111,7 @@ void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp, | |||
| 110 | { | 111 | { |
| 111 | struct devres *dr; | 112 | struct devres *dr; |
| 112 | 113 | ||
| 113 | dr = alloc_dr(release, size, gfp); | 114 | dr = alloc_dr(release, size, gfp | __GFP_ZERO); |
| 114 | if (unlikely(!dr)) | 115 | if (unlikely(!dr)) |
| 115 | return NULL; | 116 | return NULL; |
| 116 | set_node_dbginfo(&dr->node, name, size); | 117 | set_node_dbginfo(&dr->node, name, size); |
| @@ -135,7 +136,7 @@ void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp) | |||
| 135 | { | 136 | { |
| 136 | struct devres *dr; | 137 | struct devres *dr; |
| 137 | 138 | ||
| 138 | dr = alloc_dr(release, size, gfp); | 139 | dr = alloc_dr(release, size, gfp | __GFP_ZERO); |
| 139 | if (unlikely(!dr)) | 140 | if (unlikely(!dr)) |
| 140 | return NULL; | 141 | return NULL; |
| 141 | return dr->data; | 142 | return dr->data; |
| @@ -745,58 +746,62 @@ void devm_remove_action(struct device *dev, void (*action)(void *), void *data) | |||
| 745 | EXPORT_SYMBOL_GPL(devm_remove_action); | 746 | EXPORT_SYMBOL_GPL(devm_remove_action); |
| 746 | 747 | ||
| 747 | /* | 748 | /* |
| 748 | * Managed kzalloc/kfree | 749 | * Managed kmalloc/kfree |
| 749 | */ | 750 | */ |
| 750 | static void devm_kzalloc_release(struct device *dev, void *res) | 751 | static void devm_kmalloc_release(struct device *dev, void *res) |
| 751 | { | 752 | { |
| 752 | /* noop */ | 753 | /* noop */ |
| 753 | } | 754 | } |
| 754 | 755 | ||
| 755 | static int devm_kzalloc_match(struct device *dev, void *res, void *data) | 756 | static int devm_kmalloc_match(struct device *dev, void *res, void *data) |
| 756 | { | 757 | { |
| 757 | return res == data; | 758 | return res == data; |
| 758 | } | 759 | } |
| 759 | 760 | ||
| 760 | /** | 761 | /** |
| 761 | * devm_kzalloc - Resource-managed kzalloc | 762 | * devm_kmalloc - Resource-managed kmalloc |
| 762 | * @dev: Device to allocate memory for | 763 | * @dev: Device to allocate memory for |
| 763 | * @size: Allocation size | 764 | * @size: Allocation size |
| 764 | * @gfp: Allocation gfp flags | 765 | * @gfp: Allocation gfp flags |
| 765 | * | 766 | * |
| 766 | * Managed kzalloc. Memory allocated with this function is | 767 | * Managed kmalloc. Memory allocated with this function is |
| 767 | * automatically freed on driver detach. Like all other devres | 768 | * automatically freed on driver detach. Like all other devres |
| 768 | * resources, guaranteed alignment is unsigned long long. | 769 | * resources, guaranteed alignment is unsigned long long. |
| 769 | * | 770 | * |
| 770 | * RETURNS: | 771 | * RETURNS: |
| 771 | * Pointer to allocated memory on success, NULL on failure. | 772 | * Pointer to allocated memory on success, NULL on failure. |
| 772 | */ | 773 | */ |
| 773 | void * devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) | 774 | void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) |
| 774 | { | 775 | { |
| 775 | struct devres *dr; | 776 | struct devres *dr; |
| 776 | 777 | ||
| 777 | /* use raw alloc_dr for kmalloc caller tracing */ | 778 | /* use raw alloc_dr for kmalloc caller tracing */ |
| 778 | dr = alloc_dr(devm_kzalloc_release, size, gfp); | 779 | dr = alloc_dr(devm_kmalloc_release, size, gfp); |
| 779 | if (unlikely(!dr)) | 780 | if (unlikely(!dr)) |
| 780 | return NULL; | 781 | return NULL; |
| 781 | 782 | ||
| 783 | /* | ||
| 784 | * This is named devm_kzalloc_release for historical reasons | ||
| 785 | * The initial implementation did not support kmalloc, only kzalloc | ||
| 786 | */ | ||
| 782 | set_node_dbginfo(&dr->node, "devm_kzalloc_release", size); | 787 | set_node_dbginfo(&dr->node, "devm_kzalloc_release", size); |
| 783 | devres_add(dev, dr->data); | 788 | devres_add(dev, dr->data); |
| 784 | return dr->data; | 789 | return dr->data; |
| 785 | } | 790 | } |
| 786 | EXPORT_SYMBOL_GPL(devm_kzalloc); | 791 | EXPORT_SYMBOL_GPL(devm_kmalloc); |
| 787 | 792 | ||
| 788 | /** | 793 | /** |
| 789 | * devm_kfree - Resource-managed kfree | 794 | * devm_kfree - Resource-managed kfree |
| 790 | * @dev: Device this memory belongs to | 795 | * @dev: Device this memory belongs to |
| 791 | * @p: Memory to free | 796 | * @p: Memory to free |
| 792 | * | 797 | * |
| 793 | * Free memory allocated with devm_kzalloc(). | 798 | * Free memory allocated with devm_kmalloc(). |
| 794 | */ | 799 | */ |
| 795 | void devm_kfree(struct device *dev, void *p) | 800 | void devm_kfree(struct device *dev, void *p) |
| 796 | { | 801 | { |
| 797 | int rc; | 802 | int rc; |
| 798 | 803 | ||
| 799 | rc = devres_destroy(dev, devm_kzalloc_release, devm_kzalloc_match, p); | 804 | rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p); |
| 800 | WARN_ON(rc); | 805 | WARN_ON(rc); |
| 801 | } | 806 | } |
| 802 | EXPORT_SYMBOL_GPL(devm_kfree); | 807 | EXPORT_SYMBOL_GPL(devm_kfree); |
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 10a4467c63f1..eb8fb94ae2c5 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
| @@ -282,31 +282,35 @@ static noinline_for_stack long fw_file_size(struct file *file) | |||
| 282 | return st.size; | 282 | return st.size; |
| 283 | } | 283 | } |
| 284 | 284 | ||
| 285 | static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf) | 285 | static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf) |
| 286 | { | 286 | { |
| 287 | long size; | 287 | long size; |
| 288 | char *buf; | 288 | char *buf; |
| 289 | int rc; | ||
| 289 | 290 | ||
| 290 | size = fw_file_size(file); | 291 | size = fw_file_size(file); |
| 291 | if (size <= 0) | 292 | if (size <= 0) |
| 292 | return false; | 293 | return -EINVAL; |
| 293 | buf = vmalloc(size); | 294 | buf = vmalloc(size); |
| 294 | if (!buf) | 295 | if (!buf) |
| 295 | return false; | 296 | return -ENOMEM; |
| 296 | if (kernel_read(file, 0, buf, size) != size) { | 297 | rc = kernel_read(file, 0, buf, size); |
| 298 | if (rc != size) { | ||
| 299 | if (rc > 0) | ||
| 300 | rc = -EIO; | ||
| 297 | vfree(buf); | 301 | vfree(buf); |
| 298 | return false; | 302 | return rc; |
| 299 | } | 303 | } |
| 300 | fw_buf->data = buf; | 304 | fw_buf->data = buf; |
| 301 | fw_buf->size = size; | 305 | fw_buf->size = size; |
| 302 | return true; | 306 | return 0; |
| 303 | } | 307 | } |
| 304 | 308 | ||
| 305 | static bool fw_get_filesystem_firmware(struct device *device, | 309 | static int fw_get_filesystem_firmware(struct device *device, |
| 306 | struct firmware_buf *buf) | 310 | struct firmware_buf *buf) |
| 307 | { | 311 | { |
| 308 | int i; | 312 | int i; |
| 309 | bool success = false; | 313 | int rc = -ENOENT; |
| 310 | char *path = __getname(); | 314 | char *path = __getname(); |
| 311 | 315 | ||
| 312 | for (i = 0; i < ARRAY_SIZE(fw_path); i++) { | 316 | for (i = 0; i < ARRAY_SIZE(fw_path); i++) { |
| @@ -321,14 +325,17 @@ static bool fw_get_filesystem_firmware(struct device *device, | |||
| 321 | file = filp_open(path, O_RDONLY, 0); | 325 | file = filp_open(path, O_RDONLY, 0); |
| 322 | if (IS_ERR(file)) | 326 | if (IS_ERR(file)) |
| 323 | continue; | 327 | continue; |
| 324 | success = fw_read_file_contents(file, buf); | 328 | rc = fw_read_file_contents(file, buf); |
| 325 | fput(file); | 329 | fput(file); |
| 326 | if (success) | 330 | if (rc) |
| 331 | dev_warn(device, "firmware, attempted to load %s, but failed with error %d\n", | ||
| 332 | path, rc); | ||
| 333 | else | ||
| 327 | break; | 334 | break; |
| 328 | } | 335 | } |
| 329 | __putname(path); | 336 | __putname(path); |
| 330 | 337 | ||
| 331 | if (success) { | 338 | if (!rc) { |
| 332 | dev_dbg(device, "firmware: direct-loading firmware %s\n", | 339 | dev_dbg(device, "firmware: direct-loading firmware %s\n", |
| 333 | buf->fw_id); | 340 | buf->fw_id); |
| 334 | mutex_lock(&fw_lock); | 341 | mutex_lock(&fw_lock); |
| @@ -337,7 +344,7 @@ static bool fw_get_filesystem_firmware(struct device *device, | |||
| 337 | mutex_unlock(&fw_lock); | 344 | mutex_unlock(&fw_lock); |
| 338 | } | 345 | } |
| 339 | 346 | ||
| 340 | return success; | 347 | return rc; |
| 341 | } | 348 | } |
| 342 | 349 | ||
| 343 | /* firmware holds the ownership of pages */ | 350 | /* firmware holds the ownership of pages */ |
| @@ -1086,9 +1093,14 @@ _request_firmware(const struct firmware **firmware_p, const char *name, | |||
| 1086 | } | 1093 | } |
| 1087 | } | 1094 | } |
| 1088 | 1095 | ||
| 1089 | if (!fw_get_filesystem_firmware(device, fw->priv)) | 1096 | ret = fw_get_filesystem_firmware(device, fw->priv); |
| 1097 | if (ret) { | ||
| 1098 | dev_warn(device, "Direct firmware load failed with error %d\n", | ||
| 1099 | ret); | ||
| 1100 | dev_warn(device, "Falling back to user helper\n"); | ||
| 1090 | ret = fw_load_from_user_helper(fw, name, device, | 1101 | ret = fw_load_from_user_helper(fw, name, device, |
| 1091 | uevent, nowait, timeout); | 1102 | uevent, nowait, timeout); |
| 1103 | } | ||
| 1092 | 1104 | ||
| 1093 | /* don't cache firmware handled without uevent */ | 1105 | /* don't cache firmware handled without uevent */ |
| 1094 | if (!ret) | 1106 | if (!ret) |
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 4f8bef3eb5a8..47051cd25113 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
| @@ -488,6 +488,11 @@ static int platform_drv_probe(struct device *_dev) | |||
| 488 | if (ret && ACPI_HANDLE(_dev)) | 488 | if (ret && ACPI_HANDLE(_dev)) |
| 489 | acpi_dev_pm_detach(_dev, true); | 489 | acpi_dev_pm_detach(_dev, true); |
| 490 | 490 | ||
| 491 | if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { | ||
| 492 | dev_warn(_dev, "probe deferral not supported\n"); | ||
| 493 | ret = -ENXIO; | ||
| 494 | } | ||
| 495 | |||
| 491 | return ret; | 496 | return ret; |
| 492 | } | 497 | } |
| 493 | 498 | ||
| @@ -553,8 +558,7 @@ EXPORT_SYMBOL_GPL(platform_driver_unregister); | |||
| 553 | /** | 558 | /** |
| 554 | * platform_driver_probe - register driver for non-hotpluggable device | 559 | * platform_driver_probe - register driver for non-hotpluggable device |
| 555 | * @drv: platform driver structure | 560 | * @drv: platform driver structure |
| 556 | * @probe: the driver probe routine, probably from an __init section, | 561 | * @probe: the driver probe routine, probably from an __init section |
| 557 | * must not return -EPROBE_DEFER. | ||
| 558 | * | 562 | * |
| 559 | * Use this instead of platform_driver_register() when you know the device | 563 | * Use this instead of platform_driver_register() when you know the device |
| 560 | * is not hotpluggable and has already been registered, and you want to | 564 | * is not hotpluggable and has already been registered, and you want to |
| @@ -565,8 +569,7 @@ EXPORT_SYMBOL_GPL(platform_driver_unregister); | |||
| 565 | * into system-on-chip processors, where the controller devices have been | 569 | * into system-on-chip processors, where the controller devices have been |
| 566 | * configured as part of board setup. | 570 | * configured as part of board setup. |
| 567 | * | 571 | * |
| 568 | * This is incompatible with deferred probing so probe() must not | 572 | * Note that this is incompatible with deferred probing. |
| 569 | * return -EPROBE_DEFER. | ||
| 570 | * | 573 | * |
| 571 | * Returns zero if the driver registered and bound to a device, else returns | 574 | * Returns zero if the driver registered and bound to a device, else returns |
| 572 | * a negative error code and with the driver not registered. | 575 | * a negative error code and with the driver not registered. |
| @@ -576,6 +579,12 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv, | |||
| 576 | { | 579 | { |
| 577 | int retval, code; | 580 | int retval, code; |
| 578 | 581 | ||
| 582 | /* | ||
| 583 | * Prevent driver from requesting probe deferral to avoid further | ||
| 584 | * futile probe attempts. | ||
| 585 | */ | ||
| 586 | drv->prevent_deferred_probe = true; | ||
| 587 | |||
| 579 | /* make sure driver won't have bind/unbind attributes */ | 588 | /* make sure driver won't have bind/unbind attributes */ |
| 580 | drv->driver.suppress_bind_attrs = true; | 589 | drv->driver.suppress_bind_attrs = true; |
| 581 | 590 | ||
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 90ee350442a9..e15430a82e90 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c | |||
| @@ -30,28 +30,37 @@ static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, cha | |||
| 30 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | 30 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
| 31 | return sprintf(buf, "0x%03X\n", core->id.manuf); | 31 | return sprintf(buf, "0x%03X\n", core->id.manuf); |
| 32 | } | 32 | } |
| 33 | static DEVICE_ATTR_RO(manuf); | ||
| 34 | |||
| 33 | static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) | 35 | static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 34 | { | 36 | { |
| 35 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | 37 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
| 36 | return sprintf(buf, "0x%03X\n", core->id.id); | 38 | return sprintf(buf, "0x%03X\n", core->id.id); |
| 37 | } | 39 | } |
| 40 | static DEVICE_ATTR_RO(id); | ||
| 41 | |||
| 38 | static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf) | 42 | static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 39 | { | 43 | { |
| 40 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | 44 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
| 41 | return sprintf(buf, "0x%02X\n", core->id.rev); | 45 | return sprintf(buf, "0x%02X\n", core->id.rev); |
| 42 | } | 46 | } |
| 47 | static DEVICE_ATTR_RO(rev); | ||
| 48 | |||
| 43 | static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf) | 49 | static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 44 | { | 50 | { |
| 45 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | 51 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
| 46 | return sprintf(buf, "0x%X\n", core->id.class); | 52 | return sprintf(buf, "0x%X\n", core->id.class); |
| 47 | } | 53 | } |
| 48 | static struct device_attribute bcma_device_attrs[] = { | 54 | static DEVICE_ATTR_RO(class); |
| 49 | __ATTR_RO(manuf), | 55 | |
| 50 | __ATTR_RO(id), | 56 | static struct attribute *bcma_device_attrs[] = { |
| 51 | __ATTR_RO(rev), | 57 | &dev_attr_manuf.attr, |
| 52 | __ATTR_RO(class), | 58 | &dev_attr_id.attr, |
| 53 | __ATTR_NULL, | 59 | &dev_attr_rev.attr, |
| 60 | &dev_attr_class.attr, | ||
| 61 | NULL, | ||
| 54 | }; | 62 | }; |
| 63 | ATTRIBUTE_GROUPS(bcma_device); | ||
| 55 | 64 | ||
| 56 | static struct bus_type bcma_bus_type = { | 65 | static struct bus_type bcma_bus_type = { |
| 57 | .name = "bcma", | 66 | .name = "bcma", |
| @@ -59,7 +68,7 @@ static struct bus_type bcma_bus_type = { | |||
| 59 | .probe = bcma_device_probe, | 68 | .probe = bcma_device_probe, |
| 60 | .remove = bcma_device_remove, | 69 | .remove = bcma_device_remove, |
| 61 | .uevent = bcma_device_uevent, | 70 | .uevent = bcma_device_uevent, |
| 62 | .dev_attrs = bcma_device_attrs, | 71 | .dev_groups = bcma_device_groups, |
| 63 | }; | 72 | }; |
| 64 | 73 | ||
| 65 | static u16 bcma_cc_core_id(struct bcma_bus *bus) | 74 | static u16 bcma_cc_core_id(struct bcma_bus *bus) |
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 0dee0e0c247a..dadbac277267 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
| @@ -408,7 +408,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, | |||
| 408 | IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; | 408 | IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; |
| 409 | 409 | ||
| 410 | if (!value_sd) { | 410 | if (!value_sd) { |
| 411 | value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value"); | 411 | value_sd = sysfs_get_dirent(dev->kobj.sd, "value"); |
| 412 | if (!value_sd) { | 412 | if (!value_sd) { |
| 413 | ret = -ENODEV; | 413 | ret = -ENODEV; |
| 414 | goto err_out; | 414 | goto err_out; |
diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c index 66d44581e1b1..749f7b5c8179 100644 --- a/drivers/hsi/hsi.c +++ b/drivers/hsi/hsi.c | |||
| @@ -33,11 +33,13 @@ static ssize_t modalias_show(struct device *dev, | |||
| 33 | { | 33 | { |
| 34 | return sprintf(buf, "hsi:%s\n", dev_name(dev)); | 34 | return sprintf(buf, "hsi:%s\n", dev_name(dev)); |
| 35 | } | 35 | } |
| 36 | static DEVICE_ATTR_RO(modalias); | ||
| 36 | 37 | ||
| 37 | static struct device_attribute hsi_bus_dev_attrs[] = { | 38 | static struct attribute *hsi_bus_dev_attrs[] = { |
| 38 | __ATTR_RO(modalias), | 39 | &dev_attr_modalias.attr, |
| 39 | __ATTR_NULL, | 40 | NULL, |
| 40 | }; | 41 | }; |
| 42 | ATTRIBUTE_GROUPS(hsi_bus_dev); | ||
| 41 | 43 | ||
| 42 | static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) | 44 | static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) |
| 43 | { | 45 | { |
| @@ -53,7 +55,7 @@ static int hsi_bus_match(struct device *dev, struct device_driver *driver) | |||
| 53 | 55 | ||
| 54 | static struct bus_type hsi_bus_type = { | 56 | static struct bus_type hsi_bus_type = { |
| 55 | .name = "hsi", | 57 | .name = "hsi", |
| 56 | .dev_attrs = hsi_bus_dev_attrs, | 58 | .dev_groups = hsi_bus_dev_groups, |
| 57 | .match = hsi_bus_match, | 59 | .match = hsi_bus_match, |
| 58 | .uevent = hsi_bus_uevent, | 60 | .uevent = hsi_bus_uevent, |
| 59 | }; | 61 | }; |
diff --git a/drivers/ide/ide-sysfs.c b/drivers/ide/ide-sysfs.c index 883ffacaf45a..84a6a9e08d64 100644 --- a/drivers/ide/ide-sysfs.c +++ b/drivers/ide/ide-sysfs.c | |||
| @@ -25,6 +25,7 @@ static ssize_t media_show(struct device *dev, struct device_attribute *attr, | |||
| 25 | ide_drive_t *drive = to_ide_device(dev); | 25 | ide_drive_t *drive = to_ide_device(dev); |
| 26 | return sprintf(buf, "%s\n", ide_media_string(drive)); | 26 | return sprintf(buf, "%s\n", ide_media_string(drive)); |
| 27 | } | 27 | } |
| 28 | static DEVICE_ATTR_RO(media); | ||
| 28 | 29 | ||
| 29 | static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, | 30 | static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, |
| 30 | char *buf) | 31 | char *buf) |
| @@ -32,6 +33,7 @@ static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, | |||
| 32 | ide_drive_t *drive = to_ide_device(dev); | 33 | ide_drive_t *drive = to_ide_device(dev); |
| 33 | return sprintf(buf, "%s\n", drive->name); | 34 | return sprintf(buf, "%s\n", drive->name); |
| 34 | } | 35 | } |
| 36 | static DEVICE_ATTR_RO(drivename); | ||
| 35 | 37 | ||
| 36 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | 38 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, |
| 37 | char *buf) | 39 | char *buf) |
| @@ -39,6 +41,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | |||
| 39 | ide_drive_t *drive = to_ide_device(dev); | 41 | ide_drive_t *drive = to_ide_device(dev); |
| 40 | return sprintf(buf, "ide:m-%s\n", ide_media_string(drive)); | 42 | return sprintf(buf, "ide:m-%s\n", ide_media_string(drive)); |
| 41 | } | 43 | } |
| 44 | static DEVICE_ATTR_RO(modalias); | ||
| 42 | 45 | ||
| 43 | static ssize_t model_show(struct device *dev, struct device_attribute *attr, | 46 | static ssize_t model_show(struct device *dev, struct device_attribute *attr, |
| 44 | char *buf) | 47 | char *buf) |
| @@ -46,6 +49,7 @@ static ssize_t model_show(struct device *dev, struct device_attribute *attr, | |||
| 46 | ide_drive_t *drive = to_ide_device(dev); | 49 | ide_drive_t *drive = to_ide_device(dev); |
| 47 | return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]); | 50 | return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]); |
| 48 | } | 51 | } |
| 52 | static DEVICE_ATTR_RO(model); | ||
| 49 | 53 | ||
| 50 | static ssize_t firmware_show(struct device *dev, struct device_attribute *attr, | 54 | static ssize_t firmware_show(struct device *dev, struct device_attribute *attr, |
| 51 | char *buf) | 55 | char *buf) |
| @@ -53,6 +57,7 @@ static ssize_t firmware_show(struct device *dev, struct device_attribute *attr, | |||
| 53 | ide_drive_t *drive = to_ide_device(dev); | 57 | ide_drive_t *drive = to_ide_device(dev); |
| 54 | return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]); | 58 | return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]); |
| 55 | } | 59 | } |
| 60 | static DEVICE_ATTR_RO(firmware); | ||
| 56 | 61 | ||
| 57 | static ssize_t serial_show(struct device *dev, struct device_attribute *attr, | 62 | static ssize_t serial_show(struct device *dev, struct device_attribute *attr, |
| 58 | char *buf) | 63 | char *buf) |
| @@ -60,16 +65,28 @@ static ssize_t serial_show(struct device *dev, struct device_attribute *attr, | |||
| 60 | ide_drive_t *drive = to_ide_device(dev); | 65 | ide_drive_t *drive = to_ide_device(dev); |
| 61 | return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]); | 66 | return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]); |
| 62 | } | 67 | } |
| 68 | static DEVICE_ATTR(serial, 0400, serial_show, NULL); | ||
| 69 | |||
| 70 | static DEVICE_ATTR(unload_heads, 0644, ide_park_show, ide_park_store); | ||
| 71 | |||
| 72 | static struct attribute *ide_attrs[] = { | ||
| 73 | &dev_attr_media.attr, | ||
| 74 | &dev_attr_drivename.attr, | ||
| 75 | &dev_attr_modalias.attr, | ||
| 76 | &dev_attr_model.attr, | ||
| 77 | &dev_attr_firmware.attr, | ||
| 78 | &dev_attr_serial.attr, | ||
| 79 | &dev_attr_unload_heads.attr, | ||
| 80 | NULL, | ||
| 81 | }; | ||
| 82 | |||
| 83 | static const struct attribute_group ide_attr_group = { | ||
| 84 | .attrs = ide_attrs, | ||
| 85 | }; | ||
| 63 | 86 | ||
| 64 | struct device_attribute ide_dev_attrs[] = { | 87 | const struct attribute_group *ide_dev_groups[] = { |
| 65 | __ATTR_RO(media), | 88 | &ide_attr_group, |
| 66 | __ATTR_RO(drivename), | 89 | NULL, |
| 67 | __ATTR_RO(modalias), | ||
| 68 | __ATTR_RO(model), | ||
| 69 | __ATTR_RO(firmware), | ||
| 70 | __ATTR(serial, 0400, serial_show, NULL), | ||
| 71 | __ATTR(unload_heads, 0644, ide_park_show, ide_park_store), | ||
| 72 | __ATTR_NULL | ||
| 73 | }; | 90 | }; |
| 74 | 91 | ||
| 75 | static ssize_t store_delete_devices(struct device *portdev, | 92 | static ssize_t store_delete_devices(struct device *portdev, |
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index fa896210ed7b..2ce6268a2734 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c | |||
| @@ -158,7 +158,7 @@ struct bus_type ide_bus_type = { | |||
| 158 | .probe = generic_ide_probe, | 158 | .probe = generic_ide_probe, |
| 159 | .remove = generic_ide_remove, | 159 | .remove = generic_ide_remove, |
| 160 | .shutdown = generic_ide_shutdown, | 160 | .shutdown = generic_ide_shutdown, |
| 161 | .dev_attrs = ide_dev_attrs, | 161 | .dev_groups = ide_dev_groups, |
| 162 | .suspend = generic_ide_suspend, | 162 | .suspend = generic_ide_suspend, |
| 163 | .resume = generic_ide_resume, | 163 | .resume = generic_ide_resume, |
| 164 | }; | 164 | }; |
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 922a7fea2ce6..24c41ba7d4e0 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c | |||
| @@ -422,14 +422,15 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent) | |||
| 422 | * Gameport port operations | 422 | * Gameport port operations |
| 423 | */ | 423 | */ |
| 424 | 424 | ||
| 425 | static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf) | 425 | static ssize_t gameport_description_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 426 | { | 426 | { |
| 427 | struct gameport *gameport = to_gameport_port(dev); | 427 | struct gameport *gameport = to_gameport_port(dev); |
| 428 | 428 | ||
| 429 | return sprintf(buf, "%s\n", gameport->name); | 429 | return sprintf(buf, "%s\n", gameport->name); |
| 430 | } | 430 | } |
| 431 | static DEVICE_ATTR(description, S_IRUGO, gameport_description_show, NULL); | ||
| 431 | 432 | ||
| 432 | static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 433 | static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
| 433 | { | 434 | { |
| 434 | struct gameport *gameport = to_gameport_port(dev); | 435 | struct gameport *gameport = to_gameport_port(dev); |
| 435 | struct device_driver *drv; | 436 | struct device_driver *drv; |
| @@ -457,12 +458,14 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut | |||
| 457 | 458 | ||
| 458 | return error ? error : count; | 459 | return error ? error : count; |
| 459 | } | 460 | } |
| 461 | static DEVICE_ATTR_WO(drvctl); | ||
| 460 | 462 | ||
| 461 | static struct device_attribute gameport_device_attrs[] = { | 463 | static struct attribute *gameport_device_attrs[] = { |
| 462 | __ATTR(description, S_IRUGO, gameport_show_description, NULL), | 464 | &dev_attr_description.attr, |
| 463 | __ATTR(drvctl, S_IWUSR, NULL, gameport_rebind_driver), | 465 | &dev_attr_drvctl.attr, |
| 464 | __ATTR_NULL | 466 | NULL, |
| 465 | }; | 467 | }; |
| 468 | ATTRIBUTE_GROUPS(gameport_device); | ||
| 466 | 469 | ||
| 467 | static void gameport_release_port(struct device *dev) | 470 | static void gameport_release_port(struct device *dev) |
| 468 | { | 471 | { |
| @@ -750,7 +753,7 @@ static int gameport_bus_match(struct device *dev, struct device_driver *drv) | |||
| 750 | 753 | ||
| 751 | static struct bus_type gameport_bus = { | 754 | static struct bus_type gameport_bus = { |
| 752 | .name = "gameport", | 755 | .name = "gameport", |
| 753 | .dev_attrs = gameport_device_attrs, | 756 | .dev_groups = gameport_device_groups, |
| 754 | .drv_groups = gameport_driver_groups, | 757 | .drv_groups = gameport_driver_groups, |
| 755 | .match = gameport_bus_match, | 758 | .match = gameport_bus_match, |
| 756 | .probe = gameport_driver_probe, | 759 | .probe = gameport_driver_probe, |
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 2b56855c2c77..98707fb2cb5d 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c | |||
| @@ -365,7 +365,7 @@ static ssize_t serio_show_description(struct device *dev, struct device_attribut | |||
| 365 | return sprintf(buf, "%s\n", serio->name); | 365 | return sprintf(buf, "%s\n", serio->name); |
| 366 | } | 366 | } |
| 367 | 367 | ||
| 368 | static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) | 368 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 369 | { | 369 | { |
| 370 | struct serio *serio = to_serio_port(dev); | 370 | struct serio *serio = to_serio_port(dev); |
| 371 | 371 | ||
| @@ -373,54 +373,31 @@ static ssize_t serio_show_modalias(struct device *dev, struct device_attribute * | |||
| 373 | serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); | 373 | serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); |
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | static ssize_t serio_show_id_type(struct device *dev, struct device_attribute *attr, char *buf) | 376 | static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 377 | { | 377 | { |
| 378 | struct serio *serio = to_serio_port(dev); | 378 | struct serio *serio = to_serio_port(dev); |
| 379 | return sprintf(buf, "%02x\n", serio->id.type); | 379 | return sprintf(buf, "%02x\n", serio->id.type); |
| 380 | } | 380 | } |
| 381 | 381 | ||
| 382 | static ssize_t serio_show_id_proto(struct device *dev, struct device_attribute *attr, char *buf) | 382 | static ssize_t proto_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 383 | { | 383 | { |
| 384 | struct serio *serio = to_serio_port(dev); | 384 | struct serio *serio = to_serio_port(dev); |
| 385 | return sprintf(buf, "%02x\n", serio->id.proto); | 385 | return sprintf(buf, "%02x\n", serio->id.proto); |
| 386 | } | 386 | } |
| 387 | 387 | ||
| 388 | static ssize_t serio_show_id_id(struct device *dev, struct device_attribute *attr, char *buf) | 388 | static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 389 | { | 389 | { |
| 390 | struct serio *serio = to_serio_port(dev); | 390 | struct serio *serio = to_serio_port(dev); |
| 391 | return sprintf(buf, "%02x\n", serio->id.id); | 391 | return sprintf(buf, "%02x\n", serio->id.id); |
| 392 | } | 392 | } |
| 393 | 393 | ||
| 394 | static ssize_t serio_show_id_extra(struct device *dev, struct device_attribute *attr, char *buf) | 394 | static ssize_t extra_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 395 | { | 395 | { |
| 396 | struct serio *serio = to_serio_port(dev); | 396 | struct serio *serio = to_serio_port(dev); |
| 397 | return sprintf(buf, "%02x\n", serio->id.extra); | 397 | return sprintf(buf, "%02x\n", serio->id.extra); |
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | static DEVICE_ATTR(type, S_IRUGO, serio_show_id_type, NULL); | 400 | static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
| 401 | static DEVICE_ATTR(proto, S_IRUGO, serio_show_id_proto, NULL); | ||
| 402 | static DEVICE_ATTR(id, S_IRUGO, serio_show_id_id, NULL); | ||
| 403 | static DEVICE_ATTR(extra, S_IRUGO, serio_show_id_extra, NULL); | ||
| 404 | |||
| 405 | static struct attribute *serio_device_id_attrs[] = { | ||
| 406 | &dev_attr_type.attr, | ||
| 407 | &dev_attr_proto.attr, | ||
| 408 | &dev_attr_id.attr, | ||
| 409 | &dev_attr_extra.attr, | ||
| 410 | NULL | ||
| 411 | }; | ||
| 412 | |||
| 413 | static struct attribute_group serio_id_attr_group = { | ||
| 414 | .name = "id", | ||
| 415 | .attrs = serio_device_id_attrs, | ||
| 416 | }; | ||
| 417 | |||
| 418 | static const struct attribute_group *serio_device_attr_groups[] = { | ||
| 419 | &serio_id_attr_group, | ||
| 420 | NULL | ||
| 421 | }; | ||
| 422 | |||
| 423 | static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
| 424 | { | 401 | { |
| 425 | struct serio *serio = to_serio_port(dev); | 402 | struct serio *serio = to_serio_port(dev); |
| 426 | struct device_driver *drv; | 403 | struct device_driver *drv; |
| @@ -474,14 +451,36 @@ static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute * | |||
| 474 | return retval; | 451 | return retval; |
| 475 | } | 452 | } |
| 476 | 453 | ||
| 477 | static struct device_attribute serio_device_attrs[] = { | 454 | static DEVICE_ATTR_RO(type); |
| 478 | __ATTR(description, S_IRUGO, serio_show_description, NULL), | 455 | static DEVICE_ATTR_RO(proto); |
| 479 | __ATTR(modalias, S_IRUGO, serio_show_modalias, NULL), | 456 | static DEVICE_ATTR_RO(id); |
| 480 | __ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver), | 457 | static DEVICE_ATTR_RO(extra); |
| 481 | __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode), | 458 | static DEVICE_ATTR_RO(modalias); |
| 482 | __ATTR_NULL | 459 | static DEVICE_ATTR_WO(drvctl); |
| 460 | static DEVICE_ATTR(description, S_IRUGO, serio_show_description, NULL); | ||
| 461 | static DEVICE_ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode); | ||
| 462 | |||
| 463 | static struct attribute *serio_device_id_attrs[] = { | ||
| 464 | &dev_attr_type.attr, | ||
| 465 | &dev_attr_proto.attr, | ||
| 466 | &dev_attr_id.attr, | ||
| 467 | &dev_attr_extra.attr, | ||
| 468 | &dev_attr_modalias.attr, | ||
| 469 | &dev_attr_description.attr, | ||
| 470 | &dev_attr_drvctl.attr, | ||
| 471 | &dev_attr_bind_mode.attr, | ||
| 472 | NULL | ||
| 483 | }; | 473 | }; |
| 484 | 474 | ||
| 475 | static struct attribute_group serio_id_attr_group = { | ||
| 476 | .name = "id", | ||
| 477 | .attrs = serio_device_id_attrs, | ||
| 478 | }; | ||
| 479 | |||
| 480 | static const struct attribute_group *serio_device_attr_groups[] = { | ||
| 481 | &serio_id_attr_group, | ||
| 482 | NULL | ||
| 483 | }; | ||
| 485 | 484 | ||
| 486 | static void serio_release_port(struct device *dev) | 485 | static void serio_release_port(struct device *dev) |
| 487 | { | 486 | { |
| @@ -996,7 +995,6 @@ EXPORT_SYMBOL(serio_interrupt); | |||
| 996 | 995 | ||
| 997 | static struct bus_type serio_bus = { | 996 | static struct bus_type serio_bus = { |
| 998 | .name = "serio", | 997 | .name = "serio", |
| 999 | .dev_attrs = serio_device_attrs, | ||
| 1000 | .drv_groups = serio_driver_groups, | 998 | .drv_groups = serio_driver_groups, |
| 1001 | .match = serio_bus_match, | 999 | .match = serio_bus_match, |
| 1002 | .uevent = serio_uevent, | 1000 | .uevent = serio_uevent, |
diff --git a/drivers/ipack/ipack.c b/drivers/ipack/ipack.c index 6e066c53acce..d0016ba469ed 100644 --- a/drivers/ipack/ipack.c +++ b/drivers/ipack/ipack.c | |||
| @@ -180,20 +180,28 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | |||
| 180 | 180 | ||
| 181 | ipack_device_attr(id_format, "0x%hhu\n"); | 181 | ipack_device_attr(id_format, "0x%hhu\n"); |
| 182 | 182 | ||
| 183 | static struct device_attribute ipack_dev_attrs[] = { | 183 | static DEVICE_ATTR_RO(id); |
| 184 | __ATTR_RO(id), | 184 | static DEVICE_ATTR_RO(id_device); |
| 185 | __ATTR_RO(id_device), | 185 | static DEVICE_ATTR_RO(id_format); |
| 186 | __ATTR_RO(id_format), | 186 | static DEVICE_ATTR_RO(id_vendor); |
| 187 | __ATTR_RO(id_vendor), | 187 | static DEVICE_ATTR_RO(modalias); |
| 188 | __ATTR_RO(modalias), | 188 | |
| 189 | static struct attribute *ipack_attrs[] = { | ||
| 190 | &dev_attr_id.attr, | ||
| 191 | &dev_attr_id_device.attr, | ||
| 192 | &dev_attr_id_format.attr, | ||
| 193 | &dev_attr_id_vendor.attr, | ||
| 194 | &dev_attr_modalias.attr, | ||
| 195 | NULL, | ||
| 189 | }; | 196 | }; |
| 197 | ATTRIBUTE_GROUPS(ipack); | ||
| 190 | 198 | ||
| 191 | static struct bus_type ipack_bus_type = { | 199 | static struct bus_type ipack_bus_type = { |
| 192 | .name = "ipack", | 200 | .name = "ipack", |
| 193 | .probe = ipack_bus_probe, | 201 | .probe = ipack_bus_probe, |
| 194 | .match = ipack_bus_match, | 202 | .match = ipack_bus_match, |
| 195 | .remove = ipack_bus_remove, | 203 | .remove = ipack_bus_remove, |
| 196 | .dev_attrs = ipack_dev_attrs, | 204 | .dev_groups = ipack_groups, |
| 197 | .uevent = ipack_uevent, | 205 | .uevent = ipack_uevent, |
| 198 | }; | 206 | }; |
| 199 | 207 | ||
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index a7fd82133b12..12dc29ba7399 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c | |||
| @@ -1654,9 +1654,9 @@ int bitmap_create(struct mddev *mddev) | |||
| 1654 | bitmap->mddev = mddev; | 1654 | bitmap->mddev = mddev; |
| 1655 | 1655 | ||
| 1656 | if (mddev->kobj.sd) | 1656 | if (mddev->kobj.sd) |
| 1657 | bm = sysfs_get_dirent(mddev->kobj.sd, NULL, "bitmap"); | 1657 | bm = sysfs_get_dirent(mddev->kobj.sd, "bitmap"); |
| 1658 | if (bm) { | 1658 | if (bm) { |
| 1659 | bitmap->sysfs_can_clear = sysfs_get_dirent(bm, NULL, "can_clear"); | 1659 | bitmap->sysfs_can_clear = sysfs_get_dirent(bm, "can_clear"); |
| 1660 | sysfs_put(bm); | 1660 | sysfs_put(bm); |
| 1661 | } else | 1661 | } else |
| 1662 | bitmap->sysfs_can_clear = NULL; | 1662 | bitmap->sysfs_can_clear = NULL; |
diff --git a/drivers/md/md.c b/drivers/md/md.c index 561a65f82e26..2445fece9263 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
| @@ -3555,7 +3555,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len) | |||
| 3555 | printk(KERN_WARNING | 3555 | printk(KERN_WARNING |
| 3556 | "md: cannot register extra attributes for %s\n", | 3556 | "md: cannot register extra attributes for %s\n", |
| 3557 | mdname(mddev)); | 3557 | mdname(mddev)); |
| 3558 | mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, NULL, "sync_action"); | 3558 | mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action"); |
| 3559 | } | 3559 | } |
| 3560 | if (mddev->pers->sync_request != NULL && | 3560 | if (mddev->pers->sync_request != NULL && |
| 3561 | pers->sync_request == NULL) { | 3561 | pers->sync_request == NULL) { |
diff --git a/drivers/md/md.h b/drivers/md/md.h index 608050c43f17..b0051f2fbc0c 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h | |||
| @@ -501,7 +501,7 @@ extern struct attribute_group md_bitmap_group; | |||
| 501 | static inline struct sysfs_dirent *sysfs_get_dirent_safe(struct sysfs_dirent *sd, char *name) | 501 | static inline struct sysfs_dirent *sysfs_get_dirent_safe(struct sysfs_dirent *sd, char *name) |
| 502 | { | 502 | { |
| 503 | if (sd) | 503 | if (sd) |
| 504 | return sysfs_get_dirent(sd, NULL, name); | 504 | return sysfs_get_dirent(sd, name); |
| 505 | return sd; | 505 | return sd; |
| 506 | } | 506 | } |
| 507 | static inline void sysfs_notify_dirent_safe(struct sysfs_dirent *sd) | 507 | static inline void sysfs_notify_dirent_safe(struct sysfs_dirent *sd) |
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index ffcb10ac4341..bbf4aea1627d 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c | |||
| @@ -153,24 +153,24 @@ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ | |||
| 153 | struct memstick_dev *card = container_of(dev, struct memstick_dev, \ | 153 | struct memstick_dev *card = container_of(dev, struct memstick_dev, \ |
| 154 | dev); \ | 154 | dev); \ |
| 155 | return sprintf(buf, format, card->id.name); \ | 155 | return sprintf(buf, format, card->id.name); \ |
| 156 | } | 156 | } \ |
| 157 | static DEVICE_ATTR_RO(name); | ||
| 157 | 158 | ||
| 158 | MEMSTICK_ATTR(type, "%02X"); | 159 | MEMSTICK_ATTR(type, "%02X"); |
| 159 | MEMSTICK_ATTR(category, "%02X"); | 160 | MEMSTICK_ATTR(category, "%02X"); |
| 160 | MEMSTICK_ATTR(class, "%02X"); | 161 | MEMSTICK_ATTR(class, "%02X"); |
| 161 | 162 | ||
| 162 | #define MEMSTICK_ATTR_RO(name) __ATTR(name, S_IRUGO, name##_show, NULL) | 163 | static struct attribute *memstick_dev_attrs[] = { |
| 163 | 164 | &dev_attr_type.attr, | |
| 164 | static struct device_attribute memstick_dev_attrs[] = { | 165 | &dev_attr_category.attr, |
| 165 | MEMSTICK_ATTR_RO(type), | 166 | &dev_attr_class.attr, |
| 166 | MEMSTICK_ATTR_RO(category), | 167 | NULL, |
| 167 | MEMSTICK_ATTR_RO(class), | ||
| 168 | __ATTR_NULL | ||
| 169 | }; | 168 | }; |
| 169 | ATTRIBUTE_GROUPS(memstick_dev); | ||
| 170 | 170 | ||
| 171 | static struct bus_type memstick_bus_type = { | 171 | static struct bus_type memstick_bus_type = { |
| 172 | .name = "memstick", | 172 | .name = "memstick", |
| 173 | .dev_attrs = memstick_dev_attrs, | 173 | .dev_groups = memstick_dev_groups, |
| 174 | .match = memstick_bus_match, | 174 | .match = memstick_bus_match, |
| 175 | .uevent = memstick_uevent, | 175 | .uevent = memstick_uevent, |
| 176 | .probe = memstick_device_probe, | 176 | .probe = memstick_device_probe, |
diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h index cbe384fb848c..91614f11f89a 100644 --- a/drivers/message/i2o/core.h +++ b/drivers/message/i2o/core.h | |||
| @@ -33,7 +33,7 @@ extern int __init i2o_pci_init(void); | |||
| 33 | extern void __exit i2o_pci_exit(void); | 33 | extern void __exit i2o_pci_exit(void); |
| 34 | 34 | ||
| 35 | /* device */ | 35 | /* device */ |
| 36 | extern struct device_attribute i2o_device_attrs[]; | 36 | extern const struct attribute_group *i2o_device_groups[]; |
| 37 | 37 | ||
| 38 | extern void i2o_device_remove(struct i2o_device *); | 38 | extern void i2o_device_remove(struct i2o_device *); |
| 39 | extern int i2o_device_parse_lct(struct i2o_controller *); | 39 | extern int i2o_device_parse_lct(struct i2o_controller *); |
diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c index 4547db99f7da..98348f420b52 100644 --- a/drivers/message/i2o/device.c +++ b/drivers/message/i2o/device.c | |||
| @@ -138,45 +138,55 @@ static void i2o_device_release(struct device *dev) | |||
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | /** | 140 | /** |
| 141 | * i2o_device_show_class_id - Displays class id of I2O device | 141 | * class_id_show - Displays class id of I2O device |
| 142 | * @dev: device of which the class id should be displayed | 142 | * @dev: device of which the class id should be displayed |
| 143 | * @attr: pointer to device attribute | 143 | * @attr: pointer to device attribute |
| 144 | * @buf: buffer into which the class id should be printed | 144 | * @buf: buffer into which the class id should be printed |
| 145 | * | 145 | * |
| 146 | * Returns the number of bytes which are printed into the buffer. | 146 | * Returns the number of bytes which are printed into the buffer. |
| 147 | */ | 147 | */ |
| 148 | static ssize_t i2o_device_show_class_id(struct device *dev, | 148 | static ssize_t class_id_show(struct device *dev, struct device_attribute *attr, |
| 149 | struct device_attribute *attr, | 149 | char *buf) |
| 150 | char *buf) | ||
| 151 | { | 150 | { |
| 152 | struct i2o_device *i2o_dev = to_i2o_device(dev); | 151 | struct i2o_device *i2o_dev = to_i2o_device(dev); |
| 153 | 152 | ||
| 154 | sprintf(buf, "0x%03x\n", i2o_dev->lct_data.class_id); | 153 | sprintf(buf, "0x%03x\n", i2o_dev->lct_data.class_id); |
| 155 | return strlen(buf) + 1; | 154 | return strlen(buf) + 1; |
| 156 | } | 155 | } |
| 156 | static DEVICE_ATTR_RO(class_id); | ||
| 157 | 157 | ||
| 158 | /** | 158 | /** |
| 159 | * i2o_device_show_tid - Displays TID of I2O device | 159 | * tid_show - Displays TID of I2O device |
| 160 | * @dev: device of which the TID should be displayed | 160 | * @dev: device of which the TID should be displayed |
| 161 | * @attr: pointer to device attribute | 161 | * @attr: pointer to device attribute |
| 162 | * @buf: buffer into which the TID should be printed | 162 | * @buf: buffer into which the TID should be printed |
| 163 | * | 163 | * |
| 164 | * Returns the number of bytes which are printed into the buffer. | 164 | * Returns the number of bytes which are printed into the buffer. |
| 165 | */ | 165 | */ |
| 166 | static ssize_t i2o_device_show_tid(struct device *dev, | 166 | static ssize_t tid_show(struct device *dev, struct device_attribute *attr, |
| 167 | struct device_attribute *attr, char *buf) | 167 | char *buf) |
| 168 | { | 168 | { |
| 169 | struct i2o_device *i2o_dev = to_i2o_device(dev); | 169 | struct i2o_device *i2o_dev = to_i2o_device(dev); |
| 170 | 170 | ||
| 171 | sprintf(buf, "0x%03x\n", i2o_dev->lct_data.tid); | 171 | sprintf(buf, "0x%03x\n", i2o_dev->lct_data.tid); |
| 172 | return strlen(buf) + 1; | 172 | return strlen(buf) + 1; |
| 173 | } | 173 | } |
| 174 | static DEVICE_ATTR_RO(tid); | ||
| 174 | 175 | ||
| 175 | /* I2O device attributes */ | 176 | /* I2O device attributes */ |
| 176 | struct device_attribute i2o_device_attrs[] = { | 177 | static struct attribute *i2o_device_attrs[] = { |
| 177 | __ATTR(class_id, S_IRUGO, i2o_device_show_class_id, NULL), | 178 | &dev_attr_class_id.attr, |
| 178 | __ATTR(tid, S_IRUGO, i2o_device_show_tid, NULL), | 179 | &dev_attr_tid.attr, |
| 179 | __ATTR_NULL | 180 | NULL, |
| 181 | }; | ||
| 182 | |||
| 183 | static const struct attribute_group i2o_device_group = { | ||
| 184 | .attrs = i2o_device_attrs, | ||
| 185 | }; | ||
| 186 | |||
| 187 | const struct attribute_group *i2o_device_groups[] = { | ||
| 188 | &i2o_device_group, | ||
| 189 | NULL, | ||
| 180 | }; | 190 | }; |
| 181 | 191 | ||
| 182 | /** | 192 | /** |
diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c index 813eaa33fa14..b6b92d760510 100644 --- a/drivers/message/i2o/driver.c +++ b/drivers/message/i2o/driver.c | |||
| @@ -62,7 +62,7 @@ static int i2o_bus_match(struct device *dev, struct device_driver *drv) | |||
| 62 | struct bus_type i2o_bus_type = { | 62 | struct bus_type i2o_bus_type = { |
| 63 | .name = "i2o", | 63 | .name = "i2o", |
| 64 | .match = i2o_bus_match, | 64 | .match = i2o_bus_match, |
| 65 | .dev_attrs = i2o_device_attrs | 65 | .dev_groups = i2o_device_groups, |
| 66 | }; | 66 | }; |
| 67 | 67 | ||
| 68 | /** | 68 | /** |
diff --git a/drivers/misc/mic/host/mic_main.c b/drivers/misc/mic/host/mic_main.c index b3520859abd3..ad838c7651c4 100644 --- a/drivers/misc/mic/host/mic_main.c +++ b/drivers/misc/mic/host/mic_main.c | |||
| @@ -374,8 +374,7 @@ static int mic_probe(struct pci_dev *pdev, | |||
| 374 | "device_create_with_groups failed rc %d\n", rc); | 374 | "device_create_with_groups failed rc %d\n", rc); |
| 375 | goto smpt_uninit; | 375 | goto smpt_uninit; |
| 376 | } | 376 | } |
| 377 | mdev->state_sysfs = sysfs_get_dirent(mdev->sdev->kobj.sd, | 377 | mdev->state_sysfs = sysfs_get_dirent(mdev->sdev->kobj.sd, "state"); |
| 378 | NULL, "state"); | ||
| 379 | if (!mdev->state_sysfs) { | 378 | if (!mdev->state_sysfs) { |
| 380 | rc = -ENODEV; | 379 | rc = -ENODEV; |
| 381 | dev_err(&pdev->dev, "sysfs_get_dirent failed rc %d\n", rc); | 380 | dev_err(&pdev->dev, "sysfs_get_dirent failed rc %d\n", rc); |
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index 0ab7c922212c..a511b2a713b3 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c | |||
| @@ -145,15 +145,17 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr, | |||
| 145 | struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); | 145 | struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); |
| 146 | return sprintf(buf, "%x", sock->type); | 146 | return sprintf(buf, "%x", sock->type); |
| 147 | } | 147 | } |
| 148 | static DEVICE_ATTR_RO(type); | ||
| 148 | 149 | ||
| 149 | static struct device_attribute tifm_dev_attrs[] = { | 150 | static struct attribute *tifm_dev_attrs[] = { |
| 150 | __ATTR(type, S_IRUGO, type_show, NULL), | 151 | &dev_attr_type.attr, |
| 151 | __ATTR_NULL | 152 | NULL, |
| 152 | }; | 153 | }; |
| 154 | ATTRIBUTE_GROUPS(tifm_dev); | ||
| 153 | 155 | ||
| 154 | static struct bus_type tifm_bus_type = { | 156 | static struct bus_type tifm_bus_type = { |
| 155 | .name = "tifm", | 157 | .name = "tifm", |
| 156 | .dev_attrs = tifm_dev_attrs, | 158 | .dev_groups = tifm_dev_groups, |
| 157 | .match = tifm_bus_match, | 159 | .match = tifm_bus_match, |
| 158 | .uevent = tifm_uevent, | 160 | .uevent = tifm_uevent, |
| 159 | .probe = tifm_device_probe, | 161 | .probe = tifm_device_probe, |
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 704bf66f5873..3e227bd91e81 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) | 28 | #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) |
| 29 | 29 | ||
| 30 | static ssize_t mmc_type_show(struct device *dev, | 30 | static ssize_t type_show(struct device *dev, |
| 31 | struct device_attribute *attr, char *buf) | 31 | struct device_attribute *attr, char *buf) |
| 32 | { | 32 | { |
| 33 | struct mmc_card *card = mmc_dev_to_card(dev); | 33 | struct mmc_card *card = mmc_dev_to_card(dev); |
| @@ -45,11 +45,13 @@ static ssize_t mmc_type_show(struct device *dev, | |||
| 45 | return -EFAULT; | 45 | return -EFAULT; |
| 46 | } | 46 | } |
| 47 | } | 47 | } |
| 48 | static DEVICE_ATTR_RO(type); | ||
| 48 | 49 | ||
| 49 | static struct device_attribute mmc_dev_attrs[] = { | 50 | static struct attribute *mmc_dev_attrs[] = { |
| 50 | __ATTR(type, S_IRUGO, mmc_type_show, NULL), | 51 | &dev_attr_type.attr, |
| 51 | __ATTR_NULL, | 52 | NULL, |
| 52 | }; | 53 | }; |
| 54 | ATTRIBUTE_GROUPS(mmc_dev); | ||
| 53 | 55 | ||
| 54 | /* | 56 | /* |
| 55 | * This currently matches any MMC driver to any MMC card - drivers | 57 | * This currently matches any MMC driver to any MMC card - drivers |
| @@ -218,7 +220,7 @@ static const struct dev_pm_ops mmc_bus_pm_ops = { | |||
| 218 | 220 | ||
| 219 | static struct bus_type mmc_bus_type = { | 221 | static struct bus_type mmc_bus_type = { |
| 220 | .name = "mmc", | 222 | .name = "mmc", |
| 221 | .dev_attrs = mmc_dev_attrs, | 223 | .dev_groups = mmc_dev_groups, |
| 222 | .match = mmc_bus_match, | 224 | .match = mmc_bus_match, |
| 223 | .uevent = mmc_bus_uevent, | 225 | .uevent = mmc_bus_uevent, |
| 224 | .probe = mmc_bus_probe, | 226 | .probe = mmc_bus_probe, |
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 6d67492a9247..ef8956568c3a 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c | |||
| @@ -34,7 +34,8 @@ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ | |||
| 34 | \ | 34 | \ |
| 35 | func = dev_to_sdio_func (dev); \ | 35 | func = dev_to_sdio_func (dev); \ |
| 36 | return sprintf (buf, format_string, func->field); \ | 36 | return sprintf (buf, format_string, func->field); \ |
| 37 | } | 37 | } \ |
| 38 | static DEVICE_ATTR_RO(field) | ||
| 38 | 39 | ||
| 39 | sdio_config_attr(class, "0x%02x\n"); | 40 | sdio_config_attr(class, "0x%02x\n"); |
| 40 | sdio_config_attr(vendor, "0x%04x\n"); | 41 | sdio_config_attr(vendor, "0x%04x\n"); |
| @@ -47,14 +48,16 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | |||
| 47 | return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n", | 48 | return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n", |
| 48 | func->class, func->vendor, func->device); | 49 | func->class, func->vendor, func->device); |
| 49 | } | 50 | } |
| 50 | 51 | static DEVICE_ATTR_RO(modalias); | |
| 51 | static struct device_attribute sdio_dev_attrs[] = { | 52 | |
| 52 | __ATTR_RO(class), | 53 | static struct attribute *sdio_dev_attrs[] = { |
| 53 | __ATTR_RO(vendor), | 54 | &dev_attr_class.attr, |
| 54 | __ATTR_RO(device), | 55 | &dev_attr_vendor.attr, |
| 55 | __ATTR_RO(modalias), | 56 | &dev_attr_device.attr, |
| 56 | __ATTR_NULL, | 57 | &dev_attr_modalias.attr, |
| 58 | NULL, | ||
| 57 | }; | 59 | }; |
| 60 | ATTRIBUTE_GROUPS(sdio_dev); | ||
| 58 | 61 | ||
| 59 | static const struct sdio_device_id *sdio_match_one(struct sdio_func *func, | 62 | static const struct sdio_device_id *sdio_match_one(struct sdio_func *func, |
| 60 | const struct sdio_device_id *id) | 63 | const struct sdio_device_id *id) |
| @@ -225,7 +228,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = { | |||
| 225 | 228 | ||
| 226 | static struct bus_type sdio_bus_type = { | 229 | static struct bus_type sdio_bus_type = { |
| 227 | .name = "sdio", | 230 | .name = "sdio", |
| 228 | .dev_attrs = sdio_dev_attrs, | 231 | .dev_groups = sdio_dev_groups, |
| 229 | .match = sdio_bus_match, | 232 | .match = sdio_bus_match, |
| 230 | .uevent = sdio_bus_uevent, | 233 | .uevent = sdio_bus_uevent, |
| 231 | .probe = sdio_bus_probe, | 234 | .probe = sdio_bus_probe, |
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 06c5b0b28ebc..deecee08c288 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c | |||
| @@ -655,7 +655,7 @@ static const struct mmc_host_ops mvsd_ops = { | |||
| 655 | .enable_sdio_irq = mvsd_enable_sdio_irq, | 655 | .enable_sdio_irq = mvsd_enable_sdio_irq, |
| 656 | }; | 656 | }; |
| 657 | 657 | ||
| 658 | static void __init | 658 | static void |
| 659 | mv_conf_mbus_windows(struct mvsd_host *host, | 659 | mv_conf_mbus_windows(struct mvsd_host *host, |
| 660 | const struct mbus_dram_target_info *dram) | 660 | const struct mbus_dram_target_info *dram) |
| 661 | { | 661 | { |
| @@ -677,7 +677,7 @@ mv_conf_mbus_windows(struct mvsd_host *host, | |||
| 677 | } | 677 | } |
| 678 | } | 678 | } |
| 679 | 679 | ||
| 680 | static int __init mvsd_probe(struct platform_device *pdev) | 680 | static int mvsd_probe(struct platform_device *pdev) |
| 681 | { | 681 | { |
| 682 | struct device_node *np = pdev->dev.of_node; | 682 | struct device_node *np = pdev->dev.of_node; |
| 683 | struct mmc_host *mmc = NULL; | 683 | struct mmc_host *mmc = NULL; |
| @@ -819,7 +819,7 @@ out: | |||
| 819 | return ret; | 819 | return ret; |
| 820 | } | 820 | } |
| 821 | 821 | ||
| 822 | static int __exit mvsd_remove(struct platform_device *pdev) | 822 | static int mvsd_remove(struct platform_device *pdev) |
| 823 | { | 823 | { |
| 824 | struct mmc_host *mmc = platform_get_drvdata(pdev); | 824 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
| 825 | 825 | ||
| @@ -872,7 +872,8 @@ static const struct of_device_id mvsdio_dt_ids[] = { | |||
| 872 | MODULE_DEVICE_TABLE(of, mvsdio_dt_ids); | 872 | MODULE_DEVICE_TABLE(of, mvsdio_dt_ids); |
| 873 | 873 | ||
| 874 | static struct platform_driver mvsd_driver = { | 874 | static struct platform_driver mvsd_driver = { |
| 875 | .remove = __exit_p(mvsd_remove), | 875 | .probe = mvsd_probe, |
| 876 | .remove = mvsd_remove, | ||
| 876 | .suspend = mvsd_suspend, | 877 | .suspend = mvsd_suspend, |
| 877 | .resume = mvsd_resume, | 878 | .resume = mvsd_resume, |
| 878 | .driver = { | 879 | .driver = { |
| @@ -881,7 +882,7 @@ static struct platform_driver mvsd_driver = { | |||
| 881 | }, | 882 | }, |
| 882 | }; | 883 | }; |
| 883 | 884 | ||
| 884 | module_platform_driver_probe(mvsd_driver, mvsd_probe); | 885 | module_platform_driver(mvsd_driver); |
| 885 | 886 | ||
| 886 | /* maximum card clock frequency (default 50MHz) */ | 887 | /* maximum card clock frequency (default 50MHz) */ |
| 887 | module_param(maxfreq, int, 0); | 888 | module_param(maxfreq, int, 0); |
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 060feeaf6b3e..bd1ce7d13702 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
| @@ -1139,7 +1139,7 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, | |||
| 1139 | return 0; | 1139 | return 0; |
| 1140 | } | 1140 | } |
| 1141 | 1141 | ||
| 1142 | static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev, | 1142 | static int atmel_pmecc_nand_init_params(struct platform_device *pdev, |
| 1143 | struct atmel_nand_host *host) | 1143 | struct atmel_nand_host *host) |
| 1144 | { | 1144 | { |
| 1145 | struct mtd_info *mtd = &host->mtd; | 1145 | struct mtd_info *mtd = &host->mtd; |
| @@ -1548,7 +1548,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host, | |||
| 1548 | } | 1548 | } |
| 1549 | #endif | 1549 | #endif |
| 1550 | 1550 | ||
| 1551 | static int __init atmel_hw_nand_init_params(struct platform_device *pdev, | 1551 | static int atmel_hw_nand_init_params(struct platform_device *pdev, |
| 1552 | struct atmel_nand_host *host) | 1552 | struct atmel_nand_host *host) |
| 1553 | { | 1553 | { |
| 1554 | struct mtd_info *mtd = &host->mtd; | 1554 | struct mtd_info *mtd = &host->mtd; |
| @@ -1987,7 +1987,7 @@ static struct platform_driver atmel_nand_nfc_driver; | |||
| 1987 | /* | 1987 | /* |
| 1988 | * Probe for the NAND device. | 1988 | * Probe for the NAND device. |
| 1989 | */ | 1989 | */ |
| 1990 | static int __init atmel_nand_probe(struct platform_device *pdev) | 1990 | static int atmel_nand_probe(struct platform_device *pdev) |
| 1991 | { | 1991 | { |
| 1992 | struct atmel_nand_host *host; | 1992 | struct atmel_nand_host *host; |
| 1993 | struct mtd_info *mtd; | 1993 | struct mtd_info *mtd; |
| @@ -2184,7 +2184,7 @@ err_nand_ioremap: | |||
| 2184 | /* | 2184 | /* |
| 2185 | * Remove a NAND device. | 2185 | * Remove a NAND device. |
| 2186 | */ | 2186 | */ |
| 2187 | static int __exit atmel_nand_remove(struct platform_device *pdev) | 2187 | static int atmel_nand_remove(struct platform_device *pdev) |
| 2188 | { | 2188 | { |
| 2189 | struct atmel_nand_host *host = platform_get_drvdata(pdev); | 2189 | struct atmel_nand_host *host = platform_get_drvdata(pdev); |
| 2190 | struct mtd_info *mtd = &host->mtd; | 2190 | struct mtd_info *mtd = &host->mtd; |
| @@ -2270,7 +2270,8 @@ static struct platform_driver atmel_nand_nfc_driver = { | |||
| 2270 | }; | 2270 | }; |
| 2271 | 2271 | ||
| 2272 | static struct platform_driver atmel_nand_driver = { | 2272 | static struct platform_driver atmel_nand_driver = { |
| 2273 | .remove = __exit_p(atmel_nand_remove), | 2273 | .probe = atmel_nand_probe, |
| 2274 | .remove = atmel_nand_remove, | ||
| 2274 | .driver = { | 2275 | .driver = { |
| 2275 | .name = "atmel_nand", | 2276 | .name = "atmel_nand", |
| 2276 | .owner = THIS_MODULE, | 2277 | .owner = THIS_MODULE, |
| @@ -2278,7 +2279,7 @@ static struct platform_driver atmel_nand_driver = { | |||
| 2278 | }, | 2279 | }, |
| 2279 | }; | 2280 | }; |
| 2280 | 2281 | ||
| 2281 | module_platform_driver_probe(atmel_nand_driver, atmel_nand_probe); | 2282 | module_platform_driver(atmel_nand_driver); |
| 2282 | 2283 | ||
| 2283 | MODULE_LICENSE("GPL"); | 2284 | MODULE_LICENSE("GPL"); |
| 2284 | MODULE_AUTHOR("Rick Bronson"); | 2285 | MODULE_AUTHOR("Rick Bronson"); |
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index c29b836749b6..ec9b6460a38d 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
| @@ -149,14 +149,6 @@ err_no_cmd: | |||
| 149 | return -EPERM; | 149 | return -EPERM; |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | static const void *bonding_namespace(struct class *cls, | ||
| 153 | const struct class_attribute *attr) | ||
| 154 | { | ||
| 155 | const struct bond_net *bn = | ||
| 156 | container_of(attr, struct bond_net, class_attr_bonding_masters); | ||
| 157 | return bn->net; | ||
| 158 | } | ||
| 159 | |||
| 160 | /* class attribute for bond_masters file. This ends up in /sys/class/net */ | 152 | /* class attribute for bond_masters file. This ends up in /sys/class/net */ |
| 161 | static const struct class_attribute class_attr_bonding_masters = { | 153 | static const struct class_attribute class_attr_bonding_masters = { |
| 162 | .attr = { | 154 | .attr = { |
| @@ -165,7 +157,6 @@ static const struct class_attribute class_attr_bonding_masters = { | |||
| 165 | }, | 157 | }, |
| 166 | .show = bonding_show_bonds, | 158 | .show = bonding_show_bonds, |
| 167 | .store = bonding_store_bonds, | 159 | .store = bonding_store_bonds, |
| 168 | .namespace = bonding_namespace, | ||
| 169 | }; | 160 | }; |
| 170 | 161 | ||
| 171 | int bond_create_slave_symlinks(struct net_device *master, | 162 | int bond_create_slave_symlinks(struct net_device *master, |
| @@ -1787,7 +1778,8 @@ int bond_create_sysfs(struct bond_net *bn) | |||
| 1787 | bn->class_attr_bonding_masters = class_attr_bonding_masters; | 1778 | bn->class_attr_bonding_masters = class_attr_bonding_masters; |
| 1788 | sysfs_attr_init(&bn->class_attr_bonding_masters.attr); | 1779 | sysfs_attr_init(&bn->class_attr_bonding_masters.attr); |
| 1789 | 1780 | ||
| 1790 | ret = netdev_class_create_file(&bn->class_attr_bonding_masters); | 1781 | ret = netdev_class_create_file_ns(&bn->class_attr_bonding_masters, |
| 1782 | bn->net); | ||
| 1791 | /* | 1783 | /* |
| 1792 | * Permit multiple loads of the module by ignoring failures to | 1784 | * Permit multiple loads of the module by ignoring failures to |
| 1793 | * create the bonding_masters sysfs file. Bonding devices | 1785 | * create the bonding_masters sysfs file. Bonding devices |
| @@ -1817,7 +1809,7 @@ int bond_create_sysfs(struct bond_net *bn) | |||
| 1817 | */ | 1809 | */ |
| 1818 | void bond_destroy_sysfs(struct bond_net *bn) | 1810 | void bond_destroy_sysfs(struct bond_net *bn) |
| 1819 | { | 1811 | { |
| 1820 | netdev_class_remove_file(&bn->class_attr_bonding_masters); | 1812 | netdev_class_remove_file_ns(&bn->class_attr_bonding_masters, bn->net); |
| 1821 | } | 1813 | } |
| 1822 | 1814 | ||
| 1823 | /* | 1815 | /* |
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index dc920974204e..56178761ce93 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c | |||
| @@ -438,17 +438,19 @@ phy_id_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
| 438 | 438 | ||
| 439 | return sprintf(buf, "0x%.8lx\n", (unsigned long)phydev->phy_id); | 439 | return sprintf(buf, "0x%.8lx\n", (unsigned long)phydev->phy_id); |
| 440 | } | 440 | } |
| 441 | static DEVICE_ATTR_RO(phy_id); | ||
| 441 | 442 | ||
| 442 | static struct device_attribute mdio_dev_attrs[] = { | 443 | static struct attribute *mdio_dev_attrs[] = { |
| 443 | __ATTR_RO(phy_id), | 444 | &dev_attr_phy_id.attr, |
| 444 | __ATTR_NULL | 445 | NULL, |
| 445 | }; | 446 | }; |
| 447 | ATTRIBUTE_GROUPS(mdio_dev); | ||
| 446 | 448 | ||
| 447 | struct bus_type mdio_bus_type = { | 449 | struct bus_type mdio_bus_type = { |
| 448 | .name = "mdio_bus", | 450 | .name = "mdio_bus", |
| 449 | .match = mdio_bus_match, | 451 | .match = mdio_bus_match, |
| 450 | .pm = MDIO_BUS_PM_OPS, | 452 | .pm = MDIO_BUS_PM_OPS, |
| 451 | .dev_attrs = mdio_dev_attrs, | 453 | .dev_groups = mdio_dev_groups, |
| 452 | }; | 454 | }; |
| 453 | EXPORT_SYMBOL(mdio_bus_type); | 455 | EXPORT_SYMBOL(mdio_bus_type); |
| 454 | 456 | ||
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 98f7b9b89507..38f3c0140dfb 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
| @@ -135,6 +135,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) | |||
| 135 | return retval; | 135 | return retval; |
| 136 | return count; | 136 | return count; |
| 137 | } | 137 | } |
| 138 | static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); | ||
| 138 | 139 | ||
| 139 | /** | 140 | /** |
| 140 | * store_remove_id - remove a PCI device ID from this driver | 141 | * store_remove_id - remove a PCI device ID from this driver |
| @@ -180,12 +181,14 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count) | |||
| 180 | return retval; | 181 | return retval; |
| 181 | return count; | 182 | return count; |
| 182 | } | 183 | } |
| 184 | static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id); | ||
| 183 | 185 | ||
| 184 | static struct driver_attribute pci_drv_attrs[] = { | 186 | static struct attribute *pci_drv_attrs[] = { |
| 185 | __ATTR(new_id, S_IWUSR, NULL, store_new_id), | 187 | &driver_attr_new_id.attr, |
| 186 | __ATTR(remove_id, S_IWUSR, NULL, store_remove_id), | 188 | &driver_attr_remove_id.attr, |
| 187 | __ATTR_NULL, | 189 | NULL, |
| 188 | }; | 190 | }; |
| 191 | ATTRIBUTE_GROUPS(pci_drv); | ||
| 189 | 192 | ||
| 190 | /** | 193 | /** |
| 191 | * pci_match_id - See if a pci device matches a given pci_id table | 194 | * pci_match_id - See if a pci device matches a given pci_id table |
| @@ -1317,8 +1320,8 @@ struct bus_type pci_bus_type = { | |||
| 1317 | .remove = pci_device_remove, | 1320 | .remove = pci_device_remove, |
| 1318 | .shutdown = pci_device_shutdown, | 1321 | .shutdown = pci_device_shutdown, |
| 1319 | .dev_attrs = pci_dev_attrs, | 1322 | .dev_attrs = pci_dev_attrs, |
| 1320 | .bus_attrs = pci_bus_attrs, | 1323 | .bus_groups = pci_bus_groups, |
| 1321 | .drv_attrs = pci_drv_attrs, | 1324 | .drv_groups = pci_drv_groups, |
| 1322 | .pm = PCI_PM_OPS_PTR, | 1325 | .pm = PCI_PM_OPS_PTR, |
| 1323 | }; | 1326 | }; |
| 1324 | 1327 | ||
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 7128cfdd64aa..d8eb880bd1fc 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
| @@ -302,10 +302,20 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, | |||
| 302 | } | 302 | } |
| 303 | return count; | 303 | return count; |
| 304 | } | 304 | } |
| 305 | static BUS_ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store); | ||
| 305 | 306 | ||
| 306 | struct bus_attribute pci_bus_attrs[] = { | 307 | struct attribute *pci_bus_attrs[] = { |
| 307 | __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store), | 308 | &bus_attr_rescan.attr, |
| 308 | __ATTR_NULL | 309 | NULL, |
| 310 | }; | ||
| 311 | |||
| 312 | static const struct attribute_group pci_bus_group = { | ||
| 313 | .attrs = pci_bus_attrs, | ||
| 314 | }; | ||
| 315 | |||
| 316 | const struct attribute_group *pci_bus_groups[] = { | ||
| 317 | &pci_bus_group, | ||
| 318 | NULL, | ||
| 309 | }; | 319 | }; |
| 310 | 320 | ||
| 311 | static ssize_t | 321 | static ssize_t |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 8a00c063d7bc..607be58dd728 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
| @@ -156,7 +156,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev) | |||
| 156 | extern struct device_attribute pci_dev_attrs[]; | 156 | extern struct device_attribute pci_dev_attrs[]; |
| 157 | extern const struct attribute_group *pcibus_groups[]; | 157 | extern const struct attribute_group *pcibus_groups[]; |
| 158 | extern struct device_type pci_dev_type; | 158 | extern struct device_type pci_dev_type; |
| 159 | extern struct bus_attribute pci_bus_attrs[]; | 159 | extern const struct attribute_group *pci_bus_groups[]; |
| 160 | 160 | ||
| 161 | 161 | ||
| 162 | /** | 162 | /** |
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index b8f5acf02261..de24232c5191 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c | |||
| @@ -245,7 +245,7 @@ static int at91_cf_dt_init(struct platform_device *pdev) | |||
| 245 | } | 245 | } |
| 246 | #endif | 246 | #endif |
| 247 | 247 | ||
| 248 | static int __init at91_cf_probe(struct platform_device *pdev) | 248 | static int at91_cf_probe(struct platform_device *pdev) |
| 249 | { | 249 | { |
| 250 | struct at91_cf_socket *cf; | 250 | struct at91_cf_socket *cf; |
| 251 | struct at91_cf_data *board = pdev->dev.platform_data; | 251 | struct at91_cf_data *board = pdev->dev.platform_data; |
| @@ -354,7 +354,7 @@ fail0a: | |||
| 354 | return status; | 354 | return status; |
| 355 | } | 355 | } |
| 356 | 356 | ||
| 357 | static int __exit at91_cf_remove(struct platform_device *pdev) | 357 | static int at91_cf_remove(struct platform_device *pdev) |
| 358 | { | 358 | { |
| 359 | struct at91_cf_socket *cf = platform_get_drvdata(pdev); | 359 | struct at91_cf_socket *cf = platform_get_drvdata(pdev); |
| 360 | 360 | ||
| @@ -404,14 +404,13 @@ static struct platform_driver at91_cf_driver = { | |||
| 404 | .owner = THIS_MODULE, | 404 | .owner = THIS_MODULE, |
| 405 | .of_match_table = of_match_ptr(at91_cf_dt_ids), | 405 | .of_match_table = of_match_ptr(at91_cf_dt_ids), |
| 406 | }, | 406 | }, |
| 407 | .remove = __exit_p(at91_cf_remove), | 407 | .probe = at91_cf_probe, |
| 408 | .remove = at91_cf_remove, | ||
| 408 | .suspend = at91_cf_suspend, | 409 | .suspend = at91_cf_suspend, |
| 409 | .resume = at91_cf_resume, | 410 | .resume = at91_cf_resume, |
| 410 | }; | 411 | }; |
| 411 | 412 | ||
| 412 | /*--------------------------------------------------------------------------*/ | 413 | module_platform_driver(at91_cf_driver); |
| 413 | |||
| 414 | module_platform_driver_probe(at91_cf_driver, at91_cf_probe); | ||
| 415 | 414 | ||
| 416 | MODULE_DESCRIPTION("AT91 Compact Flash Driver"); | 415 | MODULE_DESCRIPTION("AT91 Compact Flash Driver"); |
| 417 | MODULE_AUTHOR("David Brownell"); | 416 | MODULE_AUTHOR("David Brownell"); |
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 2deacbb2ffdc..757119b87146 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
| @@ -992,16 +992,17 @@ static ssize_t field##_show (struct device *dev, struct device_attribute *attr, | |||
| 992 | { \ | 992 | { \ |
| 993 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ | 993 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ |
| 994 | return p_dev->test ? sprintf(buf, format, p_dev->field) : -ENODEV; \ | 994 | return p_dev->test ? sprintf(buf, format, p_dev->field) : -ENODEV; \ |
| 995 | } | 995 | } \ |
| 996 | static DEVICE_ATTR_RO(field); | ||
| 996 | 997 | ||
| 997 | #define pcmcia_device_stringattr(name, field) \ | 998 | #define pcmcia_device_stringattr(name, field) \ |
| 998 | static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ | 999 | static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ |
| 999 | { \ | 1000 | { \ |
| 1000 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ | 1001 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ |
| 1001 | return p_dev->field ? sprintf(buf, "%s\n", p_dev->field) : -ENODEV; \ | 1002 | return p_dev->field ? sprintf(buf, "%s\n", p_dev->field) : -ENODEV; \ |
| 1002 | } | 1003 | } \ |
| 1004 | static DEVICE_ATTR_RO(name); | ||
| 1003 | 1005 | ||
| 1004 | pcmcia_device_attr(func, socket, "0x%02x\n"); | ||
| 1005 | pcmcia_device_attr(func_id, has_func_id, "0x%02x\n"); | 1006 | pcmcia_device_attr(func_id, has_func_id, "0x%02x\n"); |
| 1006 | pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n"); | 1007 | pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n"); |
| 1007 | pcmcia_device_attr(card_id, has_card_id, "0x%04x\n"); | 1008 | pcmcia_device_attr(card_id, has_card_id, "0x%04x\n"); |
| @@ -1010,8 +1011,16 @@ pcmcia_device_stringattr(prod_id2, prod_id[1]); | |||
| 1010 | pcmcia_device_stringattr(prod_id3, prod_id[2]); | 1011 | pcmcia_device_stringattr(prod_id3, prod_id[2]); |
| 1011 | pcmcia_device_stringattr(prod_id4, prod_id[3]); | 1012 | pcmcia_device_stringattr(prod_id4, prod_id[3]); |
| 1012 | 1013 | ||
| 1013 | static ssize_t pcmcia_show_resources(struct device *dev, | 1014 | static ssize_t function_show(struct device *dev, struct device_attribute *attr, |
| 1014 | struct device_attribute *attr, char *buf) | 1015 | char *buf) |
| 1016 | { | ||
| 1017 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
| 1018 | return p_dev->socket ? sprintf(buf, "0x%02x\n", p_dev->func) : -ENODEV; | ||
| 1019 | } | ||
| 1020 | static DEVICE_ATTR_RO(function); | ||
| 1021 | |||
| 1022 | static ssize_t resources_show(struct device *dev, | ||
| 1023 | struct device_attribute *attr, char *buf) | ||
| 1015 | { | 1024 | { |
| 1016 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1025 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
| 1017 | char *str = buf; | 1026 | char *str = buf; |
| @@ -1022,8 +1031,9 @@ static ssize_t pcmcia_show_resources(struct device *dev, | |||
| 1022 | 1031 | ||
| 1023 | return str - buf; | 1032 | return str - buf; |
| 1024 | } | 1033 | } |
| 1034 | static DEVICE_ATTR_RO(resources); | ||
| 1025 | 1035 | ||
| 1026 | static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute *attr, char *buf) | 1036 | static ssize_t pm_state_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 1027 | { | 1037 | { |
| 1028 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1038 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
| 1029 | 1039 | ||
| @@ -1033,8 +1043,8 @@ static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute | |||
| 1033 | return sprintf(buf, "on\n"); | 1043 | return sprintf(buf, "on\n"); |
| 1034 | } | 1044 | } |
| 1035 | 1045 | ||
| 1036 | static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute *attr, | 1046 | static ssize_t pm_state_store(struct device *dev, struct device_attribute *attr, |
| 1037 | const char *buf, size_t count) | 1047 | const char *buf, size_t count) |
| 1038 | { | 1048 | { |
| 1039 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1049 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
| 1040 | int ret = 0; | 1050 | int ret = 0; |
| @@ -1049,7 +1059,7 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute | |||
| 1049 | 1059 | ||
| 1050 | return ret ? ret : count; | 1060 | return ret ? ret : count; |
| 1051 | } | 1061 | } |
| 1052 | 1062 | static DEVICE_ATTR_RW(pm_state); | |
| 1053 | 1063 | ||
| 1054 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) | 1064 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 1055 | { | 1065 | { |
| @@ -1072,8 +1082,9 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | |||
| 1072 | p_dev->func, p_dev->device_no, | 1082 | p_dev->func, p_dev->device_no, |
| 1073 | hash[0], hash[1], hash[2], hash[3]); | 1083 | hash[0], hash[1], hash[2], hash[3]); |
| 1074 | } | 1084 | } |
| 1085 | static DEVICE_ATTR_RO(modalias); | ||
| 1075 | 1086 | ||
| 1076 | static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, | 1087 | static ssize_t allow_func_id_match_store(struct device *dev, |
| 1077 | struct device_attribute *attr, const char *buf, size_t count) | 1088 | struct device_attribute *attr, const char *buf, size_t count) |
| 1078 | { | 1089 | { |
| 1079 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1090 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
| @@ -1088,22 +1099,24 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, | |||
| 1088 | 1099 | ||
| 1089 | return count; | 1100 | return count; |
| 1090 | } | 1101 | } |
| 1091 | 1102 | static DEVICE_ATTR_WO(allow_func_id_match); | |
| 1092 | static struct device_attribute pcmcia_dev_attrs[] = { | 1103 | |
| 1093 | __ATTR(function, 0444, func_show, NULL), | 1104 | static struct attribute *pcmcia_dev_attrs[] = { |
| 1094 | __ATTR(pm_state, 0644, pcmcia_show_pm_state, pcmcia_store_pm_state), | 1105 | &dev_attr_resources.attr, |
| 1095 | __ATTR(resources, 0444, pcmcia_show_resources, NULL), | 1106 | &dev_attr_pm_state.attr, |
| 1096 | __ATTR_RO(func_id), | 1107 | &dev_attr_function.attr, |
| 1097 | __ATTR_RO(manf_id), | 1108 | &dev_attr_func_id.attr, |
| 1098 | __ATTR_RO(card_id), | 1109 | &dev_attr_manf_id.attr, |
| 1099 | __ATTR_RO(prod_id1), | 1110 | &dev_attr_card_id.attr, |
| 1100 | __ATTR_RO(prod_id2), | 1111 | &dev_attr_prod_id1.attr, |
| 1101 | __ATTR_RO(prod_id3), | 1112 | &dev_attr_prod_id2.attr, |
| 1102 | __ATTR_RO(prod_id4), | 1113 | &dev_attr_prod_id3.attr, |
| 1103 | __ATTR_RO(modalias), | 1114 | &dev_attr_prod_id4.attr, |
| 1104 | __ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match), | 1115 | &dev_attr_modalias.attr, |
| 1105 | __ATTR_NULL, | 1116 | &dev_attr_allow_func_id_match.attr, |
| 1117 | NULL, | ||
| 1106 | }; | 1118 | }; |
| 1119 | ATTRIBUTE_GROUPS(pcmcia_dev); | ||
| 1107 | 1120 | ||
| 1108 | /* PM support, also needed for reset */ | 1121 | /* PM support, also needed for reset */ |
| 1109 | 1122 | ||
| @@ -1389,7 +1402,7 @@ struct bus_type pcmcia_bus_type = { | |||
| 1389 | .name = "pcmcia", | 1402 | .name = "pcmcia", |
| 1390 | .uevent = pcmcia_bus_uevent, | 1403 | .uevent = pcmcia_bus_uevent, |
| 1391 | .match = pcmcia_bus_match, | 1404 | .match = pcmcia_bus_match, |
| 1392 | .dev_attrs = pcmcia_dev_attrs, | 1405 | .dev_groups = pcmcia_dev_groups, |
| 1393 | .probe = pcmcia_device_probe, | 1406 | .probe = pcmcia_device_probe, |
| 1394 | .remove = pcmcia_device_remove, | 1407 | .remove = pcmcia_device_remove, |
| 1395 | .suspend = pcmcia_dev_suspend, | 1408 | .suspend = pcmcia_dev_suspend, |
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index ffd53e3eb92f..c8873b0ca551 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | extern spinlock_t pnp_lock; | 6 | extern spinlock_t pnp_lock; |
| 7 | extern struct device_attribute pnp_interface_attrs[]; | 7 | extern const struct attribute_group *pnp_dev_groups[]; |
| 8 | void *pnp_alloc(long size); | 8 | void *pnp_alloc(long size); |
| 9 | 9 | ||
| 10 | int pnp_register_protocol(struct pnp_protocol *protocol); | 10 | int pnp_register_protocol(struct pnp_protocol *protocol); |
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index a39ee38a9414..6936e0acedcd 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c | |||
| @@ -246,7 +246,7 @@ struct bus_type pnp_bus_type = { | |||
| 246 | .remove = pnp_device_remove, | 246 | .remove = pnp_device_remove, |
| 247 | .shutdown = pnp_device_shutdown, | 247 | .shutdown = pnp_device_shutdown, |
| 248 | .pm = &pnp_bus_dev_pm_ops, | 248 | .pm = &pnp_bus_dev_pm_ops, |
| 249 | .dev_attrs = pnp_interface_attrs, | 249 | .dev_groups = pnp_dev_groups, |
| 250 | }; | 250 | }; |
| 251 | 251 | ||
| 252 | int pnp_register_driver(struct pnp_driver *drv) | 252 | int pnp_register_driver(struct pnp_driver *drv) |
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 0c201317284b..e6c403be09a9 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c | |||
| @@ -203,8 +203,8 @@ static void pnp_print_option(pnp_info_buffer_t * buffer, char *space, | |||
| 203 | } | 203 | } |
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | static ssize_t pnp_show_options(struct device *dmdev, | 206 | static ssize_t options_show(struct device *dmdev, struct device_attribute *attr, |
| 207 | struct device_attribute *attr, char *buf) | 207 | char *buf) |
| 208 | { | 208 | { |
| 209 | struct pnp_dev *dev = to_pnp_dev(dmdev); | 209 | struct pnp_dev *dev = to_pnp_dev(dmdev); |
| 210 | pnp_info_buffer_t *buffer; | 210 | pnp_info_buffer_t *buffer; |
| @@ -241,10 +241,10 @@ static ssize_t pnp_show_options(struct device *dmdev, | |||
| 241 | kfree(buffer); | 241 | kfree(buffer); |
| 242 | return ret; | 242 | return ret; |
| 243 | } | 243 | } |
| 244 | static DEVICE_ATTR_RO(options); | ||
| 244 | 245 | ||
| 245 | static ssize_t pnp_show_current_resources(struct device *dmdev, | 246 | static ssize_t resources_show(struct device *dmdev, |
| 246 | struct device_attribute *attr, | 247 | struct device_attribute *attr, char *buf) |
| 247 | char *buf) | ||
| 248 | { | 248 | { |
| 249 | struct pnp_dev *dev = to_pnp_dev(dmdev); | 249 | struct pnp_dev *dev = to_pnp_dev(dmdev); |
| 250 | pnp_info_buffer_t *buffer; | 250 | pnp_info_buffer_t *buffer; |
| @@ -331,9 +331,9 @@ static char *pnp_get_resource_value(char *buf, | |||
| 331 | return buf; | 331 | return buf; |
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | static ssize_t pnp_set_current_resources(struct device *dmdev, | 334 | static ssize_t resources_store(struct device *dmdev, |
| 335 | struct device_attribute *attr, | 335 | struct device_attribute *attr, const char *ubuf, |
| 336 | const char *ubuf, size_t count) | 336 | size_t count) |
| 337 | { | 337 | { |
| 338 | struct pnp_dev *dev = to_pnp_dev(dmdev); | 338 | struct pnp_dev *dev = to_pnp_dev(dmdev); |
| 339 | char *buf = (void *)ubuf; | 339 | char *buf = (void *)ubuf; |
| @@ -434,9 +434,10 @@ done: | |||
| 434 | return retval; | 434 | return retval; |
| 435 | return count; | 435 | return count; |
| 436 | } | 436 | } |
| 437 | static DEVICE_ATTR_RW(resources); | ||
| 437 | 438 | ||
| 438 | static ssize_t pnp_show_current_ids(struct device *dmdev, | 439 | static ssize_t id_show(struct device *dmdev, struct device_attribute *attr, |
| 439 | struct device_attribute *attr, char *buf) | 440 | char *buf) |
| 440 | { | 441 | { |
| 441 | char *str = buf; | 442 | char *str = buf; |
| 442 | struct pnp_dev *dev = to_pnp_dev(dmdev); | 443 | struct pnp_dev *dev = to_pnp_dev(dmdev); |
| @@ -448,12 +449,20 @@ static ssize_t pnp_show_current_ids(struct device *dmdev, | |||
| 448 | } | 449 | } |
| 449 | return (str - buf); | 450 | return (str - buf); |
| 450 | } | 451 | } |
| 452 | static DEVICE_ATTR_RO(id); | ||
| 451 | 453 | ||
| 452 | struct device_attribute pnp_interface_attrs[] = { | 454 | static struct attribute *pnp_dev_attrs[] = { |
| 453 | __ATTR(resources, S_IRUGO | S_IWUSR, | 455 | &dev_attr_resources.attr, |
| 454 | pnp_show_current_resources, | 456 | &dev_attr_options.attr, |
| 455 | pnp_set_current_resources), | 457 | &dev_attr_id.attr, |
| 456 | __ATTR(options, S_IRUGO, pnp_show_options, NULL), | 458 | NULL, |
| 457 | __ATTR(id, S_IRUGO, pnp_show_current_ids, NULL), | 459 | }; |
| 458 | __ATTR_NULL, | 460 | |
| 461 | static const struct attribute_group pnp_dev_group = { | ||
| 462 | .attrs = pnp_dev_attrs, | ||
| 463 | }; | ||
| 464 | |||
| 465 | const struct attribute_group *pnp_dev_groups[] = { | ||
| 466 | &pnp_dev_group, | ||
| 467 | NULL, | ||
| 459 | }; | 468 | }; |
diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c index 3e9b6a78ad18..c9ae692d3451 100644 --- a/drivers/rapidio/rio-driver.c +++ b/drivers/rapidio/rio-driver.c | |||
| @@ -223,8 +223,8 @@ struct device rio_bus = { | |||
| 223 | struct bus_type rio_bus_type = { | 223 | struct bus_type rio_bus_type = { |
| 224 | .name = "rapidio", | 224 | .name = "rapidio", |
| 225 | .match = rio_match_bus, | 225 | .match = rio_match_bus, |
| 226 | .dev_attrs = rio_dev_attrs, | 226 | .dev_groups = rio_dev_groups, |
| 227 | .bus_attrs = rio_bus_attrs, | 227 | .bus_groups = rio_bus_groups, |
| 228 | .probe = rio_device_probe, | 228 | .probe = rio_device_probe, |
| 229 | .remove = rio_device_remove, | 229 | .remove = rio_device_remove, |
| 230 | .uevent = rio_uevent, | 230 | .uevent = rio_uevent, |
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 9331be646dc3..e0221c6d0cc2 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c | |||
| @@ -27,6 +27,7 @@ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ | |||
| 27 | \ | 27 | \ |
| 28 | return sprintf(buf, format_string, rdev->field); \ | 28 | return sprintf(buf, format_string, rdev->field); \ |
| 29 | } \ | 29 | } \ |
| 30 | static DEVICE_ATTR_RO(field); | ||
| 30 | 31 | ||
| 31 | rio_config_attr(did, "0x%04x\n"); | 32 | rio_config_attr(did, "0x%04x\n"); |
| 32 | rio_config_attr(vid, "0x%04x\n"); | 33 | rio_config_attr(vid, "0x%04x\n"); |
| @@ -54,6 +55,7 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch | |||
| 54 | 55 | ||
| 55 | return (str - buf); | 56 | return (str - buf); |
| 56 | } | 57 | } |
| 58 | static DEVICE_ATTR_RO(routes); | ||
| 57 | 59 | ||
| 58 | static ssize_t lprev_show(struct device *dev, | 60 | static ssize_t lprev_show(struct device *dev, |
| 59 | struct device_attribute *attr, char *buf) | 61 | struct device_attribute *attr, char *buf) |
| @@ -63,6 +65,7 @@ static ssize_t lprev_show(struct device *dev, | |||
| 63 | return sprintf(buf, "%s\n", | 65 | return sprintf(buf, "%s\n", |
| 64 | (rdev->prev) ? rio_name(rdev->prev) : "root"); | 66 | (rdev->prev) ? rio_name(rdev->prev) : "root"); |
| 65 | } | 67 | } |
| 68 | static DEVICE_ATTR_RO(lprev); | ||
| 66 | 69 | ||
| 67 | static ssize_t lnext_show(struct device *dev, | 70 | static ssize_t lnext_show(struct device *dev, |
| 68 | struct device_attribute *attr, char *buf) | 71 | struct device_attribute *attr, char *buf) |
| @@ -83,6 +86,7 @@ static ssize_t lnext_show(struct device *dev, | |||
| 83 | 86 | ||
| 84 | return str - buf; | 87 | return str - buf; |
| 85 | } | 88 | } |
| 89 | static DEVICE_ATTR_RO(lnext); | ||
| 86 | 90 | ||
| 87 | static ssize_t modalias_show(struct device *dev, | 91 | static ssize_t modalias_show(struct device *dev, |
| 88 | struct device_attribute *attr, char *buf) | 92 | struct device_attribute *attr, char *buf) |
| @@ -92,23 +96,29 @@ static ssize_t modalias_show(struct device *dev, | |||
| 92 | return sprintf(buf, "rapidio:v%04Xd%04Xav%04Xad%04X\n", | 96 | return sprintf(buf, "rapidio:v%04Xd%04Xav%04Xad%04X\n", |
| 93 | rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did); | 97 | rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did); |
| 94 | } | 98 | } |
| 99 | static DEVICE_ATTR_RO(modalias); | ||
| 100 | |||
| 101 | static struct attribute *rio_dev_attrs[] = { | ||
| 102 | &dev_attr_did.attr, | ||
| 103 | &dev_attr_vid.attr, | ||
| 104 | &dev_attr_device_rev.attr, | ||
| 105 | &dev_attr_asm_did.attr, | ||
| 106 | &dev_attr_asm_vid.attr, | ||
| 107 | &dev_attr_asm_rev.attr, | ||
| 108 | &dev_attr_lprev.attr, | ||
| 109 | &dev_attr_destid.attr, | ||
| 110 | &dev_attr_modalias.attr, | ||
| 111 | NULL, | ||
| 112 | }; | ||
| 95 | 113 | ||
| 96 | struct device_attribute rio_dev_attrs[] = { | 114 | static const struct attribute_group rio_dev_group = { |
| 97 | __ATTR_RO(did), | 115 | .attrs = rio_dev_attrs, |
| 98 | __ATTR_RO(vid), | ||
| 99 | __ATTR_RO(device_rev), | ||
| 100 | __ATTR_RO(asm_did), | ||
| 101 | __ATTR_RO(asm_vid), | ||
| 102 | __ATTR_RO(asm_rev), | ||
| 103 | __ATTR_RO(lprev), | ||
| 104 | __ATTR_RO(destid), | ||
| 105 | __ATTR_RO(modalias), | ||
| 106 | __ATTR_NULL, | ||
| 107 | }; | 116 | }; |
| 108 | 117 | ||
| 109 | static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL); | 118 | const struct attribute_group *rio_dev_groups[] = { |
| 110 | static DEVICE_ATTR(lnext, S_IRUGO, lnext_show, NULL); | 119 | &rio_dev_group, |
| 111 | static DEVICE_ATTR(hopcount, S_IRUGO, hopcount_show, NULL); | 120 | NULL, |
| 121 | }; | ||
| 112 | 122 | ||
| 113 | static ssize_t | 123 | static ssize_t |
| 114 | rio_read_config(struct file *filp, struct kobject *kobj, | 124 | rio_read_config(struct file *filp, struct kobject *kobj, |
| @@ -316,8 +326,18 @@ exit: | |||
| 316 | 326 | ||
| 317 | return rc; | 327 | return rc; |
| 318 | } | 328 | } |
| 329 | static BUS_ATTR(scan, (S_IWUSR|S_IWGRP), NULL, bus_scan_store); | ||
| 330 | |||
| 331 | static struct attribute *rio_bus_attrs[] = { | ||
| 332 | &bus_attr_scan.attr, | ||
| 333 | NULL, | ||
| 334 | }; | ||
| 335 | |||
| 336 | static const struct attribute_group rio_bus_group = { | ||
| 337 | .attrs = rio_bus_attrs, | ||
| 338 | }; | ||
| 319 | 339 | ||
| 320 | struct bus_attribute rio_bus_attrs[] = { | 340 | const struct attribute_group *rio_bus_groups[] = { |
| 321 | __ATTR(scan, (S_IWUSR|S_IWGRP), NULL, bus_scan_store), | 341 | &rio_bus_group, |
| 322 | __ATTR_NULL | 342 | NULL, |
| 323 | }; | 343 | }; |
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index 085215cd8502..5f99d22ad0b0 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h | |||
| @@ -48,8 +48,8 @@ extern struct rio_mport *rio_find_mport(int mport_id); | |||
| 48 | extern int rio_mport_scan(int mport_id); | 48 | extern int rio_mport_scan(int mport_id); |
| 49 | 49 | ||
| 50 | /* Structures internal to the RIO core code */ | 50 | /* Structures internal to the RIO core code */ |
| 51 | extern struct device_attribute rio_dev_attrs[]; | 51 | extern const struct attribute_group *rio_dev_groups[]; |
| 52 | extern struct bus_attribute rio_bus_attrs[]; | 52 | extern const struct attribute_group *rio_bus_groups[]; |
| 53 | 53 | ||
| 54 | #define RIO_GET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16)) | 54 | #define RIO_GET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16)) |
| 55 | #define RIO_SET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x000000ff) << 16)) | 55 | #define RIO_SET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x000000ff) << 16)) |
diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index c9382d6eee78..1f4f22fe8281 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c | |||
| @@ -553,16 +553,20 @@ static struct device_type fcoe_fcf_device_type = { | |||
| 553 | .release = fcoe_fcf_device_release, | 553 | .release = fcoe_fcf_device_release, |
| 554 | }; | 554 | }; |
| 555 | 555 | ||
| 556 | static struct bus_attribute fcoe_bus_attr_group[] = { | 556 | static BUS_ATTR(ctlr_create, S_IWUSR, NULL, fcoe_ctlr_create_store); |
| 557 | __ATTR(ctlr_create, S_IWUSR, NULL, fcoe_ctlr_create_store), | 557 | static BUS_ATTR(ctlr_destroy, S_IWUSR, NULL, fcoe_ctlr_destroy_store); |
| 558 | __ATTR(ctlr_destroy, S_IWUSR, NULL, fcoe_ctlr_destroy_store), | 558 | |
| 559 | __ATTR_NULL | 559 | static struct attribute *fcoe_bus_attrs[] = { |
| 560 | &bus_attr_ctlr_create.attr, | ||
| 561 | &bus_attr_ctlr_destroy.attr, | ||
| 562 | NULL, | ||
| 560 | }; | 563 | }; |
| 564 | ATTRIBUTE_GROUPS(fcoe_bus); | ||
| 561 | 565 | ||
| 562 | static struct bus_type fcoe_bus_type = { | 566 | static struct bus_type fcoe_bus_type = { |
| 563 | .name = "fcoe", | 567 | .name = "fcoe", |
| 564 | .match = &fcoe_bus_match, | 568 | .match = &fcoe_bus_match, |
| 565 | .bus_attrs = fcoe_bus_attr_group, | 569 | .bus_groups = fcoe_bus_groups, |
| 566 | }; | 570 | }; |
| 567 | 571 | ||
| 568 | /** | 572 | /** |
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index e55ddf7cd7c2..32a811d11c25 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c | |||
| @@ -374,7 +374,8 @@ static ssize_t \ | |||
| 374 | attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \ | 374 | attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \ |
| 375 | { \ | 375 | { \ |
| 376 | return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \ | 376 | return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \ |
| 377 | } | 377 | } \ |
| 378 | static DEVICE_ATTR_RO(attrib); | ||
| 378 | 379 | ||
| 379 | ssb_config_attr(core_num, core_index, "%u\n") | 380 | ssb_config_attr(core_num, core_index, "%u\n") |
| 380 | ssb_config_attr(coreid, id.coreid, "0x%04x\n") | 381 | ssb_config_attr(coreid, id.coreid, "0x%04x\n") |
| @@ -387,16 +388,18 @@ name_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
| 387 | return sprintf(buf, "%s\n", | 388 | return sprintf(buf, "%s\n", |
| 388 | ssb_core_name(dev_to_ssb_dev(dev)->id.coreid)); | 389 | ssb_core_name(dev_to_ssb_dev(dev)->id.coreid)); |
| 389 | } | 390 | } |
| 390 | 391 | static DEVICE_ATTR_RO(name); | |
| 391 | static struct device_attribute ssb_device_attrs[] = { | 392 | |
| 392 | __ATTR_RO(name), | 393 | static struct attribute *ssb_device_attrs[] = { |
| 393 | __ATTR_RO(core_num), | 394 | &dev_attr_name.attr, |
| 394 | __ATTR_RO(coreid), | 395 | &dev_attr_core_num.attr, |
| 395 | __ATTR_RO(vendor), | 396 | &dev_attr_coreid.attr, |
| 396 | __ATTR_RO(revision), | 397 | &dev_attr_vendor.attr, |
| 397 | __ATTR_RO(irq), | 398 | &dev_attr_revision.attr, |
| 398 | __ATTR_NULL, | 399 | &dev_attr_irq.attr, |
| 400 | NULL, | ||
| 399 | }; | 401 | }; |
| 402 | ATTRIBUTE_GROUPS(ssb_device); | ||
| 400 | 403 | ||
| 401 | static struct bus_type ssb_bustype = { | 404 | static struct bus_type ssb_bustype = { |
| 402 | .name = "ssb", | 405 | .name = "ssb", |
| @@ -407,7 +410,7 @@ static struct bus_type ssb_bustype = { | |||
| 407 | .suspend = ssb_device_suspend, | 410 | .suspend = ssb_device_suspend, |
| 408 | .resume = ssb_device_resume, | 411 | .resume = ssb_device_resume, |
| 409 | .uevent = ssb_device_uevent, | 412 | .uevent = ssb_device_uevent, |
| 410 | .dev_attrs = ssb_device_attrs, | 413 | .dev_groups = ssb_device_groups, |
| 411 | }; | 414 | }; |
| 412 | 415 | ||
| 413 | static void ssb_buses_lock(void) | 416 | static void ssb_buses_lock(void) |
diff --git a/drivers/uwb/umc-bus.c b/drivers/uwb/umc-bus.c index 5c5b3fc9088a..e3ed6ff6a481 100644 --- a/drivers/uwb/umc-bus.c +++ b/drivers/uwb/umc-bus.c | |||
| @@ -201,6 +201,7 @@ static ssize_t capability_id_show(struct device *dev, struct device_attribute *a | |||
| 201 | 201 | ||
| 202 | return sprintf(buf, "0x%02x\n", umc->cap_id); | 202 | return sprintf(buf, "0x%02x\n", umc->cap_id); |
| 203 | } | 203 | } |
| 204 | static DEVICE_ATTR_RO(capability_id); | ||
| 204 | 205 | ||
| 205 | static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) | 206 | static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 206 | { | 207 | { |
| @@ -208,12 +209,14 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, c | |||
| 208 | 209 | ||
| 209 | return sprintf(buf, "0x%04x\n", umc->version); | 210 | return sprintf(buf, "0x%04x\n", umc->version); |
| 210 | } | 211 | } |
| 212 | static DEVICE_ATTR_RO(version); | ||
| 211 | 213 | ||
| 212 | static struct device_attribute umc_dev_attrs[] = { | 214 | static struct attribute *umc_dev_attrs[] = { |
| 213 | __ATTR_RO(capability_id), | 215 | &dev_attr_capability_id.attr, |
| 214 | __ATTR_RO(version), | 216 | &dev_attr_version.attr, |
| 215 | __ATTR_NULL, | 217 | NULL, |
| 216 | }; | 218 | }; |
| 219 | ATTRIBUTE_GROUPS(umc_dev); | ||
| 217 | 220 | ||
| 218 | struct bus_type umc_bus_type = { | 221 | struct bus_type umc_bus_type = { |
| 219 | .name = "umc", | 222 | .name = "umc", |
| @@ -222,7 +225,7 @@ struct bus_type umc_bus_type = { | |||
| 222 | .remove = umc_device_remove, | 225 | .remove = umc_device_remove, |
| 223 | .suspend = umc_device_suspend, | 226 | .suspend = umc_device_suspend, |
| 224 | .resume = umc_device_resume, | 227 | .resume = umc_device_resume, |
| 225 | .dev_attrs = umc_dev_attrs, | 228 | .dev_groups = umc_dev_groups, |
| 226 | }; | 229 | }; |
| 227 | EXPORT_SYMBOL_GPL(umc_bus_type); | 230 | EXPORT_SYMBOL_GPL(umc_bus_type); |
| 228 | 231 | ||
diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index 0393d827dd44..f7447f7004fb 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c | |||
| @@ -118,7 +118,7 @@ static const struct backlight_ops atmel_pwm_bl_ops = { | |||
| 118 | .update_status = atmel_pwm_bl_set_intensity, | 118 | .update_status = atmel_pwm_bl_set_intensity, |
| 119 | }; | 119 | }; |
| 120 | 120 | ||
| 121 | static int __init atmel_pwm_bl_probe(struct platform_device *pdev) | 121 | static int atmel_pwm_bl_probe(struct platform_device *pdev) |
| 122 | { | 122 | { |
| 123 | struct backlight_properties props; | 123 | struct backlight_properties props; |
| 124 | const struct atmel_pwm_bl_platform_data *pdata; | 124 | const struct atmel_pwm_bl_platform_data *pdata; |
| @@ -202,7 +202,7 @@ err_free_mem: | |||
| 202 | return retval; | 202 | return retval; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | static int __exit atmel_pwm_bl_remove(struct platform_device *pdev) | 205 | static int atmel_pwm_bl_remove(struct platform_device *pdev) |
| 206 | { | 206 | { |
| 207 | struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev); | 207 | struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev); |
| 208 | 208 | ||
| @@ -220,10 +220,11 @@ static struct platform_driver atmel_pwm_bl_driver = { | |||
| 220 | .name = "atmel-pwm-bl", | 220 | .name = "atmel-pwm-bl", |
| 221 | }, | 221 | }, |
| 222 | /* REVISIT add suspend() and resume() */ | 222 | /* REVISIT add suspend() and resume() */ |
| 223 | .remove = __exit_p(atmel_pwm_bl_remove), | 223 | .probe = atmel_pwm_bl_probe, |
| 224 | .remove = atmel_pwm_bl_remove, | ||
| 224 | }; | 225 | }; |
| 225 | 226 | ||
| 226 | module_platform_driver_probe(atmel_pwm_bl_driver, atmel_pwm_bl_probe); | 227 | module_platform_driver(atmel_pwm_bl_driver); |
| 227 | 228 | ||
| 228 | MODULE_AUTHOR("Hans-Christian egtvedt <hans-christian.egtvedt@atmel.com>"); | 229 | MODULE_AUTHOR("Hans-Christian egtvedt <hans-christian.egtvedt@atmel.com>"); |
| 229 | MODULE_DESCRIPTION("Atmel PWM backlight driver"); | 230 | MODULE_DESCRIPTION("Atmel PWM backlight driver"); |
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index ee59b74768d9..fed0ce198ae3 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c | |||
| @@ -13,18 +13,24 @@ static ssize_t device_show(struct device *_d, | |||
| 13 | struct virtio_device *dev = dev_to_virtio(_d); | 13 | struct virtio_device *dev = dev_to_virtio(_d); |
| 14 | return sprintf(buf, "0x%04x\n", dev->id.device); | 14 | return sprintf(buf, "0x%04x\n", dev->id.device); |
| 15 | } | 15 | } |
| 16 | static DEVICE_ATTR_RO(device); | ||
| 17 | |||
| 16 | static ssize_t vendor_show(struct device *_d, | 18 | static ssize_t vendor_show(struct device *_d, |
| 17 | struct device_attribute *attr, char *buf) | 19 | struct device_attribute *attr, char *buf) |
| 18 | { | 20 | { |
| 19 | struct virtio_device *dev = dev_to_virtio(_d); | 21 | struct virtio_device *dev = dev_to_virtio(_d); |
| 20 | return sprintf(buf, "0x%04x\n", dev->id.vendor); | 22 | return sprintf(buf, "0x%04x\n", dev->id.vendor); |
| 21 | } | 23 | } |
| 24 | static DEVICE_ATTR_RO(vendor); | ||
| 25 | |||
| 22 | static ssize_t status_show(struct device *_d, | 26 | static ssize_t status_show(struct device *_d, |
| 23 | struct device_attribute *attr, char *buf) | 27 | struct device_attribute *attr, char *buf) |
| 24 | { | 28 | { |
| 25 | struct virtio_device *dev = dev_to_virtio(_d); | 29 | struct virtio_device *dev = dev_to_virtio(_d); |
| 26 | return sprintf(buf, "0x%08x\n", dev->config->get_status(dev)); | 30 | return sprintf(buf, "0x%08x\n", dev->config->get_status(dev)); |
| 27 | } | 31 | } |
| 32 | static DEVICE_ATTR_RO(status); | ||
| 33 | |||
| 28 | static ssize_t modalias_show(struct device *_d, | 34 | static ssize_t modalias_show(struct device *_d, |
| 29 | struct device_attribute *attr, char *buf) | 35 | struct device_attribute *attr, char *buf) |
| 30 | { | 36 | { |
| @@ -32,6 +38,8 @@ static ssize_t modalias_show(struct device *_d, | |||
| 32 | return sprintf(buf, "virtio:d%08Xv%08X\n", | 38 | return sprintf(buf, "virtio:d%08Xv%08X\n", |
| 33 | dev->id.device, dev->id.vendor); | 39 | dev->id.device, dev->id.vendor); |
| 34 | } | 40 | } |
| 41 | static DEVICE_ATTR_RO(modalias); | ||
| 42 | |||
| 35 | static ssize_t features_show(struct device *_d, | 43 | static ssize_t features_show(struct device *_d, |
| 36 | struct device_attribute *attr, char *buf) | 44 | struct device_attribute *attr, char *buf) |
| 37 | { | 45 | { |
| @@ -47,14 +55,17 @@ static ssize_t features_show(struct device *_d, | |||
| 47 | len += sprintf(buf+len, "\n"); | 55 | len += sprintf(buf+len, "\n"); |
| 48 | return len; | 56 | return len; |
| 49 | } | 57 | } |
| 50 | static struct device_attribute virtio_dev_attrs[] = { | 58 | static DEVICE_ATTR_RO(features); |
| 51 | __ATTR_RO(device), | 59 | |
| 52 | __ATTR_RO(vendor), | 60 | static struct attribute *virtio_dev_attrs[] = { |
| 53 | __ATTR_RO(status), | 61 | &dev_attr_device.attr, |
| 54 | __ATTR_RO(modalias), | 62 | &dev_attr_vendor.attr, |
| 55 | __ATTR_RO(features), | 63 | &dev_attr_status.attr, |
| 56 | __ATTR_NULL | 64 | &dev_attr_modalias.attr, |
| 65 | &dev_attr_features.attr, | ||
| 66 | NULL, | ||
| 57 | }; | 67 | }; |
| 68 | ATTRIBUTE_GROUPS(virtio_dev); | ||
| 58 | 69 | ||
| 59 | static inline int virtio_id_match(const struct virtio_device *dev, | 70 | static inline int virtio_id_match(const struct virtio_device *dev, |
| 60 | const struct virtio_device_id *id) | 71 | const struct virtio_device_id *id) |
| @@ -165,7 +176,7 @@ static int virtio_dev_remove(struct device *_d) | |||
| 165 | static struct bus_type virtio_bus = { | 176 | static struct bus_type virtio_bus = { |
| 166 | .name = "virtio", | 177 | .name = "virtio", |
| 167 | .match = virtio_dev_match, | 178 | .match = virtio_dev_match, |
| 168 | .dev_attrs = virtio_dev_attrs, | 179 | .dev_groups = virtio_dev_groups, |
| 169 | .uevent = virtio_uevent, | 180 | .uevent = virtio_uevent, |
| 170 | .probe = virtio_dev_probe, | 181 | .probe = virtio_dev_probe, |
| 171 | .remove = virtio_dev_remove, | 182 | .remove = virtio_dev_remove, |
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 38e92b770e91..3c0a74b3e9b1 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c | |||
| @@ -384,12 +384,14 @@ static ssize_t nodename_show(struct device *dev, | |||
| 384 | { | 384 | { |
| 385 | return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename); | 385 | return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename); |
| 386 | } | 386 | } |
| 387 | static DEVICE_ATTR_RO(nodename); | ||
| 387 | 388 | ||
| 388 | static ssize_t devtype_show(struct device *dev, | 389 | static ssize_t devtype_show(struct device *dev, |
| 389 | struct device_attribute *attr, char *buf) | 390 | struct device_attribute *attr, char *buf) |
| 390 | { | 391 | { |
| 391 | return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype); | 392 | return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype); |
| 392 | } | 393 | } |
| 394 | static DEVICE_ATTR_RO(devtype); | ||
| 393 | 395 | ||
| 394 | static ssize_t modalias_show(struct device *dev, | 396 | static ssize_t modalias_show(struct device *dev, |
| 395 | struct device_attribute *attr, char *buf) | 397 | struct device_attribute *attr, char *buf) |
| @@ -397,14 +399,24 @@ static ssize_t modalias_show(struct device *dev, | |||
| 397 | return sprintf(buf, "%s:%s\n", dev->bus->name, | 399 | return sprintf(buf, "%s:%s\n", dev->bus->name, |
| 398 | to_xenbus_device(dev)->devicetype); | 400 | to_xenbus_device(dev)->devicetype); |
| 399 | } | 401 | } |
| 402 | static DEVICE_ATTR_RO(modalias); | ||
| 400 | 403 | ||
| 401 | struct device_attribute xenbus_dev_attrs[] = { | 404 | static struct attribute *xenbus_dev_attrs[] = { |
| 402 | __ATTR_RO(nodename), | 405 | &dev_attr_nodename.attr, |
| 403 | __ATTR_RO(devtype), | 406 | &dev_attr_devtype.attr, |
| 404 | __ATTR_RO(modalias), | 407 | &dev_attr_modalias.attr, |
| 405 | __ATTR_NULL | 408 | NULL, |
| 406 | }; | 409 | }; |
| 407 | EXPORT_SYMBOL_GPL(xenbus_dev_attrs); | 410 | |
| 411 | static const struct attribute_group xenbus_dev_group = { | ||
| 412 | .attrs = xenbus_dev_attrs, | ||
| 413 | }; | ||
| 414 | |||
| 415 | const struct attribute_group *xenbus_dev_groups[] = { | ||
| 416 | &xenbus_dev_group, | ||
| 417 | NULL, | ||
| 418 | }; | ||
| 419 | EXPORT_SYMBOL_GPL(xenbus_dev_groups); | ||
| 408 | 420 | ||
| 409 | int xenbus_probe_node(struct xen_bus_type *bus, | 421 | int xenbus_probe_node(struct xen_bus_type *bus, |
| 410 | const char *type, | 422 | const char *type, |
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h index 146f857a36f8..1085ec294a19 100644 --- a/drivers/xen/xenbus/xenbus_probe.h +++ b/drivers/xen/xenbus/xenbus_probe.h | |||
| @@ -54,7 +54,7 @@ enum xenstore_init { | |||
| 54 | XS_LOCAL, | 54 | XS_LOCAL, |
| 55 | }; | 55 | }; |
| 56 | 56 | ||
| 57 | extern struct device_attribute xenbus_dev_attrs[]; | 57 | extern const struct attribute_group *xenbus_dev_groups[]; |
| 58 | 58 | ||
| 59 | extern int xenbus_match(struct device *_dev, struct device_driver *_drv); | 59 | extern int xenbus_match(struct device *_dev, struct device_driver *_drv); |
| 60 | extern int xenbus_dev_probe(struct device *_dev); | 60 | extern int xenbus_dev_probe(struct device *_dev); |
diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c index 998bbbab816b..5125dce11a60 100644 --- a/drivers/xen/xenbus/xenbus_probe_backend.c +++ b/drivers/xen/xenbus/xenbus_probe_backend.c | |||
| @@ -200,7 +200,7 @@ static struct xen_bus_type xenbus_backend = { | |||
| 200 | .probe = xenbus_dev_probe, | 200 | .probe = xenbus_dev_probe, |
| 201 | .remove = xenbus_dev_remove, | 201 | .remove = xenbus_dev_remove, |
| 202 | .shutdown = xenbus_dev_shutdown, | 202 | .shutdown = xenbus_dev_shutdown, |
| 203 | .dev_attrs = xenbus_dev_attrs, | 203 | .dev_groups = xenbus_dev_groups, |
| 204 | }, | 204 | }, |
| 205 | }; | 205 | }; |
| 206 | 206 | ||
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index 34b20bfa4e8c..129bf84c19ec 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c | |||
| @@ -154,7 +154,7 @@ static struct xen_bus_type xenbus_frontend = { | |||
| 154 | .probe = xenbus_frontend_dev_probe, | 154 | .probe = xenbus_frontend_dev_probe, |
| 155 | .remove = xenbus_dev_remove, | 155 | .remove = xenbus_dev_remove, |
| 156 | .shutdown = xenbus_dev_shutdown, | 156 | .shutdown = xenbus_dev_shutdown, |
| 157 | .dev_attrs = xenbus_dev_attrs, | 157 | .dev_groups = xenbus_dev_groups, |
| 158 | 158 | ||
| 159 | .pm = &xenbus_pm_ops, | 159 | .pm = &xenbus_pm_ops, |
| 160 | }, | 160 | }, |
diff --git a/fs/sysfs/Makefile b/fs/sysfs/Makefile index 7a1ceb946b80..8876ac183373 100644 --- a/fs/sysfs/Makefile +++ b/fs/sysfs/Makefile | |||
| @@ -2,5 +2,4 @@ | |||
| 2 | # Makefile for the sysfs virtual filesystem | 2 | # Makefile for the sysfs virtual filesystem |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y := inode.o file.o dir.o symlink.o mount.o bin.o \ | 5 | obj-y := inode.o file.o dir.o symlink.o mount.o group.o |
| 6 | group.o | ||
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c deleted file mode 100644 index c590cabd57bb..000000000000 --- a/fs/sysfs/bin.c +++ /dev/null | |||
| @@ -1,502 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * fs/sysfs/bin.c - sysfs binary file implementation | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 Patrick Mochel | ||
| 5 | * Copyright (c) 2003 Matthew Wilcox | ||
| 6 | * Copyright (c) 2004 Silicon Graphics, Inc. | ||
| 7 | * Copyright (c) 2007 SUSE Linux Products GmbH | ||
| 8 | * Copyright (c) 2007 Tejun Heo <teheo@suse.de> | ||
| 9 | * | ||
| 10 | * This file is released under the GPLv2. | ||
| 11 | * | ||
| 12 | * Please see Documentation/filesystems/sysfs.txt for more information. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #undef DEBUG | ||
| 16 | |||
| 17 | #include <linux/errno.h> | ||
| 18 | #include <linux/fs.h> | ||
| 19 | #include <linux/kernel.h> | ||
| 20 | #include <linux/kobject.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/mutex.h> | ||
| 24 | #include <linux/mm.h> | ||
| 25 | #include <linux/uaccess.h> | ||
| 26 | |||
| 27 | #include "sysfs.h" | ||
| 28 | |||
| 29 | /* | ||
| 30 | * There's one bin_buffer for each open file. | ||
| 31 | * | ||
| 32 | * filp->private_data points to bin_buffer and | ||
| 33 | * sysfs_dirent->s_bin_attr.buffers points to a the bin_buffer s | ||
| 34 | * sysfs_dirent->s_bin_attr.buffers is protected by sysfs_bin_lock | ||
| 35 | */ | ||
| 36 | static DEFINE_MUTEX(sysfs_bin_lock); | ||
| 37 | |||
| 38 | struct bin_buffer { | ||
| 39 | struct mutex mutex; | ||
| 40 | void *buffer; | ||
| 41 | int mmapped; | ||
| 42 | const struct vm_operations_struct *vm_ops; | ||
| 43 | struct file *file; | ||
| 44 | struct hlist_node list; | ||
| 45 | }; | ||
| 46 | |||
| 47 | static int | ||
| 48 | fill_read(struct file *file, char *buffer, loff_t off, size_t count) | ||
| 49 | { | ||
| 50 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | ||
| 51 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; | ||
| 52 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | ||
| 53 | int rc; | ||
| 54 | |||
| 55 | /* need attr_sd for attr, its parent for kobj */ | ||
| 56 | if (!sysfs_get_active(attr_sd)) | ||
| 57 | return -ENODEV; | ||
| 58 | |||
| 59 | rc = -EIO; | ||
| 60 | if (attr->read) | ||
| 61 | rc = attr->read(file, kobj, attr, buffer, off, count); | ||
| 62 | |||
| 63 | sysfs_put_active(attr_sd); | ||
| 64 | |||
| 65 | return rc; | ||
| 66 | } | ||
| 67 | |||
| 68 | static ssize_t | ||
| 69 | read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) | ||
| 70 | { | ||
| 71 | struct bin_buffer *bb = file->private_data; | ||
| 72 | int size = file_inode(file)->i_size; | ||
| 73 | loff_t offs = *off; | ||
| 74 | int count = min_t(size_t, bytes, PAGE_SIZE); | ||
| 75 | char *temp; | ||
| 76 | |||
| 77 | if (!bytes) | ||
| 78 | return 0; | ||
| 79 | |||
| 80 | if (size) { | ||
| 81 | if (offs > size) | ||
| 82 | return 0; | ||
| 83 | if (offs + count > size) | ||
| 84 | count = size - offs; | ||
| 85 | } | ||
| 86 | |||
| 87 | temp = kmalloc(count, GFP_KERNEL); | ||
| 88 | if (!temp) | ||
| 89 | return -ENOMEM; | ||
| 90 | |||
| 91 | mutex_lock(&bb->mutex); | ||
| 92 | |||
| 93 | count = fill_read(file, bb->buffer, offs, count); | ||
| 94 | if (count < 0) { | ||
| 95 | mutex_unlock(&bb->mutex); | ||
| 96 | goto out_free; | ||
| 97 | } | ||
| 98 | |||
| 99 | memcpy(temp, bb->buffer, count); | ||
| 100 | |||
| 101 | mutex_unlock(&bb->mutex); | ||
| 102 | |||
| 103 | if (copy_to_user(userbuf, temp, count)) { | ||
| 104 | count = -EFAULT; | ||
| 105 | goto out_free; | ||
| 106 | } | ||
| 107 | |||
| 108 | pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count); | ||
| 109 | |||
| 110 | *off = offs + count; | ||
| 111 | |||
| 112 | out_free: | ||
| 113 | kfree(temp); | ||
| 114 | return count; | ||
| 115 | } | ||
| 116 | |||
| 117 | static int | ||
| 118 | flush_write(struct file *file, char *buffer, loff_t offset, size_t count) | ||
| 119 | { | ||
| 120 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | ||
| 121 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; | ||
| 122 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | ||
| 123 | int rc; | ||
| 124 | |||
| 125 | /* need attr_sd for attr, its parent for kobj */ | ||
| 126 | if (!sysfs_get_active(attr_sd)) | ||
| 127 | return -ENODEV; | ||
| 128 | |||
| 129 | rc = -EIO; | ||
| 130 | if (attr->write) | ||
| 131 | rc = attr->write(file, kobj, attr, buffer, offset, count); | ||
| 132 | |||
| 133 | sysfs_put_active(attr_sd); | ||
| 134 | |||
| 135 | return rc; | ||
| 136 | } | ||
| 137 | |||
| 138 | static ssize_t write(struct file *file, const char __user *userbuf, | ||
| 139 | size_t bytes, loff_t *off) | ||
| 140 | { | ||
| 141 | struct bin_buffer *bb = file->private_data; | ||
| 142 | int size = file_inode(file)->i_size; | ||
| 143 | loff_t offs = *off; | ||
| 144 | int count = min_t(size_t, bytes, PAGE_SIZE); | ||
| 145 | char *temp; | ||
| 146 | |||
| 147 | if (!bytes) | ||
| 148 | return 0; | ||
| 149 | |||
| 150 | if (size) { | ||
| 151 | if (offs > size) | ||
| 152 | return 0; | ||
| 153 | if (offs + count > size) | ||
| 154 | count = size - offs; | ||
| 155 | } | ||
| 156 | |||
| 157 | temp = memdup_user(userbuf, count); | ||
| 158 | if (IS_ERR(temp)) | ||
| 159 | return PTR_ERR(temp); | ||
| 160 | |||
| 161 | mutex_lock(&bb->mutex); | ||
| 162 | |||
| 163 | memcpy(bb->buffer, temp, count); | ||
| 164 | |||
| 165 | count = flush_write(file, bb->buffer, offs, count); | ||
| 166 | mutex_unlock(&bb->mutex); | ||
| 167 | |||
| 168 | if (count > 0) | ||
| 169 | *off = offs + count; | ||
| 170 | |||
| 171 | kfree(temp); | ||
| 172 | return count; | ||
| 173 | } | ||
| 174 | |||
| 175 | static void bin_vma_open(struct vm_area_struct *vma) | ||
| 176 | { | ||
| 177 | struct file *file = vma->vm_file; | ||
| 178 | struct bin_buffer *bb = file->private_data; | ||
| 179 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | ||
| 180 | |||
| 181 | if (!bb->vm_ops) | ||
| 182 | return; | ||
| 183 | |||
| 184 | if (!sysfs_get_active(attr_sd)) | ||
| 185 | return; | ||
| 186 | |||
| 187 | if (bb->vm_ops->open) | ||
| 188 | bb->vm_ops->open(vma); | ||
| 189 | |||
| 190 | sysfs_put_active(attr_sd); | ||
| 191 | } | ||
| 192 | |||
| 193 | static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
| 194 | { | ||
| 195 | struct file *file = vma->vm_file; | ||
| 196 | struct bin_buffer *bb = file->private_data; | ||
| 197 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | ||
| 198 | int ret; | ||
| 199 | |||
| 200 | if (!bb->vm_ops) | ||
| 201 | return VM_FAULT_SIGBUS; | ||
| 202 | |||
| 203 | if (!sysfs_get_active(attr_sd)) | ||
| 204 | return VM_FAULT_SIGBUS; | ||
| 205 | |||
| 206 | ret = VM_FAULT_SIGBUS; | ||
| 207 | if (bb->vm_ops->fault) | ||
| 208 | ret = bb->vm_ops->fault(vma, vmf); | ||
| 209 | |||
| 210 | sysfs_put_active(attr_sd); | ||
| 211 | return ret; | ||
| 212 | } | ||
| 213 | |||
| 214 | static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
| 215 | { | ||
| 216 | struct file *file = vma->vm_file; | ||
| 217 | struct bin_buffer *bb = file->private_data; | ||
| 218 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | ||
| 219 | int ret; | ||
| 220 | |||
| 221 | if (!bb->vm_ops) | ||
| 222 | return VM_FAULT_SIGBUS; | ||
| 223 | |||
| 224 | if (!sysfs_get_active(attr_sd)) | ||
| 225 | return VM_FAULT_SIGBUS; | ||
| 226 | |||
| 227 | ret = 0; | ||
| 228 | if (bb->vm_ops->page_mkwrite) | ||
| 229 | ret = bb->vm_ops->page_mkwrite(vma, vmf); | ||
| 230 | else | ||
| 231 | file_update_time(file); | ||
| 232 | |||
| 233 | sysfs_put_active(attr_sd); | ||
| 234 | return ret; | ||
| 235 | } | ||
| 236 | |||
| 237 | static int bin_access(struct vm_area_struct *vma, unsigned long addr, | ||
| 238 | void *buf, int len, int write) | ||
| 239 | { | ||
| 240 | struct file *file = vma->vm_file; | ||
| 241 | struct bin_buffer *bb = file->private_data; | ||
| 242 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | ||
| 243 | int ret; | ||
| 244 | |||
| 245 | if (!bb->vm_ops) | ||
| 246 | return -EINVAL; | ||
| 247 | |||
| 248 | if (!sysfs_get_active(attr_sd)) | ||
| 249 | return -EINVAL; | ||
| 250 | |||
| 251 | ret = -EINVAL; | ||
| 252 | if (bb->vm_ops->access) | ||
| 253 | ret = bb->vm_ops->access(vma, addr, buf, len, write); | ||
| 254 | |||
| 255 | sysfs_put_active(attr_sd); | ||
| 256 | return ret; | ||
| 257 | } | ||
| 258 | |||
| 259 | #ifdef CONFIG_NUMA | ||
| 260 | static int bin_set_policy(struct vm_area_struct *vma, struct mempolicy *new) | ||
| 261 | { | ||
| 262 | struct file *file = vma->vm_file; | ||
| 263 | struct bin_buffer *bb = file->private_data; | ||
| 264 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | ||
| 265 | int ret; | ||
| 266 | |||
| 267 | if (!bb->vm_ops) | ||
| 268 | return 0; | ||
| 269 | |||
| 270 | if (!sysfs_get_active(attr_sd)) | ||
| 271 | return -EINVAL; | ||
| 272 | |||
| 273 | ret = 0; | ||
| 274 | if (bb->vm_ops->set_policy) | ||
| 275 | ret = bb->vm_ops->set_policy(vma, new); | ||
| 276 | |||
| 277 | sysfs_put_active(attr_sd); | ||
| 278 | return ret; | ||
| 279 | } | ||
| 280 | |||
| 281 | static struct mempolicy *bin_get_policy(struct vm_area_struct *vma, | ||
| 282 | unsigned long addr) | ||
| 283 | { | ||
| 284 | struct file *file = vma->vm_file; | ||
| 285 | struct bin_buffer *bb = file->private_data; | ||
| 286 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | ||
| 287 | struct mempolicy *pol; | ||
| 288 | |||
| 289 | if (!bb->vm_ops) | ||
| 290 | return vma->vm_policy; | ||
| 291 | |||
| 292 | if (!sysfs_get_active(attr_sd)) | ||
| 293 | return vma->vm_policy; | ||
| 294 | |||
| 295 | pol = vma->vm_policy; | ||
| 296 | if (bb->vm_ops->get_policy) | ||
| 297 | pol = bb->vm_ops->get_policy(vma, addr); | ||
| 298 | |||
| 299 | sysfs_put_active(attr_sd); | ||
| 300 | return pol; | ||
| 301 | } | ||
| 302 | |||
| 303 | static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from, | ||
| 304 | const nodemask_t *to, unsigned long flags) | ||
| 305 | { | ||
| 306 | struct file *file = vma->vm_file; | ||
| 307 | struct bin_buffer *bb = file->private_data; | ||
| 308 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | ||
| 309 | int ret; | ||
| 310 | |||
| 311 | if (!bb->vm_ops) | ||
| 312 | return 0; | ||
| 313 | |||
| 314 | if (!sysfs_get_active(attr_sd)) | ||
| 315 | return 0; | ||
| 316 | |||
| 317 | ret = 0; | ||
| 318 | if (bb->vm_ops->migrate) | ||
| 319 | ret = bb->vm_ops->migrate(vma, from, to, flags); | ||
| 320 | |||
| 321 | sysfs_put_active(attr_sd); | ||
| 322 | return ret; | ||
| 323 | } | ||
| 324 | #endif | ||
| 325 | |||
| 326 | static const struct vm_operations_struct bin_vm_ops = { | ||
| 327 | .open = bin_vma_open, | ||
| 328 | .fault = bin_fault, | ||
| 329 | .page_mkwrite = bin_page_mkwrite, | ||
| 330 | .access = bin_access, | ||
| 331 | #ifdef CONFIG_NUMA | ||
| 332 | .set_policy = bin_set_policy, | ||
| 333 | .get_policy = bin_get_policy, | ||
| 334 | .migrate = bin_migrate, | ||
| 335 | #endif | ||
| 336 | }; | ||
| 337 | |||
| 338 | static int mmap(struct file *file, struct vm_area_struct *vma) | ||
| 339 | { | ||
| 340 | struct bin_buffer *bb = file->private_data; | ||
| 341 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | ||
| 342 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; | ||
| 343 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | ||
| 344 | int rc; | ||
| 345 | |||
| 346 | mutex_lock(&bb->mutex); | ||
| 347 | |||
| 348 | /* need attr_sd for attr, its parent for kobj */ | ||
| 349 | rc = -ENODEV; | ||
| 350 | if (!sysfs_get_active(attr_sd)) | ||
| 351 | goto out_unlock; | ||
| 352 | |||
| 353 | rc = -EINVAL; | ||
| 354 | if (!attr->mmap) | ||
| 355 | goto out_put; | ||
| 356 | |||
| 357 | rc = attr->mmap(file, kobj, attr, vma); | ||
| 358 | if (rc) | ||
| 359 | goto out_put; | ||
| 360 | |||
| 361 | /* | ||
| 362 | * PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup() | ||
| 363 | * to satisfy versions of X which crash if the mmap fails: that | ||
| 364 | * substitutes a new vm_file, and we don't then want bin_vm_ops. | ||
| 365 | */ | ||
| 366 | if (vma->vm_file != file) | ||
| 367 | goto out_put; | ||
| 368 | |||
| 369 | rc = -EINVAL; | ||
| 370 | if (bb->mmapped && bb->vm_ops != vma->vm_ops) | ||
| 371 | goto out_put; | ||
| 372 | |||
| 373 | /* | ||
| 374 | * It is not possible to successfully wrap close. | ||
| 375 | * So error if someone is trying to use close. | ||
| 376 | */ | ||
| 377 | rc = -EINVAL; | ||
| 378 | if (vma->vm_ops && vma->vm_ops->close) | ||
| 379 | goto out_put; | ||
| 380 | |||
| 381 | rc = 0; | ||
| 382 | bb->mmapped = 1; | ||
| 383 | bb->vm_ops = vma->vm_ops; | ||
| 384 | vma->vm_ops = &bin_vm_ops; | ||
| 385 | out_put: | ||
| 386 | sysfs_put_active(attr_sd); | ||
| 387 | out_unlock: | ||
| 388 | mutex_unlock(&bb->mutex); | ||
| 389 | |||
| 390 | return rc; | ||
| 391 | } | ||
| 392 | |||
| 393 | static int open(struct inode *inode, struct file *file) | ||
| 394 | { | ||
| 395 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | ||
| 396 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; | ||
| 397 | struct bin_buffer *bb = NULL; | ||
| 398 | int error; | ||
| 399 | |||
| 400 | /* binary file operations requires both @sd and its parent */ | ||
| 401 | if (!sysfs_get_active(attr_sd)) | ||
| 402 | return -ENODEV; | ||
| 403 | |||
| 404 | error = -EACCES; | ||
| 405 | if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap)) | ||
| 406 | goto err_out; | ||
| 407 | if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap)) | ||
| 408 | goto err_out; | ||
| 409 | |||
| 410 | error = -ENOMEM; | ||
| 411 | bb = kzalloc(sizeof(*bb), GFP_KERNEL); | ||
| 412 | if (!bb) | ||
| 413 | goto err_out; | ||
| 414 | |||
| 415 | bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 416 | if (!bb->buffer) | ||
| 417 | goto err_out; | ||
| 418 | |||
| 419 | mutex_init(&bb->mutex); | ||
| 420 | bb->file = file; | ||
| 421 | file->private_data = bb; | ||
| 422 | |||
| 423 | mutex_lock(&sysfs_bin_lock); | ||
| 424 | hlist_add_head(&bb->list, &attr_sd->s_bin_attr.buffers); | ||
| 425 | mutex_unlock(&sysfs_bin_lock); | ||
| 426 | |||
| 427 | /* open succeeded, put active references */ | ||
| 428 | sysfs_put_active(attr_sd); | ||
| 429 | return 0; | ||
| 430 | |||
| 431 | err_out: | ||
| 432 | sysfs_put_active(attr_sd); | ||
| 433 | kfree(bb); | ||
| 434 | return error; | ||
| 435 | } | ||
| 436 | |||
| 437 | static int release(struct inode *inode, struct file *file) | ||
| 438 | { | ||
| 439 | struct bin_buffer *bb = file->private_data; | ||
| 440 | |||
| 441 | mutex_lock(&sysfs_bin_lock); | ||
| 442 | hlist_del(&bb->list); | ||
| 443 | mutex_unlock(&sysfs_bin_lock); | ||
| 444 | |||
| 445 | kfree(bb->buffer); | ||
| 446 | kfree(bb); | ||
| 447 | return 0; | ||
| 448 | } | ||
| 449 | |||
| 450 | const struct file_operations bin_fops = { | ||
| 451 | .read = read, | ||
| 452 | .write = write, | ||
| 453 | .mmap = mmap, | ||
| 454 | .llseek = generic_file_llseek, | ||
| 455 | .open = open, | ||
| 456 | .release = release, | ||
| 457 | }; | ||
| 458 | |||
| 459 | |||
| 460 | void unmap_bin_file(struct sysfs_dirent *attr_sd) | ||
| 461 | { | ||
| 462 | struct bin_buffer *bb; | ||
| 463 | |||
| 464 | if (sysfs_type(attr_sd) != SYSFS_KOBJ_BIN_ATTR) | ||
| 465 | return; | ||
| 466 | |||
| 467 | mutex_lock(&sysfs_bin_lock); | ||
| 468 | |||
| 469 | hlist_for_each_entry(bb, &attr_sd->s_bin_attr.buffers, list) { | ||
| 470 | struct inode *inode = file_inode(bb->file); | ||
| 471 | |||
| 472 | unmap_mapping_range(inode->i_mapping, 0, 0, 1); | ||
| 473 | } | ||
| 474 | |||
| 475 | mutex_unlock(&sysfs_bin_lock); | ||
| 476 | } | ||
| 477 | |||
| 478 | /** | ||
| 479 | * sysfs_create_bin_file - create binary file for object. | ||
| 480 | * @kobj: object. | ||
| 481 | * @attr: attribute descriptor. | ||
| 482 | */ | ||
| 483 | int sysfs_create_bin_file(struct kobject *kobj, | ||
| 484 | const struct bin_attribute *attr) | ||
| 485 | { | ||
| 486 | BUG_ON(!kobj || !kobj->sd || !attr); | ||
| 487 | |||
| 488 | return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR); | ||
| 489 | } | ||
| 490 | EXPORT_SYMBOL_GPL(sysfs_create_bin_file); | ||
| 491 | |||
| 492 | /** | ||
| 493 | * sysfs_remove_bin_file - remove binary file for object. | ||
| 494 | * @kobj: object. | ||
| 495 | * @attr: attribute descriptor. | ||
| 496 | */ | ||
| 497 | void sysfs_remove_bin_file(struct kobject *kobj, | ||
| 498 | const struct bin_attribute *attr) | ||
| 499 | { | ||
| 500 | sysfs_hash_and_remove(kobj->sd, NULL, attr->attr.name); | ||
| 501 | } | ||
| 502 | EXPORT_SYMBOL_GPL(sysfs_remove_bin_file); | ||
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 4d83cedb9fcb..08c66969d52a 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
| @@ -26,21 +26,21 @@ | |||
| 26 | #include "sysfs.h" | 26 | #include "sysfs.h" |
| 27 | 27 | ||
| 28 | DEFINE_MUTEX(sysfs_mutex); | 28 | DEFINE_MUTEX(sysfs_mutex); |
| 29 | DEFINE_SPINLOCK(sysfs_assoc_lock); | 29 | DEFINE_SPINLOCK(sysfs_symlink_target_lock); |
| 30 | 30 | ||
| 31 | #define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb); | 31 | #define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb) |
| 32 | 32 | ||
| 33 | static DEFINE_SPINLOCK(sysfs_ino_lock); | 33 | static DEFINE_SPINLOCK(sysfs_ino_lock); |
| 34 | static DEFINE_IDA(sysfs_ino_ida); | 34 | static DEFINE_IDA(sysfs_ino_ida); |
| 35 | 35 | ||
| 36 | /** | 36 | /** |
| 37 | * sysfs_name_hash | 37 | * sysfs_name_hash |
| 38 | * @ns: Namespace tag to hash | ||
| 39 | * @name: Null terminated string to hash | 38 | * @name: Null terminated string to hash |
| 39 | * @ns: Namespace tag to hash | ||
| 40 | * | 40 | * |
| 41 | * Returns 31 bit hash of ns + name (so it fits in an off_t ) | 41 | * Returns 31 bit hash of ns + name (so it fits in an off_t ) |
| 42 | */ | 42 | */ |
| 43 | static unsigned int sysfs_name_hash(const void *ns, const char *name) | 43 | static unsigned int sysfs_name_hash(const char *name, const void *ns) |
| 44 | { | 44 | { |
| 45 | unsigned long hash = init_name_hash(); | 45 | unsigned long hash = init_name_hash(); |
| 46 | unsigned int len = strlen(name); | 46 | unsigned int len = strlen(name); |
| @@ -56,8 +56,8 @@ static unsigned int sysfs_name_hash(const void *ns, const char *name) | |||
| 56 | return hash; | 56 | return hash; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static int sysfs_name_compare(unsigned int hash, const void *ns, | 59 | static int sysfs_name_compare(unsigned int hash, const char *name, |
| 60 | const char *name, const struct sysfs_dirent *sd) | 60 | const void *ns, const struct sysfs_dirent *sd) |
| 61 | { | 61 | { |
| 62 | if (hash != sd->s_hash) | 62 | if (hash != sd->s_hash) |
| 63 | return hash - sd->s_hash; | 63 | return hash - sd->s_hash; |
| @@ -69,7 +69,7 @@ static int sysfs_name_compare(unsigned int hash, const void *ns, | |||
| 69 | static int sysfs_sd_compare(const struct sysfs_dirent *left, | 69 | static int sysfs_sd_compare(const struct sysfs_dirent *left, |
| 70 | const struct sysfs_dirent *right) | 70 | const struct sysfs_dirent *right) |
| 71 | { | 71 | { |
| 72 | return sysfs_name_compare(left->s_hash, left->s_ns, left->s_name, | 72 | return sysfs_name_compare(left->s_hash, left->s_name, left->s_ns, |
| 73 | right); | 73 | right); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| @@ -111,6 +111,11 @@ static int sysfs_link_sibling(struct sysfs_dirent *sd) | |||
| 111 | /* add new node and rebalance the tree */ | 111 | /* add new node and rebalance the tree */ |
| 112 | rb_link_node(&sd->s_rb, parent, node); | 112 | rb_link_node(&sd->s_rb, parent, node); |
| 113 | rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children); | 113 | rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children); |
| 114 | |||
| 115 | /* if @sd has ns tag, mark the parent to enable ns filtering */ | ||
| 116 | if (sd->s_ns) | ||
| 117 | sd->s_parent->s_flags |= SYSFS_FLAG_HAS_NS; | ||
| 118 | |||
| 114 | return 0; | 119 | return 0; |
| 115 | } | 120 | } |
| 116 | 121 | ||
| @@ -130,26 +135,15 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | |||
| 130 | sd->s_parent->s_dir.subdirs--; | 135 | sd->s_parent->s_dir.subdirs--; |
| 131 | 136 | ||
| 132 | rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children); | 137 | rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children); |
| 133 | } | ||
| 134 | |||
| 135 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
| 136 | 138 | ||
| 137 | /* Test for attributes that want to ignore lockdep for read-locking */ | 139 | /* |
| 138 | static bool ignore_lockdep(struct sysfs_dirent *sd) | 140 | * Either all or none of the children have tags. Clearing HAS_NS |
| 139 | { | 141 | * when there's no child left is enough to keep the flag synced. |
| 140 | return sysfs_type(sd) == SYSFS_KOBJ_ATTR && | 142 | */ |
| 141 | sd->s_attr.attr->ignore_lockdep; | 143 | if (RB_EMPTY_ROOT(&sd->s_parent->s_dir.children)) |
| 142 | } | 144 | sd->s_parent->s_flags &= ~SYSFS_FLAG_HAS_NS; |
| 143 | |||
| 144 | #else | ||
| 145 | |||
| 146 | static inline bool ignore_lockdep(struct sysfs_dirent *sd) | ||
| 147 | { | ||
| 148 | return true; | ||
| 149 | } | 145 | } |
| 150 | 146 | ||
| 151 | #endif | ||
| 152 | |||
| 153 | /** | 147 | /** |
| 154 | * sysfs_get_active - get an active reference to sysfs_dirent | 148 | * sysfs_get_active - get an active reference to sysfs_dirent |
| 155 | * @sd: sysfs_dirent to get an active reference to | 149 | * @sd: sysfs_dirent to get an active reference to |
| @@ -168,7 +162,7 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | |||
| 168 | if (!atomic_inc_unless_negative(&sd->s_active)) | 162 | if (!atomic_inc_unless_negative(&sd->s_active)) |
| 169 | return NULL; | 163 | return NULL; |
| 170 | 164 | ||
| 171 | if (likely(!ignore_lockdep(sd))) | 165 | if (likely(!sysfs_ignore_lockdep(sd))) |
| 172 | rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_); | 166 | rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_); |
| 173 | return sd; | 167 | return sd; |
| 174 | } | 168 | } |
| @@ -187,7 +181,7 @@ void sysfs_put_active(struct sysfs_dirent *sd) | |||
| 187 | if (unlikely(!sd)) | 181 | if (unlikely(!sd)) |
| 188 | return; | 182 | return; |
| 189 | 183 | ||
| 190 | if (likely(!ignore_lockdep(sd))) | 184 | if (likely(!sysfs_ignore_lockdep(sd))) |
| 191 | rwsem_release(&sd->dep_map, 1, _RET_IP_); | 185 | rwsem_release(&sd->dep_map, 1, _RET_IP_); |
| 192 | v = atomic_dec_return(&sd->s_active); | 186 | v = atomic_dec_return(&sd->s_active); |
| 193 | if (likely(v != SD_DEACTIVATED_BIAS)) | 187 | if (likely(v != SD_DEACTIVATED_BIAS)) |
| @@ -297,7 +291,6 @@ static int sysfs_dentry_delete(const struct dentry *dentry) | |||
| 297 | static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) | 291 | static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) |
| 298 | { | 292 | { |
| 299 | struct sysfs_dirent *sd; | 293 | struct sysfs_dirent *sd; |
| 300 | int type; | ||
| 301 | 294 | ||
| 302 | if (flags & LOOKUP_RCU) | 295 | if (flags & LOOKUP_RCU) |
| 303 | return -ECHILD; | 296 | return -ECHILD; |
| @@ -318,13 +311,8 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) | |||
| 318 | goto out_bad; | 311 | goto out_bad; |
| 319 | 312 | ||
| 320 | /* The sysfs dirent has been moved to a different namespace */ | 313 | /* The sysfs dirent has been moved to a different namespace */ |
| 321 | type = KOBJ_NS_TYPE_NONE; | 314 | if (sd->s_ns && sd->s_ns != sysfs_info(dentry->d_sb)->ns) |
| 322 | if (sd->s_parent) { | 315 | goto out_bad; |
| 323 | type = sysfs_ns_type(sd->s_parent); | ||
| 324 | if (type != KOBJ_NS_TYPE_NONE && | ||
| 325 | sysfs_info(dentry->d_sb)->ns[type] != sd->s_ns) | ||
| 326 | goto out_bad; | ||
| 327 | } | ||
| 328 | 316 | ||
| 329 | mutex_unlock(&sysfs_mutex); | 317 | mutex_unlock(&sysfs_mutex); |
| 330 | out_valid: | 318 | out_valid: |
| @@ -400,22 +388,19 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | |||
| 400 | /** | 388 | /** |
| 401 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove | 389 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove |
| 402 | * @acxt: pointer to sysfs_addrm_cxt to be used | 390 | * @acxt: pointer to sysfs_addrm_cxt to be used |
| 403 | * @parent_sd: parent sysfs_dirent | ||
| 404 | * | 391 | * |
| 405 | * This function is called when the caller is about to add or | 392 | * This function is called when the caller is about to add or remove |
| 406 | * remove sysfs_dirent under @parent_sd. This function acquires | 393 | * sysfs_dirent. This function acquires sysfs_mutex. @acxt is used |
| 407 | * sysfs_mutex. @acxt is used to keep and pass context to | 394 | * to keep and pass context to other addrm functions. |
| 408 | * other addrm functions. | ||
| 409 | * | 395 | * |
| 410 | * LOCKING: | 396 | * LOCKING: |
| 411 | * Kernel thread context (may sleep). sysfs_mutex is locked on | 397 | * Kernel thread context (may sleep). sysfs_mutex is locked on |
| 412 | * return. | 398 | * return. |
| 413 | */ | 399 | */ |
| 414 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | 400 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt) |
| 415 | struct sysfs_dirent *parent_sd) | 401 | __acquires(sysfs_mutex) |
| 416 | { | 402 | { |
| 417 | memset(acxt, 0, sizeof(*acxt)); | 403 | memset(acxt, 0, sizeof(*acxt)); |
| 418 | acxt->parent_sd = parent_sd; | ||
| 419 | 404 | ||
| 420 | mutex_lock(&sysfs_mutex); | 405 | mutex_lock(&sysfs_mutex); |
| 421 | } | 406 | } |
| @@ -424,10 +409,11 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
| 424 | * __sysfs_add_one - add sysfs_dirent to parent without warning | 409 | * __sysfs_add_one - add sysfs_dirent to parent without warning |
| 425 | * @acxt: addrm context to use | 410 | * @acxt: addrm context to use |
| 426 | * @sd: sysfs_dirent to be added | 411 | * @sd: sysfs_dirent to be added |
| 412 | * @parent_sd: the parent sysfs_dirent to add @sd to | ||
| 427 | * | 413 | * |
| 428 | * Get @acxt->parent_sd and set sd->s_parent to it and increment | 414 | * Get @parent_sd and set @sd->s_parent to it and increment nlink of |
| 429 | * nlink of parent inode if @sd is a directory and link into the | 415 | * the parent inode if @sd is a directory and link into the children |
| 430 | * children list of the parent. | 416 | * list of the parent. |
| 431 | * | 417 | * |
| 432 | * This function should be called between calls to | 418 | * This function should be called between calls to |
| 433 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | 419 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be |
| @@ -440,27 +426,21 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
| 440 | * 0 on success, -EEXIST if entry with the given name already | 426 | * 0 on success, -EEXIST if entry with the given name already |
| 441 | * exists. | 427 | * exists. |
| 442 | */ | 428 | */ |
| 443 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 429 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, |
| 430 | struct sysfs_dirent *parent_sd) | ||
| 444 | { | 431 | { |
| 445 | struct sysfs_inode_attrs *ps_iattr; | 432 | struct sysfs_inode_attrs *ps_iattr; |
| 446 | int ret; | 433 | int ret; |
| 447 | 434 | ||
| 448 | if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) { | 435 | sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); |
| 449 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", | 436 | sd->s_parent = sysfs_get(parent_sd); |
| 450 | sysfs_ns_type(acxt->parent_sd) ? "required" : "invalid", | ||
| 451 | acxt->parent_sd->s_name, sd->s_name); | ||
| 452 | return -EINVAL; | ||
| 453 | } | ||
| 454 | |||
| 455 | sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); | ||
| 456 | sd->s_parent = sysfs_get(acxt->parent_sd); | ||
| 457 | 437 | ||
| 458 | ret = sysfs_link_sibling(sd); | 438 | ret = sysfs_link_sibling(sd); |
| 459 | if (ret) | 439 | if (ret) |
| 460 | return ret; | 440 | return ret; |
| 461 | 441 | ||
| 462 | /* Update timestamps on the parent */ | 442 | /* Update timestamps on the parent */ |
| 463 | ps_iattr = acxt->parent_sd->s_iattr; | 443 | ps_iattr = parent_sd->s_iattr; |
| 464 | if (ps_iattr) { | 444 | if (ps_iattr) { |
| 465 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | 445 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; |
| 466 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | 446 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; |
| @@ -490,14 +470,32 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path) | |||
| 490 | return path; | 470 | return path; |
| 491 | } | 471 | } |
| 492 | 472 | ||
| 473 | void sysfs_warn_dup(struct sysfs_dirent *parent, const char *name) | ||
| 474 | { | ||
| 475 | char *path; | ||
| 476 | |||
| 477 | path = kzalloc(PATH_MAX, GFP_KERNEL); | ||
| 478 | if (path) { | ||
| 479 | sysfs_pathname(parent, path); | ||
| 480 | strlcat(path, "/", PATH_MAX); | ||
| 481 | strlcat(path, name, PATH_MAX); | ||
| 482 | } | ||
| 483 | |||
| 484 | WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n", | ||
| 485 | path ? path : name); | ||
| 486 | |||
| 487 | kfree(path); | ||
| 488 | } | ||
| 489 | |||
| 493 | /** | 490 | /** |
| 494 | * sysfs_add_one - add sysfs_dirent to parent | 491 | * sysfs_add_one - add sysfs_dirent to parent |
| 495 | * @acxt: addrm context to use | 492 | * @acxt: addrm context to use |
| 496 | * @sd: sysfs_dirent to be added | 493 | * @sd: sysfs_dirent to be added |
| 494 | * @parent_sd: the parent sysfs_dirent to add @sd to | ||
| 497 | * | 495 | * |
| 498 | * Get @acxt->parent_sd and set sd->s_parent to it and increment | 496 | * Get @parent_sd and set @sd->s_parent to it and increment nlink of |
| 499 | * nlink of parent inode if @sd is a directory and link into the | 497 | * the parent inode if @sd is a directory and link into the children |
| 500 | * children list of the parent. | 498 | * list of the parent. |
| 501 | * | 499 | * |
| 502 | * This function should be called between calls to | 500 | * This function should be called between calls to |
| 503 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | 501 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be |
| @@ -510,23 +508,15 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path) | |||
| 510 | * 0 on success, -EEXIST if entry with the given name already | 508 | * 0 on success, -EEXIST if entry with the given name already |
| 511 | * exists. | 509 | * exists. |
| 512 | */ | 510 | */ |
| 513 | int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 511 | int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, |
| 512 | struct sysfs_dirent *parent_sd) | ||
| 514 | { | 513 | { |
| 515 | int ret; | 514 | int ret; |
| 516 | 515 | ||
| 517 | ret = __sysfs_add_one(acxt, sd); | 516 | ret = __sysfs_add_one(acxt, sd, parent_sd); |
| 518 | if (ret == -EEXIST) { | ||
| 519 | char *path = kzalloc(PATH_MAX, GFP_KERNEL); | ||
| 520 | WARN(1, KERN_WARNING | ||
| 521 | "sysfs: cannot create duplicate filename '%s'\n", | ||
| 522 | (path == NULL) ? sd->s_name | ||
| 523 | : (sysfs_pathname(acxt->parent_sd, path), | ||
| 524 | strlcat(path, "/", PATH_MAX), | ||
| 525 | strlcat(path, sd->s_name, PATH_MAX), | ||
| 526 | path)); | ||
| 527 | kfree(path); | ||
| 528 | } | ||
| 529 | 517 | ||
| 518 | if (ret == -EEXIST) | ||
| 519 | sysfs_warn_dup(parent_sd, sd->s_name); | ||
| 530 | return ret; | 520 | return ret; |
| 531 | } | 521 | } |
| 532 | 522 | ||
| @@ -545,16 +535,22 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
| 545 | * LOCKING: | 535 | * LOCKING: |
| 546 | * Determined by sysfs_addrm_start(). | 536 | * Determined by sysfs_addrm_start(). |
| 547 | */ | 537 | */ |
| 548 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 538 | static void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, |
| 539 | struct sysfs_dirent *sd) | ||
| 549 | { | 540 | { |
| 550 | struct sysfs_inode_attrs *ps_iattr; | 541 | struct sysfs_inode_attrs *ps_iattr; |
| 551 | 542 | ||
| 552 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); | 543 | /* |
| 544 | * Removal can be called multiple times on the same node. Only the | ||
| 545 | * first invocation is effective and puts the base ref. | ||
| 546 | */ | ||
| 547 | if (sd->s_flags & SYSFS_FLAG_REMOVED) | ||
| 548 | return; | ||
| 553 | 549 | ||
| 554 | sysfs_unlink_sibling(sd); | 550 | sysfs_unlink_sibling(sd); |
| 555 | 551 | ||
| 556 | /* Update timestamps on the parent */ | 552 | /* Update timestamps on the parent */ |
| 557 | ps_iattr = acxt->parent_sd->s_iattr; | 553 | ps_iattr = sd->s_parent->s_iattr; |
| 558 | if (ps_iattr) { | 554 | if (ps_iattr) { |
| 559 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | 555 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; |
| 560 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | 556 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; |
| @@ -577,6 +573,7 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
| 577 | * sysfs_mutex is released. | 573 | * sysfs_mutex is released. |
| 578 | */ | 574 | */ |
| 579 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | 575 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) |
| 576 | __releases(sysfs_mutex) | ||
| 580 | { | 577 | { |
| 581 | /* release resources acquired by sysfs_addrm_start() */ | 578 | /* release resources acquired by sysfs_addrm_start() */ |
| 582 | mutex_unlock(&sysfs_mutex); | 579 | mutex_unlock(&sysfs_mutex); |
| @@ -588,7 +585,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
| 588 | acxt->removed = sd->u.removed_list; | 585 | acxt->removed = sd->u.removed_list; |
| 589 | 586 | ||
| 590 | sysfs_deactivate(sd); | 587 | sysfs_deactivate(sd); |
| 591 | unmap_bin_file(sd); | 588 | sysfs_unmap_bin_file(sd); |
| 592 | sysfs_put(sd); | 589 | sysfs_put(sd); |
| 593 | } | 590 | } |
| 594 | } | 591 | } |
| @@ -597,6 +594,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
| 597 | * sysfs_find_dirent - find sysfs_dirent with the given name | 594 | * sysfs_find_dirent - find sysfs_dirent with the given name |
| 598 | * @parent_sd: sysfs_dirent to search under | 595 | * @parent_sd: sysfs_dirent to search under |
| 599 | * @name: name to look for | 596 | * @name: name to look for |
| 597 | * @ns: the namespace tag to use | ||
| 600 | * | 598 | * |
| 601 | * Look for sysfs_dirent with name @name under @parent_sd. | 599 | * Look for sysfs_dirent with name @name under @parent_sd. |
| 602 | * | 600 | * |
| @@ -607,26 +605,19 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
| 607 | * Pointer to sysfs_dirent if found, NULL if not. | 605 | * Pointer to sysfs_dirent if found, NULL if not. |
| 608 | */ | 606 | */ |
| 609 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | 607 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, |
| 610 | const void *ns, | 608 | const unsigned char *name, |
| 611 | const unsigned char *name) | 609 | const void *ns) |
| 612 | { | 610 | { |
| 613 | struct rb_node *node = parent_sd->s_dir.children.rb_node; | 611 | struct rb_node *node = parent_sd->s_dir.children.rb_node; |
| 614 | unsigned int hash; | 612 | unsigned int hash; |
| 615 | 613 | ||
| 616 | if (!!sysfs_ns_type(parent_sd) != !!ns) { | 614 | hash = sysfs_name_hash(name, ns); |
| 617 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", | ||
| 618 | sysfs_ns_type(parent_sd) ? "required" : "invalid", | ||
| 619 | parent_sd->s_name, name); | ||
| 620 | return NULL; | ||
| 621 | } | ||
| 622 | |||
| 623 | hash = sysfs_name_hash(ns, name); | ||
| 624 | while (node) { | 615 | while (node) { |
| 625 | struct sysfs_dirent *sd; | 616 | struct sysfs_dirent *sd; |
| 626 | int result; | 617 | int result; |
| 627 | 618 | ||
| 628 | sd = to_sysfs_dirent(node); | 619 | sd = to_sysfs_dirent(node); |
| 629 | result = sysfs_name_compare(hash, ns, name, sd); | 620 | result = sysfs_name_compare(hash, name, ns, sd); |
| 630 | if (result < 0) | 621 | if (result < 0) |
| 631 | node = node->rb_left; | 622 | node = node->rb_left; |
| 632 | else if (result > 0) | 623 | else if (result > 0) |
| @@ -638,9 +629,10 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
| 638 | } | 629 | } |
| 639 | 630 | ||
| 640 | /** | 631 | /** |
| 641 | * sysfs_get_dirent - find and get sysfs_dirent with the given name | 632 | * sysfs_get_dirent_ns - find and get sysfs_dirent with the given name |
| 642 | * @parent_sd: sysfs_dirent to search under | 633 | * @parent_sd: sysfs_dirent to search under |
| 643 | * @name: name to look for | 634 | * @name: name to look for |
| 635 | * @ns: the namespace tag to use | ||
| 644 | * | 636 | * |
| 645 | * Look for sysfs_dirent with name @name under @parent_sd and get | 637 | * Look for sysfs_dirent with name @name under @parent_sd and get |
| 646 | * it if found. | 638 | * it if found. |
| @@ -651,24 +643,24 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
| 651 | * RETURNS: | 643 | * RETURNS: |
| 652 | * Pointer to sysfs_dirent if found, NULL if not. | 644 | * Pointer to sysfs_dirent if found, NULL if not. |
| 653 | */ | 645 | */ |
| 654 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | 646 | struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, |
| 655 | const void *ns, | 647 | const unsigned char *name, |
| 656 | const unsigned char *name) | 648 | const void *ns) |
| 657 | { | 649 | { |
| 658 | struct sysfs_dirent *sd; | 650 | struct sysfs_dirent *sd; |
| 659 | 651 | ||
| 660 | mutex_lock(&sysfs_mutex); | 652 | mutex_lock(&sysfs_mutex); |
| 661 | sd = sysfs_find_dirent(parent_sd, ns, name); | 653 | sd = sysfs_find_dirent(parent_sd, name, ns); |
| 662 | sysfs_get(sd); | 654 | sysfs_get(sd); |
| 663 | mutex_unlock(&sysfs_mutex); | 655 | mutex_unlock(&sysfs_mutex); |
| 664 | 656 | ||
| 665 | return sd; | 657 | return sd; |
| 666 | } | 658 | } |
| 667 | EXPORT_SYMBOL_GPL(sysfs_get_dirent); | 659 | EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns); |
| 668 | 660 | ||
| 669 | static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | 661 | static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, |
| 670 | enum kobj_ns_type type, const void *ns, const char *name, | 662 | const char *name, const void *ns, |
| 671 | struct sysfs_dirent **p_sd) | 663 | struct sysfs_dirent **p_sd) |
| 672 | { | 664 | { |
| 673 | umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; | 665 | umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; |
| 674 | struct sysfs_addrm_cxt acxt; | 666 | struct sysfs_addrm_cxt acxt; |
| @@ -680,13 +672,12 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
| 680 | if (!sd) | 672 | if (!sd) |
| 681 | return -ENOMEM; | 673 | return -ENOMEM; |
| 682 | 674 | ||
| 683 | sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT); | ||
| 684 | sd->s_ns = ns; | 675 | sd->s_ns = ns; |
| 685 | sd->s_dir.kobj = kobj; | 676 | sd->s_dir.kobj = kobj; |
| 686 | 677 | ||
| 687 | /* link in */ | 678 | /* link in */ |
| 688 | sysfs_addrm_start(&acxt, parent_sd); | 679 | sysfs_addrm_start(&acxt); |
| 689 | rc = sysfs_add_one(&acxt, sd); | 680 | rc = sysfs_add_one(&acxt, sd, parent_sd); |
| 690 | sysfs_addrm_finish(&acxt); | 681 | sysfs_addrm_finish(&acxt); |
| 691 | 682 | ||
| 692 | if (rc == 0) | 683 | if (rc == 0) |
| @@ -700,44 +691,17 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
| 700 | int sysfs_create_subdir(struct kobject *kobj, const char *name, | 691 | int sysfs_create_subdir(struct kobject *kobj, const char *name, |
| 701 | struct sysfs_dirent **p_sd) | 692 | struct sysfs_dirent **p_sd) |
| 702 | { | 693 | { |
| 703 | return create_dir(kobj, kobj->sd, | 694 | return create_dir(kobj, kobj->sd, name, NULL, p_sd); |
| 704 | KOBJ_NS_TYPE_NONE, NULL, name, p_sd); | ||
| 705 | } | 695 | } |
| 706 | 696 | ||
| 707 | /** | 697 | /** |
| 708 | * sysfs_read_ns_type: return associated ns_type | 698 | * sysfs_create_dir_ns - create a directory for an object with a namespace tag |
| 709 | * @kobj: the kobject being queried | 699 | * @kobj: object we're creating directory for |
| 710 | * | 700 | * @ns: the namespace tag to use |
| 711 | * Each kobject can be tagged with exactly one namespace type | ||
| 712 | * (i.e. network or user). Return the ns_type associated with | ||
| 713 | * this object if any | ||
| 714 | */ | 701 | */ |
| 715 | static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj) | 702 | int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) |
| 716 | { | 703 | { |
| 717 | const struct kobj_ns_type_operations *ops; | ||
| 718 | enum kobj_ns_type type; | ||
| 719 | |||
| 720 | ops = kobj_child_ns_ops(kobj); | ||
| 721 | if (!ops) | ||
| 722 | return KOBJ_NS_TYPE_NONE; | ||
| 723 | |||
| 724 | type = ops->type; | ||
| 725 | BUG_ON(type <= KOBJ_NS_TYPE_NONE); | ||
| 726 | BUG_ON(type >= KOBJ_NS_TYPES); | ||
| 727 | BUG_ON(!kobj_ns_type_registered(type)); | ||
| 728 | |||
| 729 | return type; | ||
| 730 | } | ||
| 731 | |||
| 732 | /** | ||
| 733 | * sysfs_create_dir - create a directory for an object. | ||
| 734 | * @kobj: object we're creating directory for. | ||
| 735 | */ | ||
| 736 | int sysfs_create_dir(struct kobject *kobj) | ||
| 737 | { | ||
| 738 | enum kobj_ns_type type; | ||
| 739 | struct sysfs_dirent *parent_sd, *sd; | 704 | struct sysfs_dirent *parent_sd, *sd; |
| 740 | const void *ns = NULL; | ||
| 741 | int error = 0; | 705 | int error = 0; |
| 742 | 706 | ||
| 743 | BUG_ON(!kobj); | 707 | BUG_ON(!kobj); |
| @@ -750,11 +714,7 @@ int sysfs_create_dir(struct kobject *kobj) | |||
| 750 | if (!parent_sd) | 714 | if (!parent_sd) |
| 751 | return -ENOENT; | 715 | return -ENOENT; |
| 752 | 716 | ||
| 753 | if (sysfs_ns_type(parent_sd)) | 717 | error = create_dir(kobj, parent_sd, kobject_name(kobj), ns, &sd); |
| 754 | ns = kobj->ktype->namespace(kobj); | ||
| 755 | type = sysfs_read_ns_type(kobj); | ||
| 756 | |||
| 757 | error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd); | ||
| 758 | if (!error) | 718 | if (!error) |
| 759 | kobj->sd = sd; | 719 | kobj->sd = sd; |
| 760 | return error; | 720 | return error; |
| @@ -768,15 +728,14 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 768 | struct sysfs_dirent *parent_sd = parent->d_fsdata; | 728 | struct sysfs_dirent *parent_sd = parent->d_fsdata; |
| 769 | struct sysfs_dirent *sd; | 729 | struct sysfs_dirent *sd; |
| 770 | struct inode *inode; | 730 | struct inode *inode; |
| 771 | enum kobj_ns_type type; | 731 | const void *ns = NULL; |
| 772 | const void *ns; | ||
| 773 | 732 | ||
| 774 | mutex_lock(&sysfs_mutex); | 733 | mutex_lock(&sysfs_mutex); |
| 775 | 734 | ||
| 776 | type = sysfs_ns_type(parent_sd); | 735 | if (parent_sd->s_flags & SYSFS_FLAG_HAS_NS) |
| 777 | ns = sysfs_info(dir->i_sb)->ns[type]; | 736 | ns = sysfs_info(dir->i_sb)->ns; |
| 778 | 737 | ||
| 779 | sd = sysfs_find_dirent(parent_sd, ns, dentry->d_name.name); | 738 | sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns); |
| 780 | 739 | ||
| 781 | /* no such entry */ | 740 | /* no such entry */ |
| 782 | if (!sd) { | 741 | if (!sd) { |
| @@ -807,41 +766,128 @@ const struct inode_operations sysfs_dir_inode_operations = { | |||
| 807 | .setxattr = sysfs_setxattr, | 766 | .setxattr = sysfs_setxattr, |
| 808 | }; | 767 | }; |
| 809 | 768 | ||
| 810 | static void remove_dir(struct sysfs_dirent *sd) | 769 | static struct sysfs_dirent *sysfs_leftmost_descendant(struct sysfs_dirent *pos) |
| 811 | { | 770 | { |
| 812 | struct sysfs_addrm_cxt acxt; | 771 | struct sysfs_dirent *last; |
| 813 | 772 | ||
| 814 | sysfs_addrm_start(&acxt, sd->s_parent); | 773 | while (true) { |
| 815 | sysfs_remove_one(&acxt, sd); | 774 | struct rb_node *rbn; |
| 816 | sysfs_addrm_finish(&acxt); | 775 | |
| 776 | last = pos; | ||
| 777 | |||
| 778 | if (sysfs_type(pos) != SYSFS_DIR) | ||
| 779 | break; | ||
| 780 | |||
| 781 | rbn = rb_first(&pos->s_dir.children); | ||
| 782 | if (!rbn) | ||
| 783 | break; | ||
| 784 | |||
| 785 | pos = to_sysfs_dirent(rbn); | ||
| 786 | } | ||
| 787 | |||
| 788 | return last; | ||
| 817 | } | 789 | } |
| 818 | 790 | ||
| 819 | void sysfs_remove_subdir(struct sysfs_dirent *sd) | 791 | /** |
| 792 | * sysfs_next_descendant_post - find the next descendant for post-order walk | ||
| 793 | * @pos: the current position (%NULL to initiate traversal) | ||
| 794 | * @root: sysfs_dirent whose descendants to walk | ||
| 795 | * | ||
| 796 | * Find the next descendant to visit for post-order traversal of @root's | ||
| 797 | * descendants. @root is included in the iteration and the last node to be | ||
| 798 | * visited. | ||
| 799 | */ | ||
| 800 | static struct sysfs_dirent *sysfs_next_descendant_post(struct sysfs_dirent *pos, | ||
| 801 | struct sysfs_dirent *root) | ||
| 820 | { | 802 | { |
| 821 | remove_dir(sd); | 803 | struct rb_node *rbn; |
| 804 | |||
| 805 | lockdep_assert_held(&sysfs_mutex); | ||
| 806 | |||
| 807 | /* if first iteration, visit leftmost descendant which may be root */ | ||
| 808 | if (!pos) | ||
| 809 | return sysfs_leftmost_descendant(root); | ||
| 810 | |||
| 811 | /* if we visited @root, we're done */ | ||
| 812 | if (pos == root) | ||
| 813 | return NULL; | ||
| 814 | |||
| 815 | /* if there's an unvisited sibling, visit its leftmost descendant */ | ||
| 816 | rbn = rb_next(&pos->s_rb); | ||
| 817 | if (rbn) | ||
| 818 | return sysfs_leftmost_descendant(to_sysfs_dirent(rbn)); | ||
| 819 | |||
| 820 | /* no sibling left, visit parent */ | ||
| 821 | return pos->s_parent; | ||
| 822 | } | 822 | } |
| 823 | 823 | ||
| 824 | static void __sysfs_remove(struct sysfs_addrm_cxt *acxt, | ||
| 825 | struct sysfs_dirent *sd) | ||
| 826 | { | ||
| 827 | struct sysfs_dirent *pos, *next; | ||
| 828 | |||
| 829 | if (!sd) | ||
| 830 | return; | ||
| 831 | |||
| 832 | pr_debug("sysfs %s: removing\n", sd->s_name); | ||
| 833 | |||
| 834 | next = NULL; | ||
| 835 | do { | ||
| 836 | pos = next; | ||
| 837 | next = sysfs_next_descendant_post(pos, sd); | ||
| 838 | if (pos) | ||
| 839 | sysfs_remove_one(acxt, pos); | ||
| 840 | } while (next); | ||
| 841 | } | ||
| 824 | 842 | ||
| 825 | static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) | 843 | /** |
| 844 | * sysfs_remove - remove a sysfs_dirent recursively | ||
| 845 | * @sd: the sysfs_dirent to remove | ||
| 846 | * | ||
| 847 | * Remove @sd along with all its subdirectories and files. | ||
| 848 | */ | ||
| 849 | void sysfs_remove(struct sysfs_dirent *sd) | ||
| 826 | { | 850 | { |
| 827 | struct sysfs_addrm_cxt acxt; | 851 | struct sysfs_addrm_cxt acxt; |
| 828 | struct rb_node *pos; | ||
| 829 | 852 | ||
| 830 | if (!dir_sd) | 853 | sysfs_addrm_start(&acxt); |
| 831 | return; | 854 | __sysfs_remove(&acxt, sd); |
| 855 | sysfs_addrm_finish(&acxt); | ||
| 856 | } | ||
| 832 | 857 | ||
| 833 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); | 858 | /** |
| 834 | sysfs_addrm_start(&acxt, dir_sd); | 859 | * sysfs_hash_and_remove - find a sysfs_dirent by name and remove it |
| 835 | pos = rb_first(&dir_sd->s_dir.children); | 860 | * @dir_sd: parent of the target |
| 836 | while (pos) { | 861 | * @name: name of the sysfs_dirent to remove |
| 837 | struct sysfs_dirent *sd = to_sysfs_dirent(pos); | 862 | * @ns: namespace tag of the sysfs_dirent to remove |
| 838 | pos = rb_next(pos); | 863 | * |
| 839 | if (sysfs_type(sd) != SYSFS_DIR) | 864 | * Look for the sysfs_dirent with @name and @ns under @dir_sd and remove |
| 840 | sysfs_remove_one(&acxt, sd); | 865 | * it. Returns 0 on success, -ENOENT if such entry doesn't exist. |
| 866 | */ | ||
| 867 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name, | ||
| 868 | const void *ns) | ||
| 869 | { | ||
| 870 | struct sysfs_addrm_cxt acxt; | ||
| 871 | struct sysfs_dirent *sd; | ||
| 872 | |||
| 873 | if (!dir_sd) { | ||
| 874 | WARN(1, KERN_WARNING "sysfs: can not remove '%s', no directory\n", | ||
| 875 | name); | ||
| 876 | return -ENOENT; | ||
| 841 | } | 877 | } |
| 878 | |||
| 879 | sysfs_addrm_start(&acxt); | ||
| 880 | |||
| 881 | sd = sysfs_find_dirent(dir_sd, name, ns); | ||
| 882 | if (sd) | ||
| 883 | __sysfs_remove(&acxt, sd); | ||
| 884 | |||
| 842 | sysfs_addrm_finish(&acxt); | 885 | sysfs_addrm_finish(&acxt); |
| 843 | 886 | ||
| 844 | remove_dir(dir_sd); | 887 | if (sd) |
| 888 | return 0; | ||
| 889 | else | ||
| 890 | return -ENOENT; | ||
| 845 | } | 891 | } |
| 846 | 892 | ||
| 847 | /** | 893 | /** |
| @@ -852,21 +898,34 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) | |||
| 852 | * the directory before we remove the directory, and we've inlined | 898 | * the directory before we remove the directory, and we've inlined |
| 853 | * what used to be sysfs_rmdir() below, instead of calling separately. | 899 | * what used to be sysfs_rmdir() below, instead of calling separately. |
| 854 | */ | 900 | */ |
| 855 | |||
| 856 | void sysfs_remove_dir(struct kobject *kobj) | 901 | void sysfs_remove_dir(struct kobject *kobj) |
| 857 | { | 902 | { |
| 858 | struct sysfs_dirent *sd = kobj->sd; | 903 | struct sysfs_dirent *sd = kobj->sd; |
| 859 | 904 | ||
| 860 | spin_lock(&sysfs_assoc_lock); | 905 | /* |
| 906 | * In general, kboject owner is responsible for ensuring removal | ||
| 907 | * doesn't race with other operations and sysfs doesn't provide any | ||
| 908 | * protection; however, when @kobj is used as a symlink target, the | ||
| 909 | * symlinking entity usually doesn't own @kobj and thus has no | ||
| 910 | * control over removal. @kobj->sd may be removed anytime and | ||
| 911 | * symlink code may end up dereferencing an already freed sd. | ||
| 912 | * | ||
| 913 | * sysfs_symlink_target_lock synchronizes @kobj->sd disassociation | ||
| 914 | * against symlink operations so that symlink code can safely | ||
| 915 | * dereference @kobj->sd. | ||
| 916 | */ | ||
| 917 | spin_lock(&sysfs_symlink_target_lock); | ||
| 861 | kobj->sd = NULL; | 918 | kobj->sd = NULL; |
| 862 | spin_unlock(&sysfs_assoc_lock); | 919 | spin_unlock(&sysfs_symlink_target_lock); |
| 863 | 920 | ||
| 864 | __sysfs_remove_dir(sd); | 921 | if (sd) { |
| 922 | WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); | ||
| 923 | sysfs_remove(sd); | ||
| 924 | } | ||
| 865 | } | 925 | } |
| 866 | 926 | ||
| 867 | int sysfs_rename(struct sysfs_dirent *sd, | 927 | int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd, |
| 868 | struct sysfs_dirent *new_parent_sd, const void *new_ns, | 928 | const char *new_name, const void *new_ns) |
| 869 | const char *new_name) | ||
| 870 | { | 929 | { |
| 871 | int error; | 930 | int error; |
| 872 | 931 | ||
| @@ -878,7 +937,7 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
| 878 | goto out; /* nothing to rename */ | 937 | goto out; /* nothing to rename */ |
| 879 | 938 | ||
| 880 | error = -EEXIST; | 939 | error = -EEXIST; |
| 881 | if (sysfs_find_dirent(new_parent_sd, new_ns, new_name)) | 940 | if (sysfs_find_dirent(new_parent_sd, new_name, new_ns)) |
| 882 | goto out; | 941 | goto out; |
| 883 | 942 | ||
| 884 | /* rename sysfs_dirent */ | 943 | /* rename sysfs_dirent */ |
| @@ -899,7 +958,7 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
| 899 | sysfs_get(new_parent_sd); | 958 | sysfs_get(new_parent_sd); |
| 900 | sysfs_put(sd->s_parent); | 959 | sysfs_put(sd->s_parent); |
| 901 | sd->s_ns = new_ns; | 960 | sd->s_ns = new_ns; |
| 902 | sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); | 961 | sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); |
| 903 | sd->s_parent = new_parent_sd; | 962 | sd->s_parent = new_parent_sd; |
| 904 | sysfs_link_sibling(sd); | 963 | sysfs_link_sibling(sd); |
| 905 | 964 | ||
| @@ -909,30 +968,25 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
| 909 | return error; | 968 | return error; |
| 910 | } | 969 | } |
| 911 | 970 | ||
| 912 | int sysfs_rename_dir(struct kobject *kobj, const char *new_name) | 971 | int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, |
| 972 | const void *new_ns) | ||
| 913 | { | 973 | { |
| 914 | struct sysfs_dirent *parent_sd = kobj->sd->s_parent; | 974 | struct sysfs_dirent *parent_sd = kobj->sd->s_parent; |
| 915 | const void *new_ns = NULL; | ||
| 916 | |||
| 917 | if (sysfs_ns_type(parent_sd)) | ||
| 918 | new_ns = kobj->ktype->namespace(kobj); | ||
| 919 | 975 | ||
| 920 | return sysfs_rename(kobj->sd, parent_sd, new_ns, new_name); | 976 | return sysfs_rename(kobj->sd, parent_sd, new_name, new_ns); |
| 921 | } | 977 | } |
| 922 | 978 | ||
| 923 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | 979 | int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, |
| 980 | const void *new_ns) | ||
| 924 | { | 981 | { |
| 925 | struct sysfs_dirent *sd = kobj->sd; | 982 | struct sysfs_dirent *sd = kobj->sd; |
| 926 | struct sysfs_dirent *new_parent_sd; | 983 | struct sysfs_dirent *new_parent_sd; |
| 927 | const void *new_ns = NULL; | ||
| 928 | 984 | ||
| 929 | BUG_ON(!sd->s_parent); | 985 | BUG_ON(!sd->s_parent); |
| 930 | if (sysfs_ns_type(sd->s_parent)) | ||
| 931 | new_ns = kobj->ktype->namespace(kobj); | ||
| 932 | new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? | 986 | new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? |
| 933 | new_parent_kobj->sd : &sysfs_root; | 987 | new_parent_kobj->sd : &sysfs_root; |
| 934 | 988 | ||
| 935 | return sysfs_rename(sd, new_parent_sd, new_ns, sd->s_name); | 989 | return sysfs_rename(sd, new_parent_sd, sd->s_name, new_ns); |
| 936 | } | 990 | } |
| 937 | 991 | ||
| 938 | /* Relationship between s_mode and the DT_xxx types */ | 992 | /* Relationship between s_mode and the DT_xxx types */ |
| @@ -1002,15 +1056,15 @@ static int sysfs_readdir(struct file *file, struct dir_context *ctx) | |||
| 1002 | struct dentry *dentry = file->f_path.dentry; | 1056 | struct dentry *dentry = file->f_path.dentry; |
| 1003 | struct sysfs_dirent *parent_sd = dentry->d_fsdata; | 1057 | struct sysfs_dirent *parent_sd = dentry->d_fsdata; |
| 1004 | struct sysfs_dirent *pos = file->private_data; | 1058 | struct sysfs_dirent *pos = file->private_data; |
| 1005 | enum kobj_ns_type type; | 1059 | const void *ns = NULL; |
| 1006 | const void *ns; | ||
| 1007 | |||
| 1008 | type = sysfs_ns_type(parent_sd); | ||
| 1009 | ns = sysfs_info(dentry->d_sb)->ns[type]; | ||
| 1010 | 1060 | ||
| 1011 | if (!dir_emit_dots(file, ctx)) | 1061 | if (!dir_emit_dots(file, ctx)) |
| 1012 | return 0; | 1062 | return 0; |
| 1013 | mutex_lock(&sysfs_mutex); | 1063 | mutex_lock(&sysfs_mutex); |
| 1064 | |||
| 1065 | if (parent_sd->s_flags & SYSFS_FLAG_HAS_NS) | ||
| 1066 | ns = sysfs_info(dentry->d_sb)->ns; | ||
| 1067 | |||
| 1014 | for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos); | 1068 | for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos); |
| 1015 | pos; | 1069 | pos; |
| 1016 | pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) { | 1070 | pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) { |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 15ef5eb13663..79b5da2acbe1 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
| @@ -21,70 +21,114 @@ | |||
| 21 | #include <linux/mutex.h> | 21 | #include <linux/mutex.h> |
| 22 | #include <linux/limits.h> | 22 | #include <linux/limits.h> |
| 23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
| 24 | #include <linux/seq_file.h> | ||
| 25 | #include <linux/mm.h> | ||
| 24 | 26 | ||
| 25 | #include "sysfs.h" | 27 | #include "sysfs.h" |
| 26 | 28 | ||
| 27 | /* | 29 | /* |
| 28 | * There's one sysfs_buffer for each open file and one | 30 | * There's one sysfs_open_file for each open file and one sysfs_open_dirent |
| 29 | * sysfs_open_dirent for each sysfs_dirent with one or more open | 31 | * for each sysfs_dirent with one or more open files. |
| 30 | * files. | ||
| 31 | * | 32 | * |
| 32 | * filp->private_data points to sysfs_buffer and | 33 | * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open is |
| 33 | * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open | 34 | * protected by sysfs_open_dirent_lock. |
| 34 | * is protected by sysfs_open_dirent_lock. | 35 | * |
| 36 | * filp->private_data points to seq_file whose ->private points to | ||
| 37 | * sysfs_open_file. sysfs_open_files are chained at | ||
| 38 | * sysfs_open_dirent->files, which is protected by sysfs_open_file_mutex. | ||
| 35 | */ | 39 | */ |
| 36 | static DEFINE_SPINLOCK(sysfs_open_dirent_lock); | 40 | static DEFINE_SPINLOCK(sysfs_open_dirent_lock); |
| 41 | static DEFINE_MUTEX(sysfs_open_file_mutex); | ||
| 37 | 42 | ||
| 38 | struct sysfs_open_dirent { | 43 | struct sysfs_open_dirent { |
| 39 | atomic_t refcnt; | 44 | atomic_t refcnt; |
| 40 | atomic_t event; | 45 | atomic_t event; |
| 41 | wait_queue_head_t poll; | 46 | wait_queue_head_t poll; |
| 42 | struct list_head buffers; /* goes through sysfs_buffer.list */ | 47 | struct list_head files; /* goes through sysfs_open_file.list */ |
| 43 | }; | 48 | }; |
| 44 | 49 | ||
| 45 | struct sysfs_buffer { | 50 | struct sysfs_open_file { |
| 46 | size_t count; | 51 | struct sysfs_dirent *sd; |
| 47 | loff_t pos; | 52 | struct file *file; |
| 48 | char *page; | ||
| 49 | const struct sysfs_ops *ops; | ||
| 50 | struct mutex mutex; | 53 | struct mutex mutex; |
| 51 | int needs_read_fill; | ||
| 52 | int event; | 54 | int event; |
| 53 | struct list_head list; | 55 | struct list_head list; |
| 56 | |||
| 57 | bool mmapped; | ||
| 58 | const struct vm_operations_struct *vm_ops; | ||
| 54 | }; | 59 | }; |
| 55 | 60 | ||
| 56 | /** | 61 | static bool sysfs_is_bin(struct sysfs_dirent *sd) |
| 57 | * fill_read_buffer - allocate and fill buffer from object. | 62 | { |
| 58 | * @dentry: dentry pointer. | 63 | return sysfs_type(sd) == SYSFS_KOBJ_BIN_ATTR; |
| 59 | * @buffer: data buffer for file. | 64 | } |
| 60 | * | 65 | |
| 61 | * Allocate @buffer->page, if it hasn't been already, then call the | 66 | static struct sysfs_open_file *sysfs_of(struct file *file) |
| 62 | * kobject's show() method to fill the buffer with this attribute's | 67 | { |
| 63 | * data. | 68 | return ((struct seq_file *)file->private_data)->private; |
| 64 | * This is called only once, on the file's first read unless an error | 69 | } |
| 65 | * is returned. | 70 | |
| 71 | /* | ||
| 72 | * Determine ktype->sysfs_ops for the given sysfs_dirent. This function | ||
| 73 | * must be called while holding an active reference. | ||
| 66 | */ | 74 | */ |
| 67 | static int fill_read_buffer(struct dentry *dentry, struct sysfs_buffer *buffer) | 75 | static const struct sysfs_ops *sysfs_file_ops(struct sysfs_dirent *sd) |
| 68 | { | 76 | { |
| 69 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 77 | struct kobject *kobj = sd->s_parent->s_dir.kobj; |
| 70 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 78 | |
| 71 | const struct sysfs_ops *ops = buffer->ops; | 79 | if (!sysfs_ignore_lockdep(sd)) |
| 72 | int ret = 0; | 80 | lockdep_assert_held(sd); |
| 81 | return kobj->ktype ? kobj->ktype->sysfs_ops : NULL; | ||
| 82 | } | ||
| 83 | |||
| 84 | /* | ||
| 85 | * Reads on sysfs are handled through seq_file, which takes care of hairy | ||
| 86 | * details like buffering and seeking. The following function pipes | ||
| 87 | * sysfs_ops->show() result through seq_file. | ||
| 88 | */ | ||
| 89 | static int sysfs_seq_show(struct seq_file *sf, void *v) | ||
| 90 | { | ||
| 91 | struct sysfs_open_file *of = sf->private; | ||
| 92 | struct kobject *kobj = of->sd->s_parent->s_dir.kobj; | ||
| 93 | const struct sysfs_ops *ops; | ||
| 94 | char *buf; | ||
| 73 | ssize_t count; | 95 | ssize_t count; |
| 74 | 96 | ||
| 75 | if (!buffer->page) | 97 | /* acquire buffer and ensure that it's >= PAGE_SIZE */ |
| 76 | buffer->page = (char *) get_zeroed_page(GFP_KERNEL); | 98 | count = seq_get_buf(sf, &buf); |
| 77 | if (!buffer->page) | 99 | if (count < PAGE_SIZE) { |
| 78 | return -ENOMEM; | 100 | seq_commit(sf, -1); |
| 101 | return 0; | ||
| 102 | } | ||
| 79 | 103 | ||
| 80 | /* need attr_sd for attr and ops, its parent for kobj */ | 104 | /* |
| 81 | if (!sysfs_get_active(attr_sd)) | 105 | * Need @of->sd for attr and ops, its parent for kobj. @of->mutex |
| 106 | * nests outside active ref and is just to ensure that the ops | ||
| 107 | * aren't called concurrently for the same open file. | ||
| 108 | */ | ||
| 109 | mutex_lock(&of->mutex); | ||
| 110 | if (!sysfs_get_active(of->sd)) { | ||
| 111 | mutex_unlock(&of->mutex); | ||
| 82 | return -ENODEV; | 112 | return -ENODEV; |
| 113 | } | ||
| 83 | 114 | ||
| 84 | buffer->event = atomic_read(&attr_sd->s_attr.open->event); | 115 | of->event = atomic_read(&of->sd->s_attr.open->event); |
| 85 | count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); | ||
| 86 | 116 | ||
| 87 | sysfs_put_active(attr_sd); | 117 | /* |
| 118 | * Lookup @ops and invoke show(). Control may reach here via seq | ||
| 119 | * file lseek even if @ops->show() isn't implemented. | ||
| 120 | */ | ||
| 121 | ops = sysfs_file_ops(of->sd); | ||
| 122 | if (ops->show) | ||
| 123 | count = ops->show(kobj, of->sd->s_attr.attr, buf); | ||
| 124 | else | ||
| 125 | count = 0; | ||
| 126 | |||
| 127 | sysfs_put_active(of->sd); | ||
| 128 | mutex_unlock(&of->mutex); | ||
| 129 | |||
| 130 | if (count < 0) | ||
| 131 | return count; | ||
| 88 | 132 | ||
| 89 | /* | 133 | /* |
| 90 | * The code works fine with PAGE_SIZE return but it's likely to | 134 | * The code works fine with PAGE_SIZE return but it's likely to |
| @@ -96,155 +140,389 @@ static int fill_read_buffer(struct dentry *dentry, struct sysfs_buffer *buffer) | |||
| 96 | /* Try to struggle along */ | 140 | /* Try to struggle along */ |
| 97 | count = PAGE_SIZE - 1; | 141 | count = PAGE_SIZE - 1; |
| 98 | } | 142 | } |
| 99 | if (count >= 0) { | 143 | seq_commit(sf, count); |
| 100 | buffer->needs_read_fill = 0; | 144 | return 0; |
| 101 | buffer->count = count; | ||
| 102 | } else { | ||
| 103 | ret = count; | ||
| 104 | } | ||
| 105 | return ret; | ||
| 106 | } | 145 | } |
| 107 | 146 | ||
| 108 | /** | 147 | /* |
| 109 | * sysfs_read_file - read an attribute. | 148 | * Read method for bin files. As reading a bin file can have side-effects, |
| 110 | * @file: file pointer. | 149 | * the exact offset and bytes specified in read(2) call should be passed to |
| 111 | * @buf: buffer to fill. | 150 | * the read callback making it difficult to use seq_file. Implement |
| 112 | * @count: number of bytes to read. | 151 | * simplistic custom buffering for bin files. |
| 113 | * @ppos: starting offset in file. | ||
| 114 | * | ||
| 115 | * Userspace wants to read an attribute file. The attribute descriptor | ||
| 116 | * is in the file's ->d_fsdata. The target object is in the directory's | ||
| 117 | * ->d_fsdata. | ||
| 118 | * | ||
| 119 | * We call fill_read_buffer() to allocate and fill the buffer from the | ||
| 120 | * object's show() method exactly once (if the read is happening from | ||
| 121 | * the beginning of the file). That should fill the entire buffer with | ||
| 122 | * all the data the object has to offer for that attribute. | ||
| 123 | * We then call flush_read_buffer() to copy the buffer to userspace | ||
| 124 | * in the increments specified. | ||
| 125 | */ | 152 | */ |
| 126 | 153 | static ssize_t sysfs_bin_read(struct file *file, char __user *userbuf, | |
| 127 | static ssize_t | 154 | size_t bytes, loff_t *off) |
| 128 | sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) | ||
| 129 | { | 155 | { |
| 130 | struct sysfs_buffer *buffer = file->private_data; | 156 | struct sysfs_open_file *of = sysfs_of(file); |
| 131 | ssize_t retval = 0; | 157 | struct bin_attribute *battr = of->sd->s_attr.bin_attr; |
| 158 | struct kobject *kobj = of->sd->s_parent->s_dir.kobj; | ||
| 159 | loff_t size = file_inode(file)->i_size; | ||
| 160 | int count = min_t(size_t, bytes, PAGE_SIZE); | ||
| 161 | loff_t offs = *off; | ||
| 162 | char *buf; | ||
| 163 | |||
| 164 | if (!bytes) | ||
| 165 | return 0; | ||
| 132 | 166 | ||
| 133 | mutex_lock(&buffer->mutex); | 167 | if (size) { |
| 134 | if (buffer->needs_read_fill || *ppos == 0) { | 168 | if (offs > size) |
| 135 | retval = fill_read_buffer(file->f_path.dentry, buffer); | 169 | return 0; |
| 136 | if (retval) | 170 | if (offs + count > size) |
| 137 | goto out; | 171 | count = size - offs; |
| 138 | } | 172 | } |
| 139 | pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n", | ||
| 140 | __func__, count, *ppos, buffer->page); | ||
| 141 | retval = simple_read_from_buffer(buf, count, ppos, buffer->page, | ||
| 142 | buffer->count); | ||
| 143 | out: | ||
| 144 | mutex_unlock(&buffer->mutex); | ||
| 145 | return retval; | ||
| 146 | } | ||
| 147 | 173 | ||
| 148 | /** | 174 | buf = kmalloc(count, GFP_KERNEL); |
| 149 | * fill_write_buffer - copy buffer from userspace. | 175 | if (!buf) |
| 150 | * @buffer: data buffer for file. | ||
| 151 | * @buf: data from user. | ||
| 152 | * @count: number of bytes in @userbuf. | ||
| 153 | * | ||
| 154 | * Allocate @buffer->page if it hasn't been already, then | ||
| 155 | * copy the user-supplied buffer into it. | ||
| 156 | */ | ||
| 157 | static int fill_write_buffer(struct sysfs_buffer *buffer, | ||
| 158 | const char __user *buf, size_t count) | ||
| 159 | { | ||
| 160 | int error; | ||
| 161 | |||
| 162 | if (!buffer->page) | ||
| 163 | buffer->page = (char *)get_zeroed_page(GFP_KERNEL); | ||
| 164 | if (!buffer->page) | ||
| 165 | return -ENOMEM; | 176 | return -ENOMEM; |
| 166 | 177 | ||
| 167 | if (count >= PAGE_SIZE) | 178 | /* need of->sd for battr, its parent for kobj */ |
| 168 | count = PAGE_SIZE - 1; | 179 | mutex_lock(&of->mutex); |
| 169 | error = copy_from_user(buffer->page, buf, count); | 180 | if (!sysfs_get_active(of->sd)) { |
| 170 | buffer->needs_read_fill = 1; | 181 | count = -ENODEV; |
| 171 | /* if buf is assumed to contain a string, terminate it by \0, | 182 | mutex_unlock(&of->mutex); |
| 172 | so e.g. sscanf() can scan the string easily */ | 183 | goto out_free; |
| 173 | buffer->page[count] = 0; | 184 | } |
| 174 | return error ? -EFAULT : count; | 185 | |
| 175 | } | 186 | if (battr->read) |
| 187 | count = battr->read(file, kobj, battr, buf, offs, count); | ||
| 188 | else | ||
| 189 | count = -EIO; | ||
| 176 | 190 | ||
| 191 | sysfs_put_active(of->sd); | ||
| 192 | mutex_unlock(&of->mutex); | ||
| 193 | |||
| 194 | if (count < 0) | ||
| 195 | goto out_free; | ||
| 196 | |||
| 197 | if (copy_to_user(userbuf, buf, count)) { | ||
| 198 | count = -EFAULT; | ||
| 199 | goto out_free; | ||
| 200 | } | ||
| 201 | |||
| 202 | pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count); | ||
| 203 | |||
| 204 | *off = offs + count; | ||
| 205 | |||
| 206 | out_free: | ||
| 207 | kfree(buf); | ||
| 208 | return count; | ||
| 209 | } | ||
| 177 | 210 | ||
| 178 | /** | 211 | /** |
| 179 | * flush_write_buffer - push buffer to kobject. | 212 | * flush_write_buffer - push buffer to kobject |
| 180 | * @dentry: dentry to the attribute | 213 | * @of: open file |
| 181 | * @buffer: data buffer for file. | 214 | * @buf: data buffer for file |
| 182 | * @count: number of bytes | 215 | * @off: file offset to write to |
| 216 | * @count: number of bytes | ||
| 183 | * | 217 | * |
| 184 | * Get the correct pointers for the kobject and the attribute we're | 218 | * Get the correct pointers for the kobject and the attribute we're dealing |
| 185 | * dealing with, then call the store() method for the attribute, | 219 | * with, then call the store() method for it with @buf. |
| 186 | * passing the buffer that we acquired in fill_write_buffer(). | ||
| 187 | */ | 220 | */ |
| 188 | static int flush_write_buffer(struct dentry *dentry, | 221 | static int flush_write_buffer(struct sysfs_open_file *of, char *buf, loff_t off, |
| 189 | struct sysfs_buffer *buffer, size_t count) | 222 | size_t count) |
| 190 | { | 223 | { |
| 191 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 224 | struct kobject *kobj = of->sd->s_parent->s_dir.kobj; |
| 192 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 225 | int rc = 0; |
| 193 | const struct sysfs_ops *ops = buffer->ops; | ||
| 194 | int rc; | ||
| 195 | 226 | ||
| 196 | /* need attr_sd for attr and ops, its parent for kobj */ | 227 | /* |
| 197 | if (!sysfs_get_active(attr_sd)) | 228 | * Need @of->sd for attr and ops, its parent for kobj. @of->mutex |
| 229 | * nests outside active ref and is just to ensure that the ops | ||
| 230 | * aren't called concurrently for the same open file. | ||
| 231 | */ | ||
| 232 | mutex_lock(&of->mutex); | ||
| 233 | if (!sysfs_get_active(of->sd)) { | ||
| 234 | mutex_unlock(&of->mutex); | ||
| 198 | return -ENODEV; | 235 | return -ENODEV; |
| 236 | } | ||
| 199 | 237 | ||
| 200 | rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count); | 238 | if (sysfs_is_bin(of->sd)) { |
| 239 | struct bin_attribute *battr = of->sd->s_attr.bin_attr; | ||
| 201 | 240 | ||
| 202 | sysfs_put_active(attr_sd); | 241 | rc = -EIO; |
| 242 | if (battr->write) | ||
| 243 | rc = battr->write(of->file, kobj, battr, buf, off, | ||
| 244 | count); | ||
| 245 | } else { | ||
| 246 | const struct sysfs_ops *ops = sysfs_file_ops(of->sd); | ||
| 247 | |||
| 248 | rc = ops->store(kobj, of->sd->s_attr.attr, buf, count); | ||
| 249 | } | ||
| 250 | |||
| 251 | sysfs_put_active(of->sd); | ||
| 252 | mutex_unlock(&of->mutex); | ||
| 203 | 253 | ||
| 204 | return rc; | 254 | return rc; |
| 205 | } | 255 | } |
| 206 | 256 | ||
| 207 | |||
| 208 | /** | 257 | /** |
| 209 | * sysfs_write_file - write an attribute. | 258 | * sysfs_write_file - write an attribute |
| 210 | * @file: file pointer | 259 | * @file: file pointer |
| 211 | * @buf: data to write | 260 | * @user_buf: data to write |
| 212 | * @count: number of bytes | 261 | * @count: number of bytes |
| 213 | * @ppos: starting offset | 262 | * @ppos: starting offset |
| 263 | * | ||
| 264 | * Copy data in from userland and pass it to the matching | ||
| 265 | * sysfs_ops->store() by invoking flush_write_buffer(). | ||
| 214 | * | 266 | * |
| 215 | * Similar to sysfs_read_file(), though working in the opposite direction. | 267 | * There is no easy way for us to know if userspace is only doing a partial |
| 216 | * We allocate and fill the data from the user in fill_write_buffer(), | 268 | * write, so we don't support them. We expect the entire buffer to come on |
| 217 | * then push it to the kobject in flush_write_buffer(). | 269 | * the first write. Hint: if you're writing a value, first read the file, |
| 218 | * There is no easy way for us to know if userspace is only doing a partial | 270 | * modify only the the value you're changing, then write entire buffer |
| 219 | * write, so we don't support them. We expect the entire buffer to come | 271 | * back. |
| 220 | * on the first write. | ||
| 221 | * Hint: if you're writing a value, first read the file, modify only the | ||
| 222 | * the value you're changing, then write entire buffer back. | ||
| 223 | */ | 272 | */ |
| 224 | static ssize_t sysfs_write_file(struct file *file, const char __user *buf, | 273 | static ssize_t sysfs_write_file(struct file *file, const char __user *user_buf, |
| 225 | size_t count, loff_t *ppos) | 274 | size_t count, loff_t *ppos) |
| 226 | { | 275 | { |
| 227 | struct sysfs_buffer *buffer = file->private_data; | 276 | struct sysfs_open_file *of = sysfs_of(file); |
| 228 | ssize_t len; | 277 | ssize_t len = min_t(size_t, count, PAGE_SIZE); |
| 278 | loff_t size = file_inode(file)->i_size; | ||
| 279 | char *buf; | ||
| 280 | |||
| 281 | if (sysfs_is_bin(of->sd) && size) { | ||
| 282 | if (size <= *ppos) | ||
| 283 | return 0; | ||
| 284 | len = min_t(ssize_t, len, size - *ppos); | ||
| 285 | } | ||
| 229 | 286 | ||
| 230 | mutex_lock(&buffer->mutex); | 287 | if (!len) |
| 231 | len = fill_write_buffer(buffer, buf, count); | 288 | return 0; |
| 232 | if (len > 0) | 289 | |
| 233 | len = flush_write_buffer(file->f_path.dentry, buffer, len); | 290 | buf = kmalloc(len + 1, GFP_KERNEL); |
| 291 | if (!buf) | ||
| 292 | return -ENOMEM; | ||
| 293 | |||
| 294 | if (copy_from_user(buf, user_buf, len)) { | ||
| 295 | len = -EFAULT; | ||
| 296 | goto out_free; | ||
| 297 | } | ||
| 298 | buf[len] = '\0'; /* guarantee string termination */ | ||
| 299 | |||
| 300 | len = flush_write_buffer(of, buf, *ppos, len); | ||
| 234 | if (len > 0) | 301 | if (len > 0) |
| 235 | *ppos += len; | 302 | *ppos += len; |
| 236 | mutex_unlock(&buffer->mutex); | 303 | out_free: |
| 304 | kfree(buf); | ||
| 237 | return len; | 305 | return len; |
| 238 | } | 306 | } |
| 239 | 307 | ||
| 308 | static void sysfs_bin_vma_open(struct vm_area_struct *vma) | ||
| 309 | { | ||
| 310 | struct file *file = vma->vm_file; | ||
| 311 | struct sysfs_open_file *of = sysfs_of(file); | ||
| 312 | |||
| 313 | if (!of->vm_ops) | ||
| 314 | return; | ||
| 315 | |||
| 316 | if (!sysfs_get_active(of->sd)) | ||
| 317 | return; | ||
| 318 | |||
| 319 | if (of->vm_ops->open) | ||
| 320 | of->vm_ops->open(vma); | ||
| 321 | |||
| 322 | sysfs_put_active(of->sd); | ||
| 323 | } | ||
| 324 | |||
| 325 | static int sysfs_bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
| 326 | { | ||
| 327 | struct file *file = vma->vm_file; | ||
| 328 | struct sysfs_open_file *of = sysfs_of(file); | ||
| 329 | int ret; | ||
| 330 | |||
| 331 | if (!of->vm_ops) | ||
| 332 | return VM_FAULT_SIGBUS; | ||
| 333 | |||
| 334 | if (!sysfs_get_active(of->sd)) | ||
| 335 | return VM_FAULT_SIGBUS; | ||
| 336 | |||
| 337 | ret = VM_FAULT_SIGBUS; | ||
| 338 | if (of->vm_ops->fault) | ||
| 339 | ret = of->vm_ops->fault(vma, vmf); | ||
| 340 | |||
| 341 | sysfs_put_active(of->sd); | ||
| 342 | return ret; | ||
| 343 | } | ||
| 344 | |||
| 345 | static int sysfs_bin_page_mkwrite(struct vm_area_struct *vma, | ||
| 346 | struct vm_fault *vmf) | ||
| 347 | { | ||
| 348 | struct file *file = vma->vm_file; | ||
| 349 | struct sysfs_open_file *of = sysfs_of(file); | ||
| 350 | int ret; | ||
| 351 | |||
| 352 | if (!of->vm_ops) | ||
| 353 | return VM_FAULT_SIGBUS; | ||
| 354 | |||
| 355 | if (!sysfs_get_active(of->sd)) | ||
| 356 | return VM_FAULT_SIGBUS; | ||
| 357 | |||
| 358 | ret = 0; | ||
| 359 | if (of->vm_ops->page_mkwrite) | ||
| 360 | ret = of->vm_ops->page_mkwrite(vma, vmf); | ||
| 361 | else | ||
| 362 | file_update_time(file); | ||
| 363 | |||
| 364 | sysfs_put_active(of->sd); | ||
| 365 | return ret; | ||
| 366 | } | ||
| 367 | |||
| 368 | static int sysfs_bin_access(struct vm_area_struct *vma, unsigned long addr, | ||
| 369 | void *buf, int len, int write) | ||
| 370 | { | ||
| 371 | struct file *file = vma->vm_file; | ||
| 372 | struct sysfs_open_file *of = sysfs_of(file); | ||
| 373 | int ret; | ||
| 374 | |||
| 375 | if (!of->vm_ops) | ||
| 376 | return -EINVAL; | ||
| 377 | |||
| 378 | if (!sysfs_get_active(of->sd)) | ||
| 379 | return -EINVAL; | ||
| 380 | |||
| 381 | ret = -EINVAL; | ||
| 382 | if (of->vm_ops->access) | ||
| 383 | ret = of->vm_ops->access(vma, addr, buf, len, write); | ||
| 384 | |||
| 385 | sysfs_put_active(of->sd); | ||
| 386 | return ret; | ||
| 387 | } | ||
| 388 | |||
| 389 | #ifdef CONFIG_NUMA | ||
| 390 | static int sysfs_bin_set_policy(struct vm_area_struct *vma, | ||
| 391 | struct mempolicy *new) | ||
| 392 | { | ||
| 393 | struct file *file = vma->vm_file; | ||
| 394 | struct sysfs_open_file *of = sysfs_of(file); | ||
| 395 | int ret; | ||
| 396 | |||
| 397 | if (!of->vm_ops) | ||
| 398 | return 0; | ||
| 399 | |||
| 400 | if (!sysfs_get_active(of->sd)) | ||
| 401 | return -EINVAL; | ||
| 402 | |||
| 403 | ret = 0; | ||
| 404 | if (of->vm_ops->set_policy) | ||
| 405 | ret = of->vm_ops->set_policy(vma, new); | ||
| 406 | |||
| 407 | sysfs_put_active(of->sd); | ||
| 408 | return ret; | ||
| 409 | } | ||
| 410 | |||
| 411 | static struct mempolicy *sysfs_bin_get_policy(struct vm_area_struct *vma, | ||
| 412 | unsigned long addr) | ||
| 413 | { | ||
| 414 | struct file *file = vma->vm_file; | ||
| 415 | struct sysfs_open_file *of = sysfs_of(file); | ||
| 416 | struct mempolicy *pol; | ||
| 417 | |||
| 418 | if (!of->vm_ops) | ||
| 419 | return vma->vm_policy; | ||
| 420 | |||
| 421 | if (!sysfs_get_active(of->sd)) | ||
| 422 | return vma->vm_policy; | ||
| 423 | |||
| 424 | pol = vma->vm_policy; | ||
| 425 | if (of->vm_ops->get_policy) | ||
| 426 | pol = of->vm_ops->get_policy(vma, addr); | ||
| 427 | |||
| 428 | sysfs_put_active(of->sd); | ||
| 429 | return pol; | ||
| 430 | } | ||
| 431 | |||
| 432 | static int sysfs_bin_migrate(struct vm_area_struct *vma, const nodemask_t *from, | ||
| 433 | const nodemask_t *to, unsigned long flags) | ||
| 434 | { | ||
| 435 | struct file *file = vma->vm_file; | ||
| 436 | struct sysfs_open_file *of = sysfs_of(file); | ||
| 437 | int ret; | ||
| 438 | |||
| 439 | if (!of->vm_ops) | ||
| 440 | return 0; | ||
| 441 | |||
| 442 | if (!sysfs_get_active(of->sd)) | ||
| 443 | return 0; | ||
| 444 | |||
| 445 | ret = 0; | ||
| 446 | if (of->vm_ops->migrate) | ||
| 447 | ret = of->vm_ops->migrate(vma, from, to, flags); | ||
| 448 | |||
| 449 | sysfs_put_active(of->sd); | ||
| 450 | return ret; | ||
| 451 | } | ||
| 452 | #endif | ||
| 453 | |||
| 454 | static const struct vm_operations_struct sysfs_bin_vm_ops = { | ||
| 455 | .open = sysfs_bin_vma_open, | ||
| 456 | .fault = sysfs_bin_fault, | ||
| 457 | .page_mkwrite = sysfs_bin_page_mkwrite, | ||
| 458 | .access = sysfs_bin_access, | ||
| 459 | #ifdef CONFIG_NUMA | ||
| 460 | .set_policy = sysfs_bin_set_policy, | ||
| 461 | .get_policy = sysfs_bin_get_policy, | ||
| 462 | .migrate = sysfs_bin_migrate, | ||
| 463 | #endif | ||
| 464 | }; | ||
| 465 | |||
| 466 | static int sysfs_bin_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 467 | { | ||
| 468 | struct sysfs_open_file *of = sysfs_of(file); | ||
| 469 | struct bin_attribute *battr = of->sd->s_attr.bin_attr; | ||
| 470 | struct kobject *kobj = of->sd->s_parent->s_dir.kobj; | ||
| 471 | int rc; | ||
| 472 | |||
| 473 | mutex_lock(&of->mutex); | ||
| 474 | |||
| 475 | /* need of->sd for battr, its parent for kobj */ | ||
| 476 | rc = -ENODEV; | ||
| 477 | if (!sysfs_get_active(of->sd)) | ||
| 478 | goto out_unlock; | ||
| 479 | |||
| 480 | if (!battr->mmap) | ||
| 481 | goto out_put; | ||
| 482 | |||
| 483 | rc = battr->mmap(file, kobj, battr, vma); | ||
| 484 | if (rc) | ||
| 485 | goto out_put; | ||
| 486 | |||
| 487 | /* | ||
| 488 | * PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup() | ||
| 489 | * to satisfy versions of X which crash if the mmap fails: that | ||
| 490 | * substitutes a new vm_file, and we don't then want bin_vm_ops. | ||
| 491 | */ | ||
| 492 | if (vma->vm_file != file) | ||
| 493 | goto out_put; | ||
| 494 | |||
| 495 | rc = -EINVAL; | ||
| 496 | if (of->mmapped && of->vm_ops != vma->vm_ops) | ||
| 497 | goto out_put; | ||
| 498 | |||
| 499 | /* | ||
| 500 | * It is not possible to successfully wrap close. | ||
| 501 | * So error if someone is trying to use close. | ||
| 502 | */ | ||
| 503 | rc = -EINVAL; | ||
| 504 | if (vma->vm_ops && vma->vm_ops->close) | ||
| 505 | goto out_put; | ||
| 506 | |||
| 507 | rc = 0; | ||
| 508 | of->mmapped = 1; | ||
| 509 | of->vm_ops = vma->vm_ops; | ||
| 510 | vma->vm_ops = &sysfs_bin_vm_ops; | ||
| 511 | out_put: | ||
| 512 | sysfs_put_active(of->sd); | ||
| 513 | out_unlock: | ||
| 514 | mutex_unlock(&of->mutex); | ||
| 515 | |||
| 516 | return rc; | ||
| 517 | } | ||
| 518 | |||
| 240 | /** | 519 | /** |
| 241 | * sysfs_get_open_dirent - get or create sysfs_open_dirent | 520 | * sysfs_get_open_dirent - get or create sysfs_open_dirent |
| 242 | * @sd: target sysfs_dirent | 521 | * @sd: target sysfs_dirent |
| 243 | * @buffer: sysfs_buffer for this instance of open | 522 | * @of: sysfs_open_file for this instance of open |
| 244 | * | 523 | * |
| 245 | * If @sd->s_attr.open exists, increment its reference count; | 524 | * If @sd->s_attr.open exists, increment its reference count; |
| 246 | * otherwise, create one. @buffer is chained to the buffers | 525 | * otherwise, create one. @of is chained to the files list. |
| 247 | * list. | ||
| 248 | * | 526 | * |
| 249 | * LOCKING: | 527 | * LOCKING: |
| 250 | * Kernel thread context (may sleep). | 528 | * Kernel thread context (may sleep). |
| @@ -253,11 +531,12 @@ static ssize_t sysfs_write_file(struct file *file, const char __user *buf, | |||
| 253 | * 0 on success, -errno on failure. | 531 | * 0 on success, -errno on failure. |
| 254 | */ | 532 | */ |
| 255 | static int sysfs_get_open_dirent(struct sysfs_dirent *sd, | 533 | static int sysfs_get_open_dirent(struct sysfs_dirent *sd, |
| 256 | struct sysfs_buffer *buffer) | 534 | struct sysfs_open_file *of) |
| 257 | { | 535 | { |
| 258 | struct sysfs_open_dirent *od, *new_od = NULL; | 536 | struct sysfs_open_dirent *od, *new_od = NULL; |
| 259 | 537 | ||
| 260 | retry: | 538 | retry: |
| 539 | mutex_lock(&sysfs_open_file_mutex); | ||
| 261 | spin_lock_irq(&sysfs_open_dirent_lock); | 540 | spin_lock_irq(&sysfs_open_dirent_lock); |
| 262 | 541 | ||
| 263 | if (!sd->s_attr.open && new_od) { | 542 | if (!sd->s_attr.open && new_od) { |
| @@ -268,10 +547,11 @@ static int sysfs_get_open_dirent(struct sysfs_dirent *sd, | |||
| 268 | od = sd->s_attr.open; | 547 | od = sd->s_attr.open; |
| 269 | if (od) { | 548 | if (od) { |
| 270 | atomic_inc(&od->refcnt); | 549 | atomic_inc(&od->refcnt); |
| 271 | list_add_tail(&buffer->list, &od->buffers); | 550 | list_add_tail(&of->list, &od->files); |
| 272 | } | 551 | } |
| 273 | 552 | ||
| 274 | spin_unlock_irq(&sysfs_open_dirent_lock); | 553 | spin_unlock_irq(&sysfs_open_dirent_lock); |
| 554 | mutex_unlock(&sysfs_open_file_mutex); | ||
| 275 | 555 | ||
| 276 | if (od) { | 556 | if (od) { |
| 277 | kfree(new_od); | 557 | kfree(new_od); |
| @@ -286,36 +566,40 @@ static int sysfs_get_open_dirent(struct sysfs_dirent *sd, | |||
| 286 | atomic_set(&new_od->refcnt, 0); | 566 | atomic_set(&new_od->refcnt, 0); |
| 287 | atomic_set(&new_od->event, 1); | 567 | atomic_set(&new_od->event, 1); |
| 288 | init_waitqueue_head(&new_od->poll); | 568 | init_waitqueue_head(&new_od->poll); |
| 289 | INIT_LIST_HEAD(&new_od->buffers); | 569 | INIT_LIST_HEAD(&new_od->files); |
| 290 | goto retry; | 570 | goto retry; |
| 291 | } | 571 | } |
| 292 | 572 | ||
| 293 | /** | 573 | /** |
| 294 | * sysfs_put_open_dirent - put sysfs_open_dirent | 574 | * sysfs_put_open_dirent - put sysfs_open_dirent |
| 295 | * @sd: target sysfs_dirent | 575 | * @sd: target sysfs_dirent |
| 296 | * @buffer: associated sysfs_buffer | 576 | * @of: associated sysfs_open_file |
| 297 | * | 577 | * |
| 298 | * Put @sd->s_attr.open and unlink @buffer from the buffers list. | 578 | * Put @sd->s_attr.open and unlink @of from the files list. If |
| 299 | * If reference count reaches zero, disassociate and free it. | 579 | * reference count reaches zero, disassociate and free it. |
| 300 | * | 580 | * |
| 301 | * LOCKING: | 581 | * LOCKING: |
| 302 | * None. | 582 | * None. |
| 303 | */ | 583 | */ |
| 304 | static void sysfs_put_open_dirent(struct sysfs_dirent *sd, | 584 | static void sysfs_put_open_dirent(struct sysfs_dirent *sd, |
| 305 | struct sysfs_buffer *buffer) | 585 | struct sysfs_open_file *of) |
| 306 | { | 586 | { |
| 307 | struct sysfs_open_dirent *od = sd->s_attr.open; | 587 | struct sysfs_open_dirent *od = sd->s_attr.open; |
| 308 | unsigned long flags; | 588 | unsigned long flags; |
| 309 | 589 | ||
| 590 | mutex_lock(&sysfs_open_file_mutex); | ||
| 310 | spin_lock_irqsave(&sysfs_open_dirent_lock, flags); | 591 | spin_lock_irqsave(&sysfs_open_dirent_lock, flags); |
| 311 | 592 | ||
| 312 | list_del(&buffer->list); | 593 | if (of) |
| 594 | list_del(&of->list); | ||
| 595 | |||
| 313 | if (atomic_dec_and_test(&od->refcnt)) | 596 | if (atomic_dec_and_test(&od->refcnt)) |
| 314 | sd->s_attr.open = NULL; | 597 | sd->s_attr.open = NULL; |
| 315 | else | 598 | else |
| 316 | od = NULL; | 599 | od = NULL; |
| 317 | 600 | ||
| 318 | spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags); | 601 | spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags); |
| 602 | mutex_unlock(&sysfs_open_file_mutex); | ||
| 319 | 603 | ||
| 320 | kfree(od); | 604 | kfree(od); |
| 321 | } | 605 | } |
| @@ -324,67 +608,81 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
| 324 | { | 608 | { |
| 325 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | 609 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
| 326 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 610 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
| 327 | struct sysfs_buffer *buffer; | 611 | struct sysfs_open_file *of; |
| 328 | const struct sysfs_ops *ops; | 612 | bool has_read, has_write; |
| 329 | int error = -EACCES; | 613 | int error = -EACCES; |
| 330 | 614 | ||
| 331 | /* need attr_sd for attr and ops, its parent for kobj */ | 615 | /* need attr_sd for attr and ops, its parent for kobj */ |
| 332 | if (!sysfs_get_active(attr_sd)) | 616 | if (!sysfs_get_active(attr_sd)) |
| 333 | return -ENODEV; | 617 | return -ENODEV; |
| 334 | 618 | ||
| 335 | /* every kobject with an attribute needs a ktype assigned */ | 619 | if (sysfs_is_bin(attr_sd)) { |
| 336 | if (kobj->ktype && kobj->ktype->sysfs_ops) | 620 | struct bin_attribute *battr = attr_sd->s_attr.bin_attr; |
| 337 | ops = kobj->ktype->sysfs_ops; | ||
| 338 | else { | ||
| 339 | WARN(1, KERN_ERR | ||
| 340 | "missing sysfs attribute operations for kobject: %s\n", | ||
| 341 | kobject_name(kobj)); | ||
| 342 | goto err_out; | ||
| 343 | } | ||
| 344 | 621 | ||
| 345 | /* File needs write support. | 622 | has_read = battr->read || battr->mmap; |
| 346 | * The inode's perms must say it's ok, | 623 | has_write = battr->write || battr->mmap; |
| 347 | * and we must have a store method. | 624 | } else { |
| 348 | */ | 625 | const struct sysfs_ops *ops = sysfs_file_ops(attr_sd); |
| 349 | if (file->f_mode & FMODE_WRITE) { | ||
| 350 | if (!(inode->i_mode & S_IWUGO) || !ops->store) | ||
| 351 | goto err_out; | ||
| 352 | } | ||
| 353 | 626 | ||
| 354 | /* File needs read support. | 627 | /* every kobject with an attribute needs a ktype assigned */ |
| 355 | * The inode's perms must say it's ok, and we there | 628 | if (WARN(!ops, KERN_ERR |
| 356 | * must be a show method for it. | 629 | "missing sysfs attribute operations for kobject: %s\n", |
| 357 | */ | 630 | kobject_name(kobj))) |
| 358 | if (file->f_mode & FMODE_READ) { | ||
| 359 | if (!(inode->i_mode & S_IRUGO) || !ops->show) | ||
| 360 | goto err_out; | 631 | goto err_out; |
| 632 | |||
| 633 | has_read = ops->show; | ||
| 634 | has_write = ops->store; | ||
| 361 | } | 635 | } |
| 362 | 636 | ||
| 363 | /* No error? Great, allocate a buffer for the file, and store it | 637 | /* check perms and supported operations */ |
| 364 | * it in file->private_data for easy access. | 638 | if ((file->f_mode & FMODE_WRITE) && |
| 365 | */ | 639 | (!(inode->i_mode & S_IWUGO) || !has_write)) |
| 640 | goto err_out; | ||
| 641 | |||
| 642 | if ((file->f_mode & FMODE_READ) && | ||
| 643 | (!(inode->i_mode & S_IRUGO) || !has_read)) | ||
| 644 | goto err_out; | ||
| 645 | |||
| 646 | /* allocate a sysfs_open_file for the file */ | ||
| 366 | error = -ENOMEM; | 647 | error = -ENOMEM; |
| 367 | buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); | 648 | of = kzalloc(sizeof(struct sysfs_open_file), GFP_KERNEL); |
| 368 | if (!buffer) | 649 | if (!of) |
| 369 | goto err_out; | 650 | goto err_out; |
| 370 | 651 | ||
| 371 | mutex_init(&buffer->mutex); | 652 | mutex_init(&of->mutex); |
| 372 | buffer->needs_read_fill = 1; | 653 | of->sd = attr_sd; |
| 373 | buffer->ops = ops; | 654 | of->file = file; |
| 374 | file->private_data = buffer; | ||
| 375 | 655 | ||
| 376 | /* make sure we have open dirent struct */ | 656 | /* |
| 377 | error = sysfs_get_open_dirent(attr_sd, buffer); | 657 | * Always instantiate seq_file even if read access doesn't use |
| 658 | * seq_file or is not requested. This unifies private data access | ||
| 659 | * and readable regular files are the vast majority anyway. | ||
| 660 | */ | ||
| 661 | if (sysfs_is_bin(attr_sd)) | ||
| 662 | error = single_open(file, NULL, of); | ||
| 663 | else | ||
| 664 | error = single_open(file, sysfs_seq_show, of); | ||
| 378 | if (error) | 665 | if (error) |
| 379 | goto err_free; | 666 | goto err_free; |
| 380 | 667 | ||
| 668 | /* seq_file clears PWRITE unconditionally, restore it if WRITE */ | ||
| 669 | if (file->f_mode & FMODE_WRITE) | ||
| 670 | file->f_mode |= FMODE_PWRITE; | ||
| 671 | |||
| 672 | /* make sure we have open dirent struct */ | ||
| 673 | error = sysfs_get_open_dirent(attr_sd, of); | ||
| 674 | if (error) | ||
| 675 | goto err_close; | ||
| 676 | |||
| 381 | /* open succeeded, put active references */ | 677 | /* open succeeded, put active references */ |
| 382 | sysfs_put_active(attr_sd); | 678 | sysfs_put_active(attr_sd); |
| 383 | return 0; | 679 | return 0; |
| 384 | 680 | ||
| 385 | err_free: | 681 | err_close: |
| 386 | kfree(buffer); | 682 | single_release(inode, file); |
| 387 | err_out: | 683 | err_free: |
| 684 | kfree(of); | ||
| 685 | err_out: | ||
| 388 | sysfs_put_active(attr_sd); | 686 | sysfs_put_active(attr_sd); |
| 389 | return error; | 687 | return error; |
| 390 | } | 688 | } |
| @@ -392,17 +690,41 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
| 392 | static int sysfs_release(struct inode *inode, struct file *filp) | 690 | static int sysfs_release(struct inode *inode, struct file *filp) |
| 393 | { | 691 | { |
| 394 | struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata; | 692 | struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata; |
| 395 | struct sysfs_buffer *buffer = filp->private_data; | 693 | struct sysfs_open_file *of = sysfs_of(filp); |
| 396 | 694 | ||
| 397 | sysfs_put_open_dirent(sd, buffer); | 695 | sysfs_put_open_dirent(sd, of); |
| 398 | 696 | single_release(inode, filp); | |
| 399 | if (buffer->page) | 697 | kfree(of); |
| 400 | free_page((unsigned long)buffer->page); | ||
| 401 | kfree(buffer); | ||
| 402 | 698 | ||
| 403 | return 0; | 699 | return 0; |
| 404 | } | 700 | } |
| 405 | 701 | ||
| 702 | void sysfs_unmap_bin_file(struct sysfs_dirent *sd) | ||
| 703 | { | ||
| 704 | struct sysfs_open_dirent *od; | ||
| 705 | struct sysfs_open_file *of; | ||
| 706 | |||
| 707 | if (!sysfs_is_bin(sd)) | ||
| 708 | return; | ||
| 709 | |||
| 710 | spin_lock_irq(&sysfs_open_dirent_lock); | ||
| 711 | od = sd->s_attr.open; | ||
| 712 | if (od) | ||
| 713 | atomic_inc(&od->refcnt); | ||
| 714 | spin_unlock_irq(&sysfs_open_dirent_lock); | ||
| 715 | if (!od) | ||
| 716 | return; | ||
| 717 | |||
| 718 | mutex_lock(&sysfs_open_file_mutex); | ||
| 719 | list_for_each_entry(of, &od->files, list) { | ||
| 720 | struct inode *inode = file_inode(of->file); | ||
| 721 | unmap_mapping_range(inode->i_mapping, 0, 0, 1); | ||
| 722 | } | ||
| 723 | mutex_unlock(&sysfs_open_file_mutex); | ||
| 724 | |||
| 725 | sysfs_put_open_dirent(sd, NULL); | ||
| 726 | } | ||
| 727 | |||
| 406 | /* Sysfs attribute files are pollable. The idea is that you read | 728 | /* Sysfs attribute files are pollable. The idea is that you read |
| 407 | * the content and then you use 'poll' or 'select' to wait for | 729 | * the content and then you use 'poll' or 'select' to wait for |
| 408 | * the content to change. When the content changes (assuming the | 730 | * the content to change. When the content changes (assuming the |
| @@ -418,7 +740,7 @@ static int sysfs_release(struct inode *inode, struct file *filp) | |||
| 418 | */ | 740 | */ |
| 419 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | 741 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) |
| 420 | { | 742 | { |
| 421 | struct sysfs_buffer *buffer = filp->private_data; | 743 | struct sysfs_open_file *of = sysfs_of(filp); |
| 422 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; | 744 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; |
| 423 | struct sysfs_open_dirent *od = attr_sd->s_attr.open; | 745 | struct sysfs_open_dirent *od = attr_sd->s_attr.open; |
| 424 | 746 | ||
| @@ -430,13 +752,12 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | |||
| 430 | 752 | ||
| 431 | sysfs_put_active(attr_sd); | 753 | sysfs_put_active(attr_sd); |
| 432 | 754 | ||
| 433 | if (buffer->event != atomic_read(&od->event)) | 755 | if (of->event != atomic_read(&od->event)) |
| 434 | goto trigger; | 756 | goto trigger; |
| 435 | 757 | ||
| 436 | return DEFAULT_POLLMASK; | 758 | return DEFAULT_POLLMASK; |
| 437 | 759 | ||
| 438 | trigger: | 760 | trigger: |
| 439 | buffer->needs_read_fill = 1; | ||
| 440 | return DEFAULT_POLLMASK|POLLERR|POLLPRI; | 761 | return DEFAULT_POLLMASK|POLLERR|POLLPRI; |
| 441 | } | 762 | } |
| 442 | 763 | ||
| @@ -466,9 +787,9 @@ void sysfs_notify(struct kobject *k, const char *dir, const char *attr) | |||
| 466 | mutex_lock(&sysfs_mutex); | 787 | mutex_lock(&sysfs_mutex); |
| 467 | 788 | ||
| 468 | if (sd && dir) | 789 | if (sd && dir) |
| 469 | sd = sysfs_find_dirent(sd, NULL, dir); | 790 | sd = sysfs_find_dirent(sd, dir, NULL); |
| 470 | if (sd && attr) | 791 | if (sd && attr) |
| 471 | sd = sysfs_find_dirent(sd, NULL, attr); | 792 | sd = sysfs_find_dirent(sd, attr, NULL); |
| 472 | if (sd) | 793 | if (sd) |
| 473 | sysfs_notify_dirent(sd); | 794 | sysfs_notify_dirent(sd); |
| 474 | 795 | ||
| @@ -477,7 +798,7 @@ void sysfs_notify(struct kobject *k, const char *dir, const char *attr) | |||
| 477 | EXPORT_SYMBOL_GPL(sysfs_notify); | 798 | EXPORT_SYMBOL_GPL(sysfs_notify); |
| 478 | 799 | ||
| 479 | const struct file_operations sysfs_file_operations = { | 800 | const struct file_operations sysfs_file_operations = { |
| 480 | .read = sysfs_read_file, | 801 | .read = seq_read, |
| 481 | .write = sysfs_write_file, | 802 | .write = sysfs_write_file, |
| 482 | .llseek = generic_file_llseek, | 803 | .llseek = generic_file_llseek, |
| 483 | .open = sysfs_open_file, | 804 | .open = sysfs_open_file, |
| @@ -485,58 +806,25 @@ const struct file_operations sysfs_file_operations = { | |||
| 485 | .poll = sysfs_poll, | 806 | .poll = sysfs_poll, |
| 486 | }; | 807 | }; |
| 487 | 808 | ||
| 488 | static int sysfs_attr_ns(struct kobject *kobj, const struct attribute *attr, | 809 | const struct file_operations sysfs_bin_operations = { |
| 489 | const void **pns) | 810 | .read = sysfs_bin_read, |
| 490 | { | 811 | .write = sysfs_write_file, |
| 491 | struct sysfs_dirent *dir_sd = kobj->sd; | 812 | .llseek = generic_file_llseek, |
| 492 | const struct sysfs_ops *ops; | 813 | .mmap = sysfs_bin_mmap, |
| 493 | const void *ns = NULL; | 814 | .open = sysfs_open_file, |
| 494 | int err; | 815 | .release = sysfs_release, |
| 495 | 816 | .poll = sysfs_poll, | |
| 496 | if (!dir_sd) { | 817 | }; |
| 497 | WARN(1, KERN_ERR "sysfs: kobject %s without dirent\n", | ||
| 498 | kobject_name(kobj)); | ||
| 499 | return -ENOENT; | ||
| 500 | } | ||
| 501 | |||
| 502 | err = 0; | ||
| 503 | if (!sysfs_ns_type(dir_sd)) | ||
| 504 | goto out; | ||
| 505 | |||
| 506 | err = -EINVAL; | ||
| 507 | if (!kobj->ktype) | ||
| 508 | goto out; | ||
| 509 | ops = kobj->ktype->sysfs_ops; | ||
| 510 | if (!ops) | ||
| 511 | goto out; | ||
| 512 | if (!ops->namespace) | ||
| 513 | goto out; | ||
| 514 | |||
| 515 | err = 0; | ||
| 516 | ns = ops->namespace(kobj, attr); | ||
| 517 | out: | ||
| 518 | if (err) { | ||
| 519 | WARN(1, KERN_ERR | ||
| 520 | "missing sysfs namespace attribute operation for kobject: %s\n", | ||
| 521 | kobject_name(kobj)); | ||
| 522 | } | ||
| 523 | *pns = ns; | ||
| 524 | return err; | ||
| 525 | } | ||
| 526 | 818 | ||
| 527 | int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, | 819 | int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, |
| 528 | const struct attribute *attr, int type, umode_t amode) | 820 | const struct attribute *attr, int type, |
| 821 | umode_t amode, const void *ns) | ||
| 529 | { | 822 | { |
| 530 | umode_t mode = (amode & S_IALLUGO) | S_IFREG; | 823 | umode_t mode = (amode & S_IALLUGO) | S_IFREG; |
| 531 | struct sysfs_addrm_cxt acxt; | 824 | struct sysfs_addrm_cxt acxt; |
| 532 | struct sysfs_dirent *sd; | 825 | struct sysfs_dirent *sd; |
| 533 | const void *ns; | ||
| 534 | int rc; | 826 | int rc; |
| 535 | 827 | ||
| 536 | rc = sysfs_attr_ns(dir_sd->s_dir.kobj, attr, &ns); | ||
| 537 | if (rc) | ||
| 538 | return rc; | ||
| 539 | |||
| 540 | sd = sysfs_new_dirent(attr->name, mode, type); | 828 | sd = sysfs_new_dirent(attr->name, mode, type); |
| 541 | if (!sd) | 829 | if (!sd) |
| 542 | return -ENOMEM; | 830 | return -ENOMEM; |
| @@ -545,8 +833,8 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, | |||
| 545 | sd->s_attr.attr = (void *)attr; | 833 | sd->s_attr.attr = (void *)attr; |
| 546 | sysfs_dirent_init_lockdep(sd); | 834 | sysfs_dirent_init_lockdep(sd); |
| 547 | 835 | ||
| 548 | sysfs_addrm_start(&acxt, dir_sd); | 836 | sysfs_addrm_start(&acxt); |
| 549 | rc = sysfs_add_one(&acxt, sd); | 837 | rc = sysfs_add_one(&acxt, sd, dir_sd); |
| 550 | sysfs_addrm_finish(&acxt); | 838 | sysfs_addrm_finish(&acxt); |
| 551 | 839 | ||
| 552 | if (rc) | 840 | if (rc) |
| @@ -559,23 +847,25 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, | |||
| 559 | int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, | 847 | int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, |
| 560 | int type) | 848 | int type) |
| 561 | { | 849 | { |
| 562 | return sysfs_add_file_mode(dir_sd, attr, type, attr->mode); | 850 | return sysfs_add_file_mode_ns(dir_sd, attr, type, attr->mode, NULL); |
| 563 | } | 851 | } |
| 564 | 852 | ||
| 565 | |||
| 566 | /** | 853 | /** |
| 567 | * sysfs_create_file - create an attribute file for an object. | 854 | * sysfs_create_file_ns - create an attribute file for an object with custom ns |
| 568 | * @kobj: object we're creating for. | 855 | * @kobj: object we're creating for |
| 569 | * @attr: attribute descriptor. | 856 | * @attr: attribute descriptor |
| 857 | * @ns: namespace the new file should belong to | ||
| 570 | */ | 858 | */ |
| 571 | int sysfs_create_file(struct kobject *kobj, const struct attribute *attr) | 859 | int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr, |
| 860 | const void *ns) | ||
| 572 | { | 861 | { |
| 573 | BUG_ON(!kobj || !kobj->sd || !attr); | 862 | BUG_ON(!kobj || !kobj->sd || !attr); |
| 574 | 863 | ||
| 575 | return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR); | 864 | return sysfs_add_file_mode_ns(kobj->sd, attr, SYSFS_KOBJ_ATTR, |
| 865 | attr->mode, ns); | ||
| 576 | 866 | ||
| 577 | } | 867 | } |
| 578 | EXPORT_SYMBOL_GPL(sysfs_create_file); | 868 | EXPORT_SYMBOL_GPL(sysfs_create_file_ns); |
| 579 | 869 | ||
| 580 | int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr) | 870 | int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr) |
| 581 | { | 871 | { |
| @@ -604,7 +894,7 @@ int sysfs_add_file_to_group(struct kobject *kobj, | |||
| 604 | int error; | 894 | int error; |
| 605 | 895 | ||
| 606 | if (group) | 896 | if (group) |
| 607 | dir_sd = sysfs_get_dirent(kobj->sd, NULL, group); | 897 | dir_sd = sysfs_get_dirent(kobj->sd, group); |
| 608 | else | 898 | else |
| 609 | dir_sd = sysfs_get(kobj->sd); | 899 | dir_sd = sysfs_get(kobj->sd); |
| 610 | 900 | ||
| @@ -630,17 +920,12 @@ int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, | |||
| 630 | { | 920 | { |
| 631 | struct sysfs_dirent *sd; | 921 | struct sysfs_dirent *sd; |
| 632 | struct iattr newattrs; | 922 | struct iattr newattrs; |
| 633 | const void *ns; | ||
| 634 | int rc; | 923 | int rc; |
| 635 | 924 | ||
| 636 | rc = sysfs_attr_ns(kobj, attr, &ns); | ||
| 637 | if (rc) | ||
| 638 | return rc; | ||
| 639 | |||
| 640 | mutex_lock(&sysfs_mutex); | 925 | mutex_lock(&sysfs_mutex); |
| 641 | 926 | ||
| 642 | rc = -ENOENT; | 927 | rc = -ENOENT; |
| 643 | sd = sysfs_find_dirent(kobj->sd, ns, attr->name); | 928 | sd = sysfs_find_dirent(kobj->sd, attr->name, NULL); |
| 644 | if (!sd) | 929 | if (!sd) |
| 645 | goto out; | 930 | goto out; |
| 646 | 931 | ||
| @@ -655,22 +940,21 @@ int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, | |||
| 655 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); | 940 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); |
| 656 | 941 | ||
| 657 | /** | 942 | /** |
| 658 | * sysfs_remove_file - remove an object attribute. | 943 | * sysfs_remove_file_ns - remove an object attribute with a custom ns tag |
| 659 | * @kobj: object we're acting for. | 944 | * @kobj: object we're acting for |
| 660 | * @attr: attribute descriptor. | 945 | * @attr: attribute descriptor |
| 946 | * @ns: namespace tag of the file to remove | ||
| 661 | * | 947 | * |
| 662 | * Hash the attribute name and kill the victim. | 948 | * Hash the attribute name and namespace tag and kill the victim. |
| 663 | */ | 949 | */ |
| 664 | void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr) | 950 | void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, |
| 951 | const void *ns) | ||
| 665 | { | 952 | { |
| 666 | const void *ns; | 953 | struct sysfs_dirent *dir_sd = kobj->sd; |
| 667 | |||
| 668 | if (sysfs_attr_ns(kobj, attr, &ns)) | ||
| 669 | return; | ||
| 670 | 954 | ||
| 671 | sysfs_hash_and_remove(kobj->sd, ns, attr->name); | 955 | sysfs_hash_and_remove(dir_sd, attr->name, ns); |
| 672 | } | 956 | } |
| 673 | EXPORT_SYMBOL_GPL(sysfs_remove_file); | 957 | EXPORT_SYMBOL_GPL(sysfs_remove_file_ns); |
| 674 | 958 | ||
| 675 | void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr) | 959 | void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr) |
| 676 | { | 960 | { |
| @@ -692,16 +976,42 @@ void sysfs_remove_file_from_group(struct kobject *kobj, | |||
| 692 | struct sysfs_dirent *dir_sd; | 976 | struct sysfs_dirent *dir_sd; |
| 693 | 977 | ||
| 694 | if (group) | 978 | if (group) |
| 695 | dir_sd = sysfs_get_dirent(kobj->sd, NULL, group); | 979 | dir_sd = sysfs_get_dirent(kobj->sd, group); |
| 696 | else | 980 | else |
| 697 | dir_sd = sysfs_get(kobj->sd); | 981 | dir_sd = sysfs_get(kobj->sd); |
| 698 | if (dir_sd) { | 982 | if (dir_sd) { |
| 699 | sysfs_hash_and_remove(dir_sd, NULL, attr->name); | 983 | sysfs_hash_and_remove(dir_sd, attr->name, NULL); |
| 700 | sysfs_put(dir_sd); | 984 | sysfs_put(dir_sd); |
| 701 | } | 985 | } |
| 702 | } | 986 | } |
| 703 | EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); | 987 | EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); |
| 704 | 988 | ||
| 989 | /** | ||
| 990 | * sysfs_create_bin_file - create binary file for object. | ||
| 991 | * @kobj: object. | ||
| 992 | * @attr: attribute descriptor. | ||
| 993 | */ | ||
| 994 | int sysfs_create_bin_file(struct kobject *kobj, | ||
| 995 | const struct bin_attribute *attr) | ||
| 996 | { | ||
| 997 | BUG_ON(!kobj || !kobj->sd || !attr); | ||
| 998 | |||
| 999 | return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR); | ||
| 1000 | } | ||
| 1001 | EXPORT_SYMBOL_GPL(sysfs_create_bin_file); | ||
| 1002 | |||
| 1003 | /** | ||
| 1004 | * sysfs_remove_bin_file - remove binary file for object. | ||
| 1005 | * @kobj: object. | ||
| 1006 | * @attr: attribute descriptor. | ||
| 1007 | */ | ||
| 1008 | void sysfs_remove_bin_file(struct kobject *kobj, | ||
| 1009 | const struct bin_attribute *attr) | ||
| 1010 | { | ||
| 1011 | sysfs_hash_and_remove(kobj->sd, attr->attr.name, NULL); | ||
| 1012 | } | ||
| 1013 | EXPORT_SYMBOL_GPL(sysfs_remove_bin_file); | ||
| 1014 | |||
| 705 | struct sysfs_schedule_callback_struct { | 1015 | struct sysfs_schedule_callback_struct { |
| 706 | struct list_head workq_list; | 1016 | struct list_head workq_list; |
| 707 | struct kobject *kobj; | 1017 | struct kobject *kobj; |
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 5f92cd2f61c1..1898a10e38ce 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
| @@ -26,7 +26,7 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, | |||
| 26 | 26 | ||
| 27 | if (grp->attrs) | 27 | if (grp->attrs) |
| 28 | for (attr = grp->attrs; *attr; attr++) | 28 | for (attr = grp->attrs; *attr; attr++) |
| 29 | sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name); | 29 | sysfs_hash_and_remove(dir_sd, (*attr)->name, NULL); |
| 30 | if (grp->bin_attrs) | 30 | if (grp->bin_attrs) |
| 31 | for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) | 31 | for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) |
| 32 | sysfs_remove_bin_file(kobj, *bin_attr); | 32 | sysfs_remove_bin_file(kobj, *bin_attr); |
| @@ -49,16 +49,17 @@ static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, | |||
| 49 | * re-adding (if required) the file. | 49 | * re-adding (if required) the file. |
| 50 | */ | 50 | */ |
| 51 | if (update) | 51 | if (update) |
| 52 | sysfs_hash_and_remove(dir_sd, NULL, | 52 | sysfs_hash_and_remove(dir_sd, (*attr)->name, |
| 53 | (*attr)->name); | 53 | NULL); |
| 54 | if (grp->is_visible) { | 54 | if (grp->is_visible) { |
| 55 | mode = grp->is_visible(kobj, *attr, i); | 55 | mode = grp->is_visible(kobj, *attr, i); |
| 56 | if (!mode) | 56 | if (!mode) |
| 57 | continue; | 57 | continue; |
| 58 | } | 58 | } |
| 59 | error = sysfs_add_file_mode(dir_sd, *attr, | 59 | error = sysfs_add_file_mode_ns(dir_sd, *attr, |
| 60 | SYSFS_KOBJ_ATTR, | 60 | SYSFS_KOBJ_ATTR, |
| 61 | (*attr)->mode | mode); | 61 | (*attr)->mode | mode, |
| 62 | NULL); | ||
| 62 | if (unlikely(error)) | 63 | if (unlikely(error)) |
| 63 | break; | 64 | break; |
| 64 | } | 65 | } |
| @@ -110,7 +111,7 @@ static int internal_create_group(struct kobject *kobj, int update, | |||
| 110 | error = create_files(sd, kobj, grp, update); | 111 | error = create_files(sd, kobj, grp, update); |
| 111 | if (error) { | 112 | if (error) { |
| 112 | if (grp->name) | 113 | if (grp->name) |
| 113 | sysfs_remove_subdir(sd); | 114 | sysfs_remove(sd); |
| 114 | } | 115 | } |
| 115 | sysfs_put(sd); | 116 | sysfs_put(sd); |
| 116 | return error; | 117 | return error; |
| @@ -206,7 +207,7 @@ void sysfs_remove_group(struct kobject *kobj, | |||
| 206 | struct sysfs_dirent *sd; | 207 | struct sysfs_dirent *sd; |
| 207 | 208 | ||
| 208 | if (grp->name) { | 209 | if (grp->name) { |
| 209 | sd = sysfs_get_dirent(dir_sd, NULL, grp->name); | 210 | sd = sysfs_get_dirent(dir_sd, grp->name); |
| 210 | if (!sd) { | 211 | if (!sd) { |
| 211 | WARN(!sd, KERN_WARNING | 212 | WARN(!sd, KERN_WARNING |
| 212 | "sysfs group %p not found for kobject '%s'\n", | 213 | "sysfs group %p not found for kobject '%s'\n", |
| @@ -218,7 +219,7 @@ void sysfs_remove_group(struct kobject *kobj, | |||
| 218 | 219 | ||
| 219 | remove_files(sd, kobj, grp); | 220 | remove_files(sd, kobj, grp); |
| 220 | if (grp->name) | 221 | if (grp->name) |
| 221 | sysfs_remove_subdir(sd); | 222 | sysfs_remove(sd); |
| 222 | 223 | ||
| 223 | sysfs_put(sd); | 224 | sysfs_put(sd); |
| 224 | } | 225 | } |
| @@ -261,7 +262,7 @@ int sysfs_merge_group(struct kobject *kobj, | |||
| 261 | struct attribute *const *attr; | 262 | struct attribute *const *attr; |
| 262 | int i; | 263 | int i; |
| 263 | 264 | ||
| 264 | dir_sd = sysfs_get_dirent(kobj->sd, NULL, grp->name); | 265 | dir_sd = sysfs_get_dirent(kobj->sd, grp->name); |
| 265 | if (!dir_sd) | 266 | if (!dir_sd) |
| 266 | return -ENOENT; | 267 | return -ENOENT; |
| 267 | 268 | ||
| @@ -269,7 +270,7 @@ int sysfs_merge_group(struct kobject *kobj, | |||
| 269 | error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR); | 270 | error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR); |
| 270 | if (error) { | 271 | if (error) { |
| 271 | while (--i >= 0) | 272 | while (--i >= 0) |
| 272 | sysfs_hash_and_remove(dir_sd, NULL, (*--attr)->name); | 273 | sysfs_hash_and_remove(dir_sd, (*--attr)->name, NULL); |
| 273 | } | 274 | } |
| 274 | sysfs_put(dir_sd); | 275 | sysfs_put(dir_sd); |
| 275 | 276 | ||
| @@ -288,10 +289,10 @@ void sysfs_unmerge_group(struct kobject *kobj, | |||
| 288 | struct sysfs_dirent *dir_sd; | 289 | struct sysfs_dirent *dir_sd; |
| 289 | struct attribute *const *attr; | 290 | struct attribute *const *attr; |
| 290 | 291 | ||
| 291 | dir_sd = sysfs_get_dirent(kobj->sd, NULL, grp->name); | 292 | dir_sd = sysfs_get_dirent(kobj->sd, grp->name); |
| 292 | if (dir_sd) { | 293 | if (dir_sd) { |
| 293 | for (attr = grp->attrs; *attr; ++attr) | 294 | for (attr = grp->attrs; *attr; ++attr) |
| 294 | sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name); | 295 | sysfs_hash_and_remove(dir_sd, (*attr)->name, NULL); |
| 295 | sysfs_put(dir_sd); | 296 | sysfs_put(dir_sd); |
| 296 | } | 297 | } |
| 297 | } | 298 | } |
| @@ -310,7 +311,7 @@ int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name, | |||
| 310 | struct sysfs_dirent *dir_sd; | 311 | struct sysfs_dirent *dir_sd; |
| 311 | int error = 0; | 312 | int error = 0; |
| 312 | 313 | ||
| 313 | dir_sd = sysfs_get_dirent(kobj->sd, NULL, group_name); | 314 | dir_sd = sysfs_get_dirent(kobj->sd, group_name); |
| 314 | if (!dir_sd) | 315 | if (!dir_sd) |
| 315 | return -ENOENT; | 316 | return -ENOENT; |
| 316 | 317 | ||
| @@ -332,9 +333,9 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, | |||
| 332 | { | 333 | { |
| 333 | struct sysfs_dirent *dir_sd; | 334 | struct sysfs_dirent *dir_sd; |
| 334 | 335 | ||
| 335 | dir_sd = sysfs_get_dirent(kobj->sd, NULL, group_name); | 336 | dir_sd = sysfs_get_dirent(kobj->sd, group_name); |
| 336 | if (dir_sd) { | 337 | if (dir_sd) { |
| 337 | sysfs_hash_and_remove(dir_sd, NULL, link_name); | 338 | sysfs_hash_and_remove(dir_sd, link_name, NULL); |
| 338 | sysfs_put(dir_sd); | 339 | sysfs_put(dir_sd); |
| 339 | } | 340 | } |
| 340 | } | 341 | } |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 963f910c8034..1750f790af3b 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
| @@ -258,9 +258,9 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | |||
| 258 | inode->i_fop = &sysfs_file_operations; | 258 | inode->i_fop = &sysfs_file_operations; |
| 259 | break; | 259 | break; |
| 260 | case SYSFS_KOBJ_BIN_ATTR: | 260 | case SYSFS_KOBJ_BIN_ATTR: |
| 261 | bin_attr = sd->s_bin_attr.bin_attr; | 261 | bin_attr = sd->s_attr.bin_attr; |
| 262 | inode->i_size = bin_attr->size; | 262 | inode->i_size = bin_attr->size; |
| 263 | inode->i_fop = &bin_fops; | 263 | inode->i_fop = &sysfs_bin_operations; |
| 264 | break; | 264 | break; |
| 265 | case SYSFS_KOBJ_LINK: | 265 | case SYSFS_KOBJ_LINK: |
| 266 | inode->i_op = &sysfs_symlink_inode_operations; | 266 | inode->i_op = &sysfs_symlink_inode_operations; |
| @@ -314,32 +314,6 @@ void sysfs_evict_inode(struct inode *inode) | |||
| 314 | sysfs_put(sd); | 314 | sysfs_put(sd); |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, | ||
| 318 | const char *name) | ||
| 319 | { | ||
| 320 | struct sysfs_addrm_cxt acxt; | ||
| 321 | struct sysfs_dirent *sd; | ||
| 322 | |||
| 323 | if (!dir_sd) { | ||
| 324 | WARN(1, KERN_WARNING "sysfs: can not remove '%s', no directory\n", | ||
| 325 | name); | ||
| 326 | return -ENOENT; | ||
| 327 | } | ||
| 328 | |||
| 329 | sysfs_addrm_start(&acxt, dir_sd); | ||
| 330 | |||
| 331 | sd = sysfs_find_dirent(dir_sd, ns, name); | ||
| 332 | if (sd) | ||
| 333 | sysfs_remove_one(&acxt, sd); | ||
| 334 | |||
| 335 | sysfs_addrm_finish(&acxt); | ||
| 336 | |||
| 337 | if (sd) | ||
| 338 | return 0; | ||
| 339 | else | ||
| 340 | return -ENOENT; | ||
| 341 | } | ||
| 342 | |||
| 343 | int sysfs_permission(struct inode *inode, int mask) | 317 | int sysfs_permission(struct inode *inode, int mask) |
| 344 | { | 318 | { |
| 345 | struct sysfs_dirent *sd; | 319 | struct sysfs_dirent *sd; |
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 834ec2cdb7a3..8c24bce2f4ae 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
| @@ -36,7 +36,7 @@ static const struct super_operations sysfs_ops = { | |||
| 36 | struct sysfs_dirent sysfs_root = { | 36 | struct sysfs_dirent sysfs_root = { |
| 37 | .s_name = "", | 37 | .s_name = "", |
| 38 | .s_count = ATOMIC_INIT(1), | 38 | .s_count = ATOMIC_INIT(1), |
| 39 | .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), | 39 | .s_flags = SYSFS_DIR, |
| 40 | .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, | 40 | .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, |
| 41 | .s_ino = 1, | 41 | .s_ino = 1, |
| 42 | }; | 42 | }; |
| @@ -77,14 +77,8 @@ static int sysfs_test_super(struct super_block *sb, void *data) | |||
| 77 | { | 77 | { |
| 78 | struct sysfs_super_info *sb_info = sysfs_info(sb); | 78 | struct sysfs_super_info *sb_info = sysfs_info(sb); |
| 79 | struct sysfs_super_info *info = data; | 79 | struct sysfs_super_info *info = data; |
| 80 | enum kobj_ns_type type; | ||
| 81 | int found = 1; | ||
| 82 | 80 | ||
| 83 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { | 81 | return sb_info->ns == info->ns; |
| 84 | if (sb_info->ns[type] != info->ns[type]) | ||
| 85 | found = 0; | ||
| 86 | } | ||
| 87 | return found; | ||
| 88 | } | 82 | } |
| 89 | 83 | ||
| 90 | static int sysfs_set_super(struct super_block *sb, void *data) | 84 | static int sysfs_set_super(struct super_block *sb, void *data) |
| @@ -98,9 +92,7 @@ static int sysfs_set_super(struct super_block *sb, void *data) | |||
| 98 | 92 | ||
| 99 | static void free_sysfs_super_info(struct sysfs_super_info *info) | 93 | static void free_sysfs_super_info(struct sysfs_super_info *info) |
| 100 | { | 94 | { |
| 101 | int type; | 95 | kobj_ns_drop(KOBJ_NS_TYPE_NET, info->ns); |
| 102 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) | ||
| 103 | kobj_ns_drop(type, info->ns[type]); | ||
| 104 | kfree(info); | 96 | kfree(info); |
| 105 | } | 97 | } |
| 106 | 98 | ||
| @@ -108,7 +100,6 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
| 108 | int flags, const char *dev_name, void *data) | 100 | int flags, const char *dev_name, void *data) |
| 109 | { | 101 | { |
| 110 | struct sysfs_super_info *info; | 102 | struct sysfs_super_info *info; |
| 111 | enum kobj_ns_type type; | ||
| 112 | struct super_block *sb; | 103 | struct super_block *sb; |
| 113 | int error; | 104 | int error; |
| 114 | 105 | ||
| @@ -116,18 +107,15 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
| 116 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) | 107 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) |
| 117 | return ERR_PTR(-EPERM); | 108 | return ERR_PTR(-EPERM); |
| 118 | 109 | ||
| 119 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { | 110 | if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) |
| 120 | if (!kobj_ns_current_may_mount(type)) | 111 | return ERR_PTR(-EPERM); |
| 121 | return ERR_PTR(-EPERM); | ||
| 122 | } | ||
| 123 | } | 112 | } |
| 124 | 113 | ||
| 125 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 114 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
| 126 | if (!info) | 115 | if (!info) |
| 127 | return ERR_PTR(-ENOMEM); | 116 | return ERR_PTR(-ENOMEM); |
| 128 | 117 | ||
| 129 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) | 118 | info->ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); |
| 130 | info->ns[type] = kobj_ns_grab_current(type); | ||
| 131 | 119 | ||
| 132 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); | 120 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); |
| 133 | if (IS_ERR(sb) || sb->s_fs_info != info) | 121 | if (IS_ERR(sb) || sb->s_fs_info != info) |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 2dd4507d9edd..1a23681b8179 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
| @@ -28,18 +28,19 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, | |||
| 28 | struct sysfs_dirent *target_sd = NULL; | 28 | struct sysfs_dirent *target_sd = NULL; |
| 29 | struct sysfs_dirent *sd = NULL; | 29 | struct sysfs_dirent *sd = NULL; |
| 30 | struct sysfs_addrm_cxt acxt; | 30 | struct sysfs_addrm_cxt acxt; |
| 31 | enum kobj_ns_type ns_type; | ||
| 32 | int error; | 31 | int error; |
| 33 | 32 | ||
| 34 | BUG_ON(!name || !parent_sd); | 33 | BUG_ON(!name || !parent_sd); |
| 35 | 34 | ||
| 36 | /* target->sd can go away beneath us but is protected with | 35 | /* |
| 37 | * sysfs_assoc_lock. Fetch target_sd from it. | 36 | * We don't own @target and it may be removed at any time. |
| 37 | * Synchronize using sysfs_symlink_target_lock. See | ||
| 38 | * sysfs_remove_dir() for details. | ||
| 38 | */ | 39 | */ |
| 39 | spin_lock(&sysfs_assoc_lock); | 40 | spin_lock(&sysfs_symlink_target_lock); |
| 40 | if (target->sd) | 41 | if (target->sd) |
| 41 | target_sd = sysfs_get(target->sd); | 42 | target_sd = sysfs_get(target->sd); |
| 42 | spin_unlock(&sysfs_assoc_lock); | 43 | spin_unlock(&sysfs_symlink_target_lock); |
| 43 | 44 | ||
| 44 | error = -ENOENT; | 45 | error = -ENOENT; |
| 45 | if (!target_sd) | 46 | if (!target_sd) |
| @@ -50,29 +51,15 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, | |||
| 50 | if (!sd) | 51 | if (!sd) |
| 51 | goto out_put; | 52 | goto out_put; |
| 52 | 53 | ||
| 53 | ns_type = sysfs_ns_type(parent_sd); | 54 | sd->s_ns = target_sd->s_ns; |
| 54 | if (ns_type) | ||
| 55 | sd->s_ns = target->ktype->namespace(target); | ||
| 56 | sd->s_symlink.target_sd = target_sd; | 55 | sd->s_symlink.target_sd = target_sd; |
| 57 | target_sd = NULL; /* reference is now owned by the symlink */ | 56 | target_sd = NULL; /* reference is now owned by the symlink */ |
| 58 | 57 | ||
| 59 | sysfs_addrm_start(&acxt, parent_sd); | 58 | sysfs_addrm_start(&acxt); |
| 60 | /* Symlinks must be between directories with the same ns_type */ | 59 | if (warn) |
| 61 | if (!ns_type || | 60 | error = sysfs_add_one(&acxt, sd, parent_sd); |
| 62 | (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { | 61 | else |
| 63 | if (warn) | 62 | error = __sysfs_add_one(&acxt, sd, parent_sd); |
| 64 | error = sysfs_add_one(&acxt, sd); | ||
| 65 | else | ||
| 66 | error = __sysfs_add_one(&acxt, sd); | ||
| 67 | } else { | ||
| 68 | error = -EINVAL; | ||
| 69 | WARN(1, KERN_WARNING | ||
| 70 | "sysfs: symlink across ns_types %s/%s -> %s/%s\n", | ||
| 71 | parent_sd->s_name, | ||
| 72 | sd->s_name, | ||
| 73 | sd->s_symlink.target_sd->s_parent->s_name, | ||
| 74 | sd->s_symlink.target_sd->s_name); | ||
| 75 | } | ||
| 76 | sysfs_addrm_finish(&acxt); | 63 | sysfs_addrm_finish(&acxt); |
| 77 | 64 | ||
| 78 | if (error) | 65 | if (error) |
| @@ -155,11 +142,17 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, | |||
| 155 | const char *name) | 142 | const char *name) |
| 156 | { | 143 | { |
| 157 | const void *ns = NULL; | 144 | const void *ns = NULL; |
| 158 | spin_lock(&sysfs_assoc_lock); | 145 | |
| 159 | if (targ->sd && sysfs_ns_type(kobj->sd)) | 146 | /* |
| 147 | * We don't own @target and it may be removed at any time. | ||
| 148 | * Synchronize using sysfs_symlink_target_lock. See | ||
| 149 | * sysfs_remove_dir() for details. | ||
| 150 | */ | ||
| 151 | spin_lock(&sysfs_symlink_target_lock); | ||
| 152 | if (targ->sd) | ||
| 160 | ns = targ->sd->s_ns; | 153 | ns = targ->sd->s_ns; |
| 161 | spin_unlock(&sysfs_assoc_lock); | 154 | spin_unlock(&sysfs_symlink_target_lock); |
| 162 | sysfs_hash_and_remove(kobj->sd, ns, name); | 155 | sysfs_hash_and_remove(kobj->sd, name, ns); |
| 163 | } | 156 | } |
| 164 | 157 | ||
| 165 | /** | 158 | /** |
| @@ -176,24 +169,25 @@ void sysfs_remove_link(struct kobject *kobj, const char *name) | |||
| 176 | else | 169 | else |
| 177 | parent_sd = kobj->sd; | 170 | parent_sd = kobj->sd; |
| 178 | 171 | ||
| 179 | sysfs_hash_and_remove(parent_sd, NULL, name); | 172 | sysfs_hash_and_remove(parent_sd, name, NULL); |
| 180 | } | 173 | } |
| 181 | EXPORT_SYMBOL_GPL(sysfs_remove_link); | 174 | EXPORT_SYMBOL_GPL(sysfs_remove_link); |
| 182 | 175 | ||
| 183 | /** | 176 | /** |
| 184 | * sysfs_rename_link - rename symlink in object's directory. | 177 | * sysfs_rename_link_ns - rename symlink in object's directory. |
| 185 | * @kobj: object we're acting for. | 178 | * @kobj: object we're acting for. |
| 186 | * @targ: object we're pointing to. | 179 | * @targ: object we're pointing to. |
| 187 | * @old: previous name of the symlink. | 180 | * @old: previous name of the symlink. |
| 188 | * @new: new name of the symlink. | 181 | * @new: new name of the symlink. |
| 182 | * @new_ns: new namespace of the symlink. | ||
| 189 | * | 183 | * |
| 190 | * A helper function for the common rename symlink idiom. | 184 | * A helper function for the common rename symlink idiom. |
| 191 | */ | 185 | */ |
| 192 | int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, | 186 | int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, |
| 193 | const char *old, const char *new) | 187 | const char *old, const char *new, const void *new_ns) |
| 194 | { | 188 | { |
| 195 | struct sysfs_dirent *parent_sd, *sd = NULL; | 189 | struct sysfs_dirent *parent_sd, *sd = NULL; |
| 196 | const void *old_ns = NULL, *new_ns = NULL; | 190 | const void *old_ns = NULL; |
| 197 | int result; | 191 | int result; |
| 198 | 192 | ||
| 199 | if (!kobj) | 193 | if (!kobj) |
| @@ -205,7 +199,7 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, | |||
| 205 | old_ns = targ->sd->s_ns; | 199 | old_ns = targ->sd->s_ns; |
| 206 | 200 | ||
| 207 | result = -ENOENT; | 201 | result = -ENOENT; |
| 208 | sd = sysfs_get_dirent(parent_sd, old_ns, old); | 202 | sd = sysfs_get_dirent_ns(parent_sd, old, old_ns); |
| 209 | if (!sd) | 203 | if (!sd) |
| 210 | goto out; | 204 | goto out; |
| 211 | 205 | ||
| @@ -215,16 +209,13 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, | |||
| 215 | if (sd->s_symlink.target_sd->s_dir.kobj != targ) | 209 | if (sd->s_symlink.target_sd->s_dir.kobj != targ) |
| 216 | goto out; | 210 | goto out; |
| 217 | 211 | ||
| 218 | if (sysfs_ns_type(parent_sd)) | 212 | result = sysfs_rename(sd, parent_sd, new, new_ns); |
| 219 | new_ns = targ->ktype->namespace(targ); | ||
| 220 | |||
| 221 | result = sysfs_rename(sd, parent_sd, new_ns, new); | ||
| 222 | 213 | ||
| 223 | out: | 214 | out: |
| 224 | sysfs_put(sd); | 215 | sysfs_put(sd); |
| 225 | return result; | 216 | return result; |
| 226 | } | 217 | } |
| 227 | EXPORT_SYMBOL_GPL(sysfs_rename_link); | 218 | EXPORT_SYMBOL_GPL(sysfs_rename_link_ns); |
| 228 | 219 | ||
| 229 | static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, | 220 | static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, |
| 230 | struct sysfs_dirent *target_sd, char *path) | 221 | struct sysfs_dirent *target_sd, char *path) |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index b6deca3e301d..e3aea92ebfa3 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
| @@ -29,15 +29,13 @@ struct sysfs_elem_symlink { | |||
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | struct sysfs_elem_attr { | 31 | struct sysfs_elem_attr { |
| 32 | struct attribute *attr; | 32 | union { |
| 33 | struct attribute *attr; | ||
| 34 | struct bin_attribute *bin_attr; | ||
| 35 | }; | ||
| 33 | struct sysfs_open_dirent *open; | 36 | struct sysfs_open_dirent *open; |
| 34 | }; | 37 | }; |
| 35 | 38 | ||
| 36 | struct sysfs_elem_bin_attr { | ||
| 37 | struct bin_attribute *bin_attr; | ||
| 38 | struct hlist_head buffers; | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct sysfs_inode_attrs { | 39 | struct sysfs_inode_attrs { |
| 42 | struct iattr ia_iattr; | 40 | struct iattr ia_iattr; |
| 43 | void *ia_secdata; | 41 | void *ia_secdata; |
| @@ -74,7 +72,6 @@ struct sysfs_dirent { | |||
| 74 | struct sysfs_elem_dir s_dir; | 72 | struct sysfs_elem_dir s_dir; |
| 75 | struct sysfs_elem_symlink s_symlink; | 73 | struct sysfs_elem_symlink s_symlink; |
| 76 | struct sysfs_elem_attr s_attr; | 74 | struct sysfs_elem_attr s_attr; |
| 77 | struct sysfs_elem_bin_attr s_bin_attr; | ||
| 78 | }; | 75 | }; |
| 79 | 76 | ||
| 80 | unsigned short s_flags; | 77 | unsigned short s_flags; |
| @@ -93,11 +90,8 @@ struct sysfs_dirent { | |||
| 93 | #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) | 90 | #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) |
| 94 | #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) | 91 | #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) |
| 95 | 92 | ||
| 96 | /* identify any namespace tag on sysfs_dirents */ | 93 | #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK |
| 97 | #define SYSFS_NS_TYPE_MASK 0xf00 | 94 | #define SYSFS_FLAG_HAS_NS 0x01000 |
| 98 | #define SYSFS_NS_TYPE_SHIFT 8 | ||
| 99 | |||
| 100 | #define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK) | ||
| 101 | #define SYSFS_FLAG_REMOVED 0x02000 | 95 | #define SYSFS_FLAG_REMOVED 0x02000 |
| 102 | 96 | ||
| 103 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | 97 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) |
| @@ -105,16 +99,8 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | |||
| 105 | return sd->s_flags & SYSFS_TYPE_MASK; | 99 | return sd->s_flags & SYSFS_TYPE_MASK; |
| 106 | } | 100 | } |
| 107 | 101 | ||
| 108 | /* | ||
| 109 | * Return any namespace tags on this dirent. | ||
| 110 | * enum kobj_ns_type is defined in linux/kobject.h | ||
| 111 | */ | ||
| 112 | static inline enum kobj_ns_type sysfs_ns_type(struct sysfs_dirent *sd) | ||
| 113 | { | ||
| 114 | return (sd->s_flags & SYSFS_NS_TYPE_MASK) >> SYSFS_NS_TYPE_SHIFT; | ||
| 115 | } | ||
| 116 | |||
| 117 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 102 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
| 103 | |||
| 118 | #define sysfs_dirent_init_lockdep(sd) \ | 104 | #define sysfs_dirent_init_lockdep(sd) \ |
| 119 | do { \ | 105 | do { \ |
| 120 | struct attribute *attr = sd->s_attr.attr; \ | 106 | struct attribute *attr = sd->s_attr.attr; \ |
| @@ -124,15 +110,31 @@ do { \ | |||
| 124 | \ | 110 | \ |
| 125 | lockdep_init_map(&sd->dep_map, "s_active", key, 0); \ | 111 | lockdep_init_map(&sd->dep_map, "s_active", key, 0); \ |
| 126 | } while (0) | 112 | } while (0) |
| 113 | |||
| 114 | /* Test for attributes that want to ignore lockdep for read-locking */ | ||
| 115 | static inline bool sysfs_ignore_lockdep(struct sysfs_dirent *sd) | ||
| 116 | { | ||
| 117 | int type = sysfs_type(sd); | ||
| 118 | |||
| 119 | return (type == SYSFS_KOBJ_ATTR || type == SYSFS_KOBJ_BIN_ATTR) && | ||
| 120 | sd->s_attr.attr->ignore_lockdep; | ||
| 121 | } | ||
| 122 | |||
| 127 | #else | 123 | #else |
| 124 | |||
| 128 | #define sysfs_dirent_init_lockdep(sd) do {} while (0) | 125 | #define sysfs_dirent_init_lockdep(sd) do {} while (0) |
| 126 | |||
| 127 | static inline bool sysfs_ignore_lockdep(struct sysfs_dirent *sd) | ||
| 128 | { | ||
| 129 | return true; | ||
| 130 | } | ||
| 131 | |||
| 129 | #endif | 132 | #endif |
| 130 | 133 | ||
| 131 | /* | 134 | /* |
| 132 | * Context structure to be used while adding/removing nodes. | 135 | * Context structure to be used while adding/removing nodes. |
| 133 | */ | 136 | */ |
| 134 | struct sysfs_addrm_cxt { | 137 | struct sysfs_addrm_cxt { |
| 135 | struct sysfs_dirent *parent_sd; | ||
| 136 | struct sysfs_dirent *removed; | 138 | struct sysfs_dirent *removed; |
| 137 | }; | 139 | }; |
| 138 | 140 | ||
| @@ -141,12 +143,13 @@ struct sysfs_addrm_cxt { | |||
| 141 | */ | 143 | */ |
| 142 | 144 | ||
| 143 | /* | 145 | /* |
| 144 | * Each sb is associated with a set of namespace tags (i.e. | 146 | * Each sb is associated with one namespace tag, currently the network |
| 145 | * the network namespace of the task which mounted this sysfs | 147 | * namespace of the task which mounted this sysfs instance. If multiple |
| 146 | * instance). | 148 | * tags become necessary, make the following an array and compare |
| 149 | * sysfs_dirent tag against every entry. | ||
| 147 | */ | 150 | */ |
| 148 | struct sysfs_super_info { | 151 | struct sysfs_super_info { |
| 149 | void *ns[KOBJ_NS_TYPES]; | 152 | void *ns; |
| 150 | }; | 153 | }; |
| 151 | #define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) | 154 | #define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) |
| 152 | extern struct sysfs_dirent sysfs_root; | 155 | extern struct sysfs_dirent sysfs_root; |
| @@ -156,38 +159,37 @@ extern struct kmem_cache *sysfs_dir_cachep; | |||
| 156 | * dir.c | 159 | * dir.c |
| 157 | */ | 160 | */ |
| 158 | extern struct mutex sysfs_mutex; | 161 | extern struct mutex sysfs_mutex; |
| 159 | extern spinlock_t sysfs_assoc_lock; | 162 | extern spinlock_t sysfs_symlink_target_lock; |
| 160 | extern const struct dentry_operations sysfs_dentry_ops; | 163 | extern const struct dentry_operations sysfs_dentry_ops; |
| 161 | 164 | ||
| 162 | extern const struct file_operations sysfs_dir_operations; | 165 | extern const struct file_operations sysfs_dir_operations; |
| 163 | extern const struct inode_operations sysfs_dir_inode_operations; | 166 | extern const struct inode_operations sysfs_dir_inode_operations; |
| 164 | 167 | ||
| 165 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); | ||
| 166 | struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); | 168 | struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); |
| 167 | void sysfs_put_active(struct sysfs_dirent *sd); | 169 | void sysfs_put_active(struct sysfs_dirent *sd); |
| 168 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | 170 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt); |
| 169 | struct sysfs_dirent *parent_sd); | 171 | void sysfs_warn_dup(struct sysfs_dirent *parent, const char *name); |
| 170 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); | 172 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, |
| 171 | int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); | 173 | struct sysfs_dirent *parent_sd); |
| 172 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); | 174 | int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, |
| 175 | struct sysfs_dirent *parent_sd); | ||
| 176 | void sysfs_remove(struct sysfs_dirent *sd); | ||
| 177 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name, | ||
| 178 | const void *ns); | ||
| 173 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); | 179 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); |
| 174 | 180 | ||
| 175 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | 181 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, |
| 176 | const void *ns, | 182 | const unsigned char *name, |
| 177 | const unsigned char *name); | 183 | const void *ns); |
| 178 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | ||
| 179 | const void *ns, | ||
| 180 | const unsigned char *name); | ||
| 181 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); | 184 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); |
| 182 | 185 | ||
| 183 | void release_sysfs_dirent(struct sysfs_dirent *sd); | 186 | void release_sysfs_dirent(struct sysfs_dirent *sd); |
| 184 | 187 | ||
| 185 | int sysfs_create_subdir(struct kobject *kobj, const char *name, | 188 | int sysfs_create_subdir(struct kobject *kobj, const char *name, |
| 186 | struct sysfs_dirent **p_sd); | 189 | struct sysfs_dirent **p_sd); |
| 187 | void sysfs_remove_subdir(struct sysfs_dirent *sd); | ||
| 188 | 190 | ||
| 189 | int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd, | 191 | int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd, |
| 190 | const void *ns, const char *new_name); | 192 | const char *new_name, const void *new_ns); |
| 191 | 193 | ||
| 192 | static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) | 194 | static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) |
| 193 | { | 195 | { |
| @@ -218,25 +220,21 @@ int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
| 218 | struct kstat *stat); | 220 | struct kstat *stat); |
| 219 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 221 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
| 220 | size_t size, int flags); | 222 | size_t size, int flags); |
| 221 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, | ||
| 222 | const char *name); | ||
| 223 | int sysfs_inode_init(void); | 223 | int sysfs_inode_init(void); |
| 224 | 224 | ||
| 225 | /* | 225 | /* |
| 226 | * file.c | 226 | * file.c |
| 227 | */ | 227 | */ |
| 228 | extern const struct file_operations sysfs_file_operations; | 228 | extern const struct file_operations sysfs_file_operations; |
| 229 | extern const struct file_operations sysfs_bin_operations; | ||
| 229 | 230 | ||
| 230 | int sysfs_add_file(struct sysfs_dirent *dir_sd, | 231 | int sysfs_add_file(struct sysfs_dirent *dir_sd, |
| 231 | const struct attribute *attr, int type); | 232 | const struct attribute *attr, int type); |
| 232 | 233 | ||
| 233 | int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, | 234 | int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, |
| 234 | const struct attribute *attr, int type, umode_t amode); | 235 | const struct attribute *attr, int type, |
| 235 | /* | 236 | umode_t amode, const void *ns); |
| 236 | * bin.c | 237 | void sysfs_unmap_bin_file(struct sysfs_dirent *sd); |
| 237 | */ | ||
| 238 | extern const struct file_operations bin_fops; | ||
| 239 | void unmap_bin_file(struct sysfs_dirent *attr_sd); | ||
| 240 | 238 | ||
| 241 | /* | 239 | /* |
| 242 | * symlink.c | 240 | * symlink.c |
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 263489d0788d..4d0b4d1aa132 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h | |||
| @@ -206,6 +206,12 @@ static inline struct dentry *debugfs_create_size_t(const char *name, umode_t mod | |||
| 206 | return ERR_PTR(-ENODEV); | 206 | return ERR_PTR(-ENODEV); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | static inline struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode, | ||
| 210 | struct dentry *parent, atomic_t *value) | ||
| 211 | { | ||
| 212 | return ERR_PTR(-ENODEV); | ||
| 213 | } | ||
| 214 | |||
| 209 | static inline struct dentry *debugfs_create_bool(const char *name, umode_t mode, | 215 | static inline struct dentry *debugfs_create_bool(const char *name, umode_t mode, |
| 210 | struct dentry *parent, | 216 | struct dentry *parent, |
| 211 | u32 *value) | 217 | u32 *value) |
| @@ -227,6 +233,12 @@ static inline struct dentry *debugfs_create_regset32(const char *name, | |||
| 227 | return ERR_PTR(-ENODEV); | 233 | return ERR_PTR(-ENODEV); |
| 228 | } | 234 | } |
| 229 | 235 | ||
| 236 | static inline int debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, | ||
| 237 | int nregs, void __iomem *base, char *prefix) | ||
| 238 | { | ||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | |||
| 230 | static inline bool debugfs_initialized(void) | 242 | static inline bool debugfs_initialized(void) |
| 231 | { | 243 | { |
| 232 | return false; | 244 | return false; |
diff --git a/include/linux/device.h b/include/linux/device.h index 2a9d6ed59579..b025925df7f7 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/atomic.h> | 26 | #include <linux/atomic.h> |
| 27 | #include <linux/ratelimit.h> | 27 | #include <linux/ratelimit.h> |
| 28 | #include <linux/uidgid.h> | 28 | #include <linux/uidgid.h> |
| 29 | #include <linux/gfp.h> | ||
| 29 | #include <asm/device.h> | 30 | #include <asm/device.h> |
| 30 | 31 | ||
| 31 | struct device; | 32 | struct device; |
| @@ -63,9 +64,7 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *); | |||
| 63 | * @name: The name of the bus. | 64 | * @name: The name of the bus. |
| 64 | * @dev_name: Used for subsystems to enumerate devices like ("foo%u", dev->id). | 65 | * @dev_name: Used for subsystems to enumerate devices like ("foo%u", dev->id). |
| 65 | * @dev_root: Default device to use as the parent. | 66 | * @dev_root: Default device to use as the parent. |
| 66 | * @bus_attrs: Default attributes of the bus. | ||
| 67 | * @dev_attrs: Default attributes of the devices on the bus. | 67 | * @dev_attrs: Default attributes of the devices on the bus. |
| 68 | * @drv_attrs: Default attributes of the device drivers on the bus. | ||
| 69 | * @bus_groups: Default attributes of the bus. | 68 | * @bus_groups: Default attributes of the bus. |
| 70 | * @dev_groups: Default attributes of the devices on the bus. | 69 | * @dev_groups: Default attributes of the devices on the bus. |
| 71 | * @drv_groups: Default attributes of the device drivers on the bus. | 70 | * @drv_groups: Default attributes of the device drivers on the bus. |
| @@ -106,9 +105,7 @@ struct bus_type { | |||
| 106 | const char *name; | 105 | const char *name; |
| 107 | const char *dev_name; | 106 | const char *dev_name; |
| 108 | struct device *dev_root; | 107 | struct device *dev_root; |
| 109 | struct bus_attribute *bus_attrs; /* use bus_groups instead */ | ||
| 110 | struct device_attribute *dev_attrs; /* use dev_groups instead */ | 108 | struct device_attribute *dev_attrs; /* use dev_groups instead */ |
| 111 | struct driver_attribute *drv_attrs; /* use drv_groups instead */ | ||
| 112 | const struct attribute_group **bus_groups; | 109 | const struct attribute_group **bus_groups; |
| 113 | const struct attribute_group **dev_groups; | 110 | const struct attribute_group **dev_groups; |
| 114 | const struct attribute_group **drv_groups; | 111 | const struct attribute_group **drv_groups; |
| @@ -329,8 +326,6 @@ int subsys_virtual_register(struct bus_type *subsys, | |||
| 329 | * @owner: The module owner. | 326 | * @owner: The module owner. |
| 330 | * @class_attrs: Default attributes of this class. | 327 | * @class_attrs: Default attributes of this class. |
| 331 | * @dev_groups: Default attributes of the devices that belong to the class. | 328 | * @dev_groups: Default attributes of the devices that belong to the class. |
| 332 | * @dev_attrs: Default attributes of the devices belong to the class. | ||
| 333 | * @dev_bin_attrs: Default binary attributes of the devices belong to the class. | ||
| 334 | * @dev_kobj: The kobject that represents this class and links it into the hierarchy. | 329 | * @dev_kobj: The kobject that represents this class and links it into the hierarchy. |
| 335 | * @dev_uevent: Called when a device is added, removed from this class, or a | 330 | * @dev_uevent: Called when a device is added, removed from this class, or a |
| 336 | * few other things that generate uevents to add the environment | 331 | * few other things that generate uevents to add the environment |
| @@ -358,9 +353,7 @@ struct class { | |||
| 358 | struct module *owner; | 353 | struct module *owner; |
| 359 | 354 | ||
| 360 | struct class_attribute *class_attrs; | 355 | struct class_attribute *class_attrs; |
| 361 | struct device_attribute *dev_attrs; /* use dev_groups instead */ | ||
| 362 | const struct attribute_group **dev_groups; | 356 | const struct attribute_group **dev_groups; |
| 363 | struct bin_attribute *dev_bin_attrs; | ||
| 364 | struct kobject *dev_kobj; | 357 | struct kobject *dev_kobj; |
| 365 | 358 | ||
| 366 | int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); | 359 | int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); |
| @@ -427,8 +420,6 @@ struct class_attribute { | |||
| 427 | char *buf); | 420 | char *buf); |
| 428 | ssize_t (*store)(struct class *class, struct class_attribute *attr, | 421 | ssize_t (*store)(struct class *class, struct class_attribute *attr, |
| 429 | const char *buf, size_t count); | 422 | const char *buf, size_t count); |
| 430 | const void *(*namespace)(struct class *class, | ||
| 431 | const struct class_attribute *attr); | ||
| 432 | }; | 423 | }; |
| 433 | 424 | ||
| 434 | #define CLASS_ATTR(_name, _mode, _show, _store) \ | 425 | #define CLASS_ATTR(_name, _mode, _show, _store) \ |
| @@ -438,10 +429,24 @@ struct class_attribute { | |||
| 438 | #define CLASS_ATTR_RO(_name) \ | 429 | #define CLASS_ATTR_RO(_name) \ |
| 439 | struct class_attribute class_attr_##_name = __ATTR_RO(_name) | 430 | struct class_attribute class_attr_##_name = __ATTR_RO(_name) |
| 440 | 431 | ||
| 441 | extern int __must_check class_create_file(struct class *class, | 432 | extern int __must_check class_create_file_ns(struct class *class, |
| 442 | const struct class_attribute *attr); | 433 | const struct class_attribute *attr, |
| 443 | extern void class_remove_file(struct class *class, | 434 | const void *ns); |
| 444 | const struct class_attribute *attr); | 435 | extern void class_remove_file_ns(struct class *class, |
| 436 | const struct class_attribute *attr, | ||
| 437 | const void *ns); | ||
| 438 | |||
| 439 | static inline int __must_check class_create_file(struct class *class, | ||
| 440 | const struct class_attribute *attr) | ||
| 441 | { | ||
| 442 | return class_create_file_ns(class, attr, NULL); | ||
| 443 | } | ||
| 444 | |||
| 445 | static inline void class_remove_file(struct class *class, | ||
| 446 | const struct class_attribute *attr) | ||
| 447 | { | ||
| 448 | return class_remove_file_ns(class, attr, NULL); | ||
| 449 | } | ||
| 445 | 450 | ||
| 446 | /* Simple class attribute that is just a static string */ | 451 | /* Simple class attribute that is just a static string */ |
| 447 | struct class_attribute_string { | 452 | struct class_attribute_string { |
| @@ -602,8 +607,24 @@ extern void devres_close_group(struct device *dev, void *id); | |||
| 602 | extern void devres_remove_group(struct device *dev, void *id); | 607 | extern void devres_remove_group(struct device *dev, void *id); |
| 603 | extern int devres_release_group(struct device *dev, void *id); | 608 | extern int devres_release_group(struct device *dev, void *id); |
| 604 | 609 | ||
| 605 | /* managed kzalloc/kfree for device drivers, no kmalloc, always use kzalloc */ | 610 | /* managed devm_k.alloc/kfree for device drivers */ |
| 606 | extern void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp); | 611 | extern void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp); |
| 612 | static inline void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) | ||
| 613 | { | ||
| 614 | return devm_kmalloc(dev, size, gfp | __GFP_ZERO); | ||
| 615 | } | ||
| 616 | static inline void *devm_kmalloc_array(struct device *dev, | ||
| 617 | size_t n, size_t size, gfp_t flags) | ||
| 618 | { | ||
| 619 | if (size != 0 && n > SIZE_MAX / size) | ||
| 620 | return NULL; | ||
| 621 | return devm_kmalloc(dev, n * size, flags); | ||
| 622 | } | ||
| 623 | static inline void *devm_kcalloc(struct device *dev, | ||
| 624 | size_t n, size_t size, gfp_t flags) | ||
| 625 | { | ||
| 626 | return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO); | ||
| 627 | } | ||
| 607 | extern void devm_kfree(struct device *dev, void *p); | 628 | extern void devm_kfree(struct device *dev, void *p); |
| 608 | 629 | ||
| 609 | void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res); | 630 | void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res); |
| @@ -1149,16 +1170,15 @@ do { \ | |||
| 1149 | #endif | 1170 | #endif |
| 1150 | 1171 | ||
| 1151 | /* | 1172 | /* |
| 1152 | * dev_WARN*() acts like dev_printk(), but with the key difference | 1173 | * dev_WARN*() acts like dev_printk(), but with the key difference of |
| 1153 | * of using a WARN/WARN_ON to get the message out, including the | 1174 | * using WARN/WARN_ONCE to include file/line information and a backtrace. |
| 1154 | * file/line information and a backtrace. | ||
| 1155 | */ | 1175 | */ |
| 1156 | #define dev_WARN(dev, format, arg...) \ | 1176 | #define dev_WARN(dev, format, arg...) \ |
| 1157 | WARN(1, "Device: %s\n" format, dev_driver_string(dev), ## arg); | 1177 | WARN(1, "%s %s: " format, dev_driver_string(dev), dev_name(dev), ## arg); |
| 1158 | 1178 | ||
| 1159 | #define dev_WARN_ONCE(dev, condition, format, arg...) \ | 1179 | #define dev_WARN_ONCE(dev, condition, format, arg...) \ |
| 1160 | WARN_ONCE(condition, "Device %s\n" format, \ | 1180 | WARN_ONCE(condition, "%s %s: " format, \ |
| 1161 | dev_driver_string(dev), ## arg) | 1181 | dev_driver_string(dev), dev_name(dev), ## arg) |
| 1162 | 1182 | ||
| 1163 | /* Create alias, so I can be autoloaded. */ | 1183 | /* Create alias, so I can be autoloaded. */ |
| 1164 | #define MODULE_ALIAS_CHARDEV(major,minor) \ | 1184 | #define MODULE_ALIAS_CHARDEV(major,minor) \ |
diff --git a/include/linux/ide.h b/include/linux/ide.h index b17974917dbf..46a14229a162 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h | |||
| @@ -1514,7 +1514,7 @@ static inline void ide_set_max_pio(ide_drive_t *drive) | |||
| 1514 | 1514 | ||
| 1515 | char *ide_media_string(ide_drive_t *); | 1515 | char *ide_media_string(ide_drive_t *); |
| 1516 | 1516 | ||
| 1517 | extern struct device_attribute ide_dev_attrs[]; | 1517 | extern const struct attribute_group *ide_dev_groups[]; |
| 1518 | extern struct bus_type ide_bus_type; | 1518 | extern struct bus_type ide_bus_type; |
| 1519 | extern struct class *ide_port_class; | 1519 | extern struct class *ide_port_class; |
| 1520 | 1520 | ||
diff --git a/include/linux/kobj_completion.h b/include/linux/kobj_completion.h new file mode 100644 index 000000000000..a428f6436063 --- /dev/null +++ b/include/linux/kobj_completion.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | #ifndef _KOBJ_COMPLETION_H_ | ||
| 2 | #define _KOBJ_COMPLETION_H_ | ||
| 3 | |||
| 4 | #include <linux/kobject.h> | ||
| 5 | #include <linux/completion.h> | ||
| 6 | |||
| 7 | struct kobj_completion { | ||
| 8 | struct kobject kc_kobj; | ||
| 9 | struct completion kc_unregister; | ||
| 10 | }; | ||
| 11 | |||
| 12 | #define kobj_to_kobj_completion(kobj) \ | ||
| 13 | container_of(kobj, struct kobj_completion, kc_kobj) | ||
| 14 | |||
| 15 | void kobj_completion_init(struct kobj_completion *kc, struct kobj_type *ktype); | ||
| 16 | void kobj_completion_release(struct kobject *kobj); | ||
| 17 | void kobj_completion_del_and_wait(struct kobj_completion *kc); | ||
| 18 | #endif /* _KOBJ_COMPLETION_H_ */ | ||
diff --git a/include/linux/kobject.h b/include/linux/kobject.h index de6dcbcc6ef7..e7ba650086ce 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h | |||
| @@ -107,6 +107,7 @@ extern int __must_check kobject_move(struct kobject *, struct kobject *); | |||
| 107 | extern struct kobject *kobject_get(struct kobject *kobj); | 107 | extern struct kobject *kobject_get(struct kobject *kobj); |
| 108 | extern void kobject_put(struct kobject *kobj); | 108 | extern void kobject_put(struct kobject *kobj); |
| 109 | 109 | ||
| 110 | extern const void *kobject_namespace(struct kobject *kobj); | ||
| 110 | extern char *kobject_get_path(struct kobject *kobj, gfp_t flag); | 111 | extern char *kobject_get_path(struct kobject *kobj, gfp_t flag); |
| 111 | 112 | ||
| 112 | struct kobj_type { | 113 | struct kobj_type { |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 25f5d2d11e7c..adf4070586d6 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
| @@ -2874,8 +2874,20 @@ extern int __init dev_proc_init(void); | |||
| 2874 | #define dev_proc_init() 0 | 2874 | #define dev_proc_init() 0 |
| 2875 | #endif | 2875 | #endif |
| 2876 | 2876 | ||
| 2877 | extern int netdev_class_create_file(struct class_attribute *class_attr); | 2877 | extern int netdev_class_create_file_ns(struct class_attribute *class_attr, |
| 2878 | extern void netdev_class_remove_file(struct class_attribute *class_attr); | 2878 | const void *ns); |
| 2879 | extern void netdev_class_remove_file_ns(struct class_attribute *class_attr, | ||
| 2880 | const void *ns); | ||
| 2881 | |||
| 2882 | static inline int netdev_class_create_file(struct class_attribute *class_attr) | ||
| 2883 | { | ||
| 2884 | return netdev_class_create_file_ns(class_attr, NULL); | ||
| 2885 | } | ||
| 2886 | |||
| 2887 | static inline void netdev_class_remove_file(struct class_attribute *class_attr) | ||
| 2888 | { | ||
| 2889 | netdev_class_remove_file_ns(class_attr, NULL); | ||
| 2890 | } | ||
| 2879 | 2891 | ||
| 2880 | extern struct kobj_ns_type_operations net_ns_type_operations; | 2892 | extern struct kobj_ns_type_operations net_ns_type_operations; |
| 2881 | 2893 | ||
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index ce8e4ffd78c7..16f6654082dd 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h | |||
| @@ -178,6 +178,7 @@ struct platform_driver { | |||
| 178 | int (*resume)(struct platform_device *); | 178 | int (*resume)(struct platform_device *); |
| 179 | struct device_driver driver; | 179 | struct device_driver driver; |
| 180 | const struct platform_device_id *id_table; | 180 | const struct platform_device_id *id_table; |
| 181 | bool prevent_deferred_probe; | ||
| 181 | }; | 182 | }; |
| 182 | 183 | ||
| 183 | #define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ | 184 | #define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ |
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 11baec7c9b26..6695040a0317 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h | |||
| @@ -173,7 +173,6 @@ struct bin_attribute bin_attr_##_name = __BIN_ATTR_RW(_name, _size) | |||
| 173 | struct sysfs_ops { | 173 | struct sysfs_ops { |
| 174 | ssize_t (*show)(struct kobject *, struct attribute *, char *); | 174 | ssize_t (*show)(struct kobject *, struct attribute *, char *); |
| 175 | ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); | 175 | ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); |
| 176 | const void *(*namespace)(struct kobject *, const struct attribute *); | ||
| 177 | }; | 176 | }; |
| 178 | 177 | ||
| 179 | struct sysfs_dirent; | 178 | struct sysfs_dirent; |
| @@ -183,19 +182,23 @@ struct sysfs_dirent; | |||
| 183 | int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), | 182 | int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), |
| 184 | void *data, struct module *owner); | 183 | void *data, struct module *owner); |
| 185 | 184 | ||
| 186 | int __must_check sysfs_create_dir(struct kobject *kobj); | 185 | int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns); |
| 187 | void sysfs_remove_dir(struct kobject *kobj); | 186 | void sysfs_remove_dir(struct kobject *kobj); |
| 188 | int __must_check sysfs_rename_dir(struct kobject *kobj, const char *new_name); | 187 | int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, |
| 189 | int __must_check sysfs_move_dir(struct kobject *kobj, | 188 | const void *new_ns); |
| 190 | struct kobject *new_parent_kobj); | 189 | int __must_check sysfs_move_dir_ns(struct kobject *kobj, |
| 191 | 190 | struct kobject *new_parent_kobj, | |
| 192 | int __must_check sysfs_create_file(struct kobject *kobj, | 191 | const void *new_ns); |
| 193 | const struct attribute *attr); | 192 | |
| 193 | int __must_check sysfs_create_file_ns(struct kobject *kobj, | ||
| 194 | const struct attribute *attr, | ||
| 195 | const void *ns); | ||
| 194 | int __must_check sysfs_create_files(struct kobject *kobj, | 196 | int __must_check sysfs_create_files(struct kobject *kobj, |
| 195 | const struct attribute **attr); | 197 | const struct attribute **attr); |
| 196 | int __must_check sysfs_chmod_file(struct kobject *kobj, | 198 | int __must_check sysfs_chmod_file(struct kobject *kobj, |
| 197 | const struct attribute *attr, umode_t mode); | 199 | const struct attribute *attr, umode_t mode); |
| 198 | void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr); | 200 | void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, |
| 201 | const void *ns); | ||
| 199 | void sysfs_remove_files(struct kobject *kobj, const struct attribute **attr); | 202 | void sysfs_remove_files(struct kobject *kobj, const struct attribute **attr); |
| 200 | 203 | ||
| 201 | int __must_check sysfs_create_bin_file(struct kobject *kobj, | 204 | int __must_check sysfs_create_bin_file(struct kobject *kobj, |
| @@ -210,8 +213,9 @@ int __must_check sysfs_create_link_nowarn(struct kobject *kobj, | |||
| 210 | const char *name); | 213 | const char *name); |
| 211 | void sysfs_remove_link(struct kobject *kobj, const char *name); | 214 | void sysfs_remove_link(struct kobject *kobj, const char *name); |
| 212 | 215 | ||
| 213 | int sysfs_rename_link(struct kobject *kobj, struct kobject *target, | 216 | int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *target, |
| 214 | const char *old_name, const char *new_name); | 217 | const char *old_name, const char *new_name, |
| 218 | const void *new_ns); | ||
| 215 | 219 | ||
| 216 | void sysfs_delete_link(struct kobject *dir, struct kobject *targ, | 220 | void sysfs_delete_link(struct kobject *dir, struct kobject *targ, |
| 217 | const char *name); | 221 | const char *name); |
| @@ -241,9 +245,9 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, | |||
| 241 | 245 | ||
| 242 | void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr); | 246 | void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr); |
| 243 | void sysfs_notify_dirent(struct sysfs_dirent *sd); | 247 | void sysfs_notify_dirent(struct sysfs_dirent *sd); |
| 244 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | 248 | struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, |
| 245 | const void *ns, | 249 | const unsigned char *name, |
| 246 | const unsigned char *name); | 250 | const void *ns); |
| 247 | struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd); | 251 | struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd); |
| 248 | void sysfs_put(struct sysfs_dirent *sd); | 252 | void sysfs_put(struct sysfs_dirent *sd); |
| 249 | 253 | ||
| @@ -257,7 +261,7 @@ static inline int sysfs_schedule_callback(struct kobject *kobj, | |||
| 257 | return -ENOSYS; | 261 | return -ENOSYS; |
| 258 | } | 262 | } |
| 259 | 263 | ||
| 260 | static inline int sysfs_create_dir(struct kobject *kobj) | 264 | static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) |
| 261 | { | 265 | { |
| 262 | return 0; | 266 | return 0; |
| 263 | } | 267 | } |
| @@ -266,19 +270,22 @@ static inline void sysfs_remove_dir(struct kobject *kobj) | |||
| 266 | { | 270 | { |
| 267 | } | 271 | } |
| 268 | 272 | ||
| 269 | static inline int sysfs_rename_dir(struct kobject *kobj, const char *new_name) | 273 | static inline int sysfs_rename_dir_ns(struct kobject *kobj, |
| 274 | const char *new_name, const void *new_ns) | ||
| 270 | { | 275 | { |
| 271 | return 0; | 276 | return 0; |
| 272 | } | 277 | } |
| 273 | 278 | ||
| 274 | static inline int sysfs_move_dir(struct kobject *kobj, | 279 | static inline int sysfs_move_dir_ns(struct kobject *kobj, |
| 275 | struct kobject *new_parent_kobj) | 280 | struct kobject *new_parent_kobj, |
| 281 | const void *new_ns) | ||
| 276 | { | 282 | { |
| 277 | return 0; | 283 | return 0; |
| 278 | } | 284 | } |
| 279 | 285 | ||
| 280 | static inline int sysfs_create_file(struct kobject *kobj, | 286 | static inline int sysfs_create_file_ns(struct kobject *kobj, |
| 281 | const struct attribute *attr) | 287 | const struct attribute *attr, |
| 288 | const void *ns) | ||
| 282 | { | 289 | { |
| 283 | return 0; | 290 | return 0; |
| 284 | } | 291 | } |
| @@ -295,8 +302,9 @@ static inline int sysfs_chmod_file(struct kobject *kobj, | |||
| 295 | return 0; | 302 | return 0; |
| 296 | } | 303 | } |
| 297 | 304 | ||
| 298 | static inline void sysfs_remove_file(struct kobject *kobj, | 305 | static inline void sysfs_remove_file_ns(struct kobject *kobj, |
| 299 | const struct attribute *attr) | 306 | const struct attribute *attr, |
| 307 | const void *ns) | ||
| 300 | { | 308 | { |
| 301 | } | 309 | } |
| 302 | 310 | ||
| @@ -333,8 +341,9 @@ static inline void sysfs_remove_link(struct kobject *kobj, const char *name) | |||
| 333 | { | 341 | { |
| 334 | } | 342 | } |
| 335 | 343 | ||
| 336 | static inline int sysfs_rename_link(struct kobject *k, struct kobject *t, | 344 | static inline int sysfs_rename_link_ns(struct kobject *k, struct kobject *t, |
| 337 | const char *old_name, const char *new_name) | 345 | const char *old_name, |
| 346 | const char *new_name, const void *ns) | ||
| 338 | { | 347 | { |
| 339 | return 0; | 348 | return 0; |
| 340 | } | 349 | } |
| @@ -413,10 +422,9 @@ static inline void sysfs_notify(struct kobject *kobj, const char *dir, | |||
| 413 | static inline void sysfs_notify_dirent(struct sysfs_dirent *sd) | 422 | static inline void sysfs_notify_dirent(struct sysfs_dirent *sd) |
| 414 | { | 423 | { |
| 415 | } | 424 | } |
| 416 | static inline | 425 | static inline struct sysfs_dirent * |
| 417 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | 426 | sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, const unsigned char *name, |
| 418 | const void *ns, | 427 | const void *ns) |
| 419 | const unsigned char *name) | ||
| 420 | { | 428 | { |
| 421 | return NULL; | 429 | return NULL; |
| 422 | } | 430 | } |
| @@ -435,4 +443,28 @@ static inline int __must_check sysfs_init(void) | |||
| 435 | 443 | ||
| 436 | #endif /* CONFIG_SYSFS */ | 444 | #endif /* CONFIG_SYSFS */ |
| 437 | 445 | ||
| 446 | static inline int __must_check sysfs_create_file(struct kobject *kobj, | ||
| 447 | const struct attribute *attr) | ||
| 448 | { | ||
| 449 | return sysfs_create_file_ns(kobj, attr, NULL); | ||
| 450 | } | ||
| 451 | |||
| 452 | static inline void sysfs_remove_file(struct kobject *kobj, | ||
| 453 | const struct attribute *attr) | ||
| 454 | { | ||
| 455 | return sysfs_remove_file_ns(kobj, attr, NULL); | ||
| 456 | } | ||
| 457 | |||
| 458 | static inline int sysfs_rename_link(struct kobject *kobj, struct kobject *target, | ||
| 459 | const char *old_name, const char *new_name) | ||
| 460 | { | ||
| 461 | return sysfs_rename_link_ns(kobj, target, old_name, new_name, NULL); | ||
| 462 | } | ||
| 463 | |||
| 464 | static inline struct sysfs_dirent * | ||
| 465 | sysfs_get_dirent(struct sysfs_dirent *parent_sd, const unsigned char *name) | ||
| 466 | { | ||
| 467 | return sysfs_get_dirent_ns(parent_sd, name, NULL); | ||
| 468 | } | ||
| 469 | |||
| 438 | #endif /* _SYSFS_H_ */ | 470 | #endif /* _SYSFS_H_ */ |
diff --git a/kernel/events/core.c b/kernel/events/core.c index 953c14348375..663f43a20f73 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
| @@ -6292,6 +6292,7 @@ type_show(struct device *dev, struct device_attribute *attr, char *page) | |||
| 6292 | 6292 | ||
| 6293 | return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type); | 6293 | return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type); |
| 6294 | } | 6294 | } |
| 6295 | static DEVICE_ATTR_RO(type); | ||
| 6295 | 6296 | ||
| 6296 | static ssize_t | 6297 | static ssize_t |
| 6297 | perf_event_mux_interval_ms_show(struct device *dev, | 6298 | perf_event_mux_interval_ms_show(struct device *dev, |
| @@ -6336,17 +6337,19 @@ perf_event_mux_interval_ms_store(struct device *dev, | |||
| 6336 | 6337 | ||
| 6337 | return count; | 6338 | return count; |
| 6338 | } | 6339 | } |
| 6340 | static DEVICE_ATTR_RW(perf_event_mux_interval_ms); | ||
| 6339 | 6341 | ||
| 6340 | static struct device_attribute pmu_dev_attrs[] = { | 6342 | static struct attribute *pmu_dev_attrs[] = { |
| 6341 | __ATTR_RO(type), | 6343 | &dev_attr_type.attr, |
| 6342 | __ATTR_RW(perf_event_mux_interval_ms), | 6344 | &dev_attr_perf_event_mux_interval_ms.attr, |
| 6343 | __ATTR_NULL, | 6345 | NULL, |
| 6344 | }; | 6346 | }; |
| 6347 | ATTRIBUTE_GROUPS(pmu_dev); | ||
| 6345 | 6348 | ||
| 6346 | static int pmu_bus_running; | 6349 | static int pmu_bus_running; |
| 6347 | static struct bus_type pmu_bus = { | 6350 | static struct bus_type pmu_bus = { |
| 6348 | .name = "event_source", | 6351 | .name = "event_source", |
| 6349 | .dev_attrs = pmu_dev_attrs, | 6352 | .dev_groups = pmu_dev_groups, |
| 6350 | }; | 6353 | }; |
| 6351 | 6354 | ||
| 6352 | static void pmu_dev_release(struct device *dev) | 6355 | static void pmu_dev_release(struct device *dev) |
diff --git a/lib/kobject.c b/lib/kobject.c index 084f7b18d0c0..7a1c203083eb 100644 --- a/lib/kobject.c +++ b/lib/kobject.c | |||
| @@ -13,11 +13,33 @@ | |||
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/kobject.h> | 15 | #include <linux/kobject.h> |
| 16 | #include <linux/kobj_completion.h> | ||
| 16 | #include <linux/string.h> | 17 | #include <linux/string.h> |
| 17 | #include <linux/export.h> | 18 | #include <linux/export.h> |
| 18 | #include <linux/stat.h> | 19 | #include <linux/stat.h> |
| 19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
| 20 | 21 | ||
| 22 | /** | ||
| 23 | * kobject_namespace - return @kobj's namespace tag | ||
| 24 | * @kobj: kobject in question | ||
| 25 | * | ||
| 26 | * Returns namespace tag of @kobj if its parent has namespace ops enabled | ||
| 27 | * and thus @kobj should have a namespace tag associated with it. Returns | ||
| 28 | * %NULL otherwise. | ||
| 29 | */ | ||
| 30 | const void *kobject_namespace(struct kobject *kobj) | ||
| 31 | { | ||
| 32 | const struct kobj_ns_type_operations *ns_ops = kobj_ns_ops(kobj); | ||
| 33 | const void *ns; | ||
| 34 | |||
| 35 | if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE) | ||
| 36 | return NULL; | ||
| 37 | |||
| 38 | ns = kobj->ktype->namespace(kobj); | ||
| 39 | WARN_ON(!ns); /* @kobj in a namespace is required to have !NULL tag */ | ||
| 40 | return ns; | ||
| 41 | } | ||
| 42 | |||
| 21 | /* | 43 | /* |
| 22 | * populate_dir - populate directory with attributes. | 44 | * populate_dir - populate directory with attributes. |
| 23 | * @kobj: object we're working on. | 45 | * @kobj: object we're working on. |
| @@ -46,13 +68,21 @@ static int populate_dir(struct kobject *kobj) | |||
| 46 | 68 | ||
| 47 | static int create_dir(struct kobject *kobj) | 69 | static int create_dir(struct kobject *kobj) |
| 48 | { | 70 | { |
| 49 | int error = 0; | 71 | int error; |
| 50 | error = sysfs_create_dir(kobj); | 72 | |
| 73 | error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj)); | ||
| 51 | if (!error) { | 74 | if (!error) { |
| 52 | error = populate_dir(kobj); | 75 | error = populate_dir(kobj); |
| 53 | if (error) | 76 | if (error) |
| 54 | sysfs_remove_dir(kobj); | 77 | sysfs_remove_dir(kobj); |
| 55 | } | 78 | } |
| 79 | |||
| 80 | /* | ||
| 81 | * @kobj->sd may be deleted by an ancestor going away. Hold an | ||
| 82 | * extra reference so that it stays until @kobj is gone. | ||
| 83 | */ | ||
| 84 | sysfs_get(kobj->sd); | ||
| 85 | |||
| 56 | return error; | 86 | return error; |
| 57 | } | 87 | } |
| 58 | 88 | ||
| @@ -428,7 +458,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name) | |||
| 428 | goto out; | 458 | goto out; |
| 429 | } | 459 | } |
| 430 | 460 | ||
| 431 | error = sysfs_rename_dir(kobj, new_name); | 461 | error = sysfs_rename_dir_ns(kobj, new_name, kobject_namespace(kobj)); |
| 432 | if (error) | 462 | if (error) |
| 433 | goto out; | 463 | goto out; |
| 434 | 464 | ||
| @@ -472,6 +502,7 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) | |||
| 472 | if (kobj->kset) | 502 | if (kobj->kset) |
| 473 | new_parent = kobject_get(&kobj->kset->kobj); | 503 | new_parent = kobject_get(&kobj->kset->kobj); |
| 474 | } | 504 | } |
| 505 | |||
| 475 | /* old object path */ | 506 | /* old object path */ |
| 476 | devpath = kobject_get_path(kobj, GFP_KERNEL); | 507 | devpath = kobject_get_path(kobj, GFP_KERNEL); |
| 477 | if (!devpath) { | 508 | if (!devpath) { |
| @@ -486,7 +517,7 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) | |||
| 486 | sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); | 517 | sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); |
| 487 | envp[0] = devpath_string; | 518 | envp[0] = devpath_string; |
| 488 | envp[1] = NULL; | 519 | envp[1] = NULL; |
| 489 | error = sysfs_move_dir(kobj, new_parent); | 520 | error = sysfs_move_dir_ns(kobj, new_parent, kobject_namespace(kobj)); |
| 490 | if (error) | 521 | if (error) |
| 491 | goto out; | 522 | goto out; |
| 492 | old_parent = kobj->parent; | 523 | old_parent = kobj->parent; |
| @@ -508,10 +539,15 @@ out: | |||
| 508 | */ | 539 | */ |
| 509 | void kobject_del(struct kobject *kobj) | 540 | void kobject_del(struct kobject *kobj) |
| 510 | { | 541 | { |
| 542 | struct sysfs_dirent *sd; | ||
| 543 | |||
| 511 | if (!kobj) | 544 | if (!kobj) |
| 512 | return; | 545 | return; |
| 513 | 546 | ||
| 547 | sd = kobj->sd; | ||
| 514 | sysfs_remove_dir(kobj); | 548 | sysfs_remove_dir(kobj); |
| 549 | sysfs_put(sd); | ||
| 550 | |||
| 515 | kobj->state_in_sysfs = 0; | 551 | kobj->state_in_sysfs = 0; |
| 516 | kobj_kset_leave(kobj); | 552 | kobj_kset_leave(kobj); |
| 517 | kobject_put(kobj->parent); | 553 | kobject_put(kobj->parent); |
| @@ -727,6 +763,55 @@ const struct sysfs_ops kobj_sysfs_ops = { | |||
| 727 | }; | 763 | }; |
| 728 | 764 | ||
| 729 | /** | 765 | /** |
| 766 | * kobj_completion_init - initialize a kobj_completion object. | ||
| 767 | * @kc: kobj_completion | ||
| 768 | * @ktype: type of kobject to initialize | ||
| 769 | * | ||
| 770 | * kobj_completion structures can be embedded within structures with different | ||
| 771 | * lifetime rules. During the release of the enclosing object, we can | ||
| 772 | * wait on the release of the kobject so that we don't free it while it's | ||
| 773 | * still busy. | ||
| 774 | */ | ||
| 775 | void kobj_completion_init(struct kobj_completion *kc, struct kobj_type *ktype) | ||
| 776 | { | ||
| 777 | init_completion(&kc->kc_unregister); | ||
| 778 | kobject_init(&kc->kc_kobj, ktype); | ||
| 779 | } | ||
| 780 | EXPORT_SYMBOL_GPL(kobj_completion_init); | ||
| 781 | |||
| 782 | /** | ||
| 783 | * kobj_completion_release - release a kobj_completion object | ||
| 784 | * @kobj: kobject embedded in kobj_completion | ||
| 785 | * | ||
| 786 | * Used with kobject_release to notify waiters that the kobject has been | ||
| 787 | * released. | ||
| 788 | */ | ||
| 789 | void kobj_completion_release(struct kobject *kobj) | ||
| 790 | { | ||
| 791 | struct kobj_completion *kc = kobj_to_kobj_completion(kobj); | ||
| 792 | complete(&kc->kc_unregister); | ||
| 793 | } | ||
| 794 | EXPORT_SYMBOL_GPL(kobj_completion_release); | ||
| 795 | |||
| 796 | /** | ||
| 797 | * kobj_completion_del_and_wait - release the kobject and wait for it | ||
| 798 | * @kc: kobj_completion object to release | ||
| 799 | * | ||
| 800 | * Delete the kobject from sysfs and drop the reference count. Then wait | ||
| 801 | * until any other outstanding references are also dropped. This routine | ||
| 802 | * is only necessary once other references may have been taken on the | ||
| 803 | * kobject. Typically this happens when the kobject has been published | ||
| 804 | * to sysfs via kobject_add. | ||
| 805 | */ | ||
| 806 | void kobj_completion_del_and_wait(struct kobj_completion *kc) | ||
| 807 | { | ||
| 808 | kobject_del(&kc->kc_kobj); | ||
| 809 | kobject_put(&kc->kc_kobj); | ||
| 810 | wait_for_completion(&kc->kc_unregister); | ||
| 811 | } | ||
| 812 | EXPORT_SYMBOL_GPL(kobj_completion_del_and_wait); | ||
| 813 | |||
| 814 | /** | ||
| 730 | * kset_register - initialize and add a kset. | 815 | * kset_register - initialize and add a kset. |
| 731 | * @k: kset. | 816 | * @k: kset. |
| 732 | */ | 817 | */ |
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index d954b56b4e47..325dee863e46 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
| @@ -1344,17 +1344,19 @@ int netdev_register_kobject(struct net_device *net) | |||
| 1344 | return error; | 1344 | return error; |
| 1345 | } | 1345 | } |
| 1346 | 1346 | ||
| 1347 | int netdev_class_create_file(struct class_attribute *class_attr) | 1347 | int netdev_class_create_file_ns(struct class_attribute *class_attr, |
| 1348 | const void *ns) | ||
| 1348 | { | 1349 | { |
| 1349 | return class_create_file(&net_class, class_attr); | 1350 | return class_create_file_ns(&net_class, class_attr, ns); |
| 1350 | } | 1351 | } |
| 1351 | EXPORT_SYMBOL(netdev_class_create_file); | 1352 | EXPORT_SYMBOL(netdev_class_create_file_ns); |
| 1352 | 1353 | ||
| 1353 | void netdev_class_remove_file(struct class_attribute *class_attr) | 1354 | void netdev_class_remove_file_ns(struct class_attribute *class_attr, |
| 1355 | const void *ns) | ||
| 1354 | { | 1356 | { |
| 1355 | class_remove_file(&net_class, class_attr); | 1357 | class_remove_file_ns(&net_class, class_attr, ns); |
| 1356 | } | 1358 | } |
| 1357 | EXPORT_SYMBOL(netdev_class_remove_file); | 1359 | EXPORT_SYMBOL(netdev_class_remove_file_ns); |
| 1358 | 1360 | ||
| 1359 | int netdev_kobject_init(void) | 1361 | int netdev_kobject_init(void) |
| 1360 | { | 1362 | { |
