mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-15 21:30:43 +00:00
Driver Core / sysfs patches for 3.13-rc1
Here's the big driver core / sysfs update for 3.13-rc1. There's lots of dev_groups updates for different subsystems, as they all get slowly migrated over to the safe versions of the attribute groups (removing userspace races with the creation of the sysfs files.) Also in here are some kobject updates, devres expansions, and the first round of Tejun's sysfs reworking to enable it to be used by other subsystems as a backend for an in-kernel filesystem. All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iEYEABECAAYFAlJ6xAMACgkQMUfUDdst+yk1kQCfcHXhfnrvFZ5J/mDP509IzhNS ddEAoLEWoivtBppNsgrWqXpD1vi4UMsE =JmVW -----END PGP SIGNATURE----- Merge tag 'driver-core-3.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core Pull driver core / sysfs patches from Greg KH: "Here's the big driver core / sysfs update for 3.13-rc1. There's lots of dev_groups updates for different subsystems, as they all get slowly migrated over to the safe versions of the attribute groups (removing userspace races with the creation of the sysfs files.) Also in here are some kobject updates, devres expansions, and the first round of Tejun's sysfs reworking to enable it to be used by other subsystems as a backend for an in-kernel filesystem. All of these have been in linux-next for a while with no reported issues" * tag 'driver-core-3.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (83 commits) sysfs: rename sysfs_assoc_lock and explain what it's about sysfs: use generic_file_llseek() for sysfs_file_operations sysfs: return correct error code on unimplemented mmap() mdio_bus: convert bus code to use dev_groups device: Make dev_WARN/dev_WARN_ONCE print device as well as driver name sysfs: separate out dup filename warning into a separate function sysfs: move sysfs_hash_and_remove() to fs/sysfs/dir.c sysfs: remove unused sysfs_get_dentry() prototype sysfs: honor bin_attr.attr.ignore_lockdep sysfs: merge sysfs_elem_bin_attr into sysfs_elem_attr devres: restore zeroing behavior of devres_alloc() sysfs: fix sysfs_write_file for bin file input: gameport: convert bus code to use dev_groups input: serio: remove bus usage of dev_attrs input: serio: use DEVICE_ATTR_RO() i2o: convert bus code to use dev_groups memstick: convert bus code to use dev_groups tifm: convert bus code to use dev_groups virtio: convert bus code to use dev_groups ipack: convert bus code to use dev_groups ...
This commit is contained in:
commit
0324e74534
@ -91,7 +91,6 @@
|
||||
<title>The Filesystem for Exporting Kernel Objects</title>
|
||||
!Efs/sysfs/file.c
|
||||
!Efs/sysfs/symlink.c
|
||||
!Efs/sysfs/bin.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="debugfs">
|
||||
|
@ -292,6 +292,7 @@ out:
|
||||
return rc;
|
||||
return count;
|
||||
}
|
||||
static BUS_ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe);
|
||||
|
||||
static ssize_t ibmebus_store_remove(struct bus_type *bus,
|
||||
const char *buf, size_t count)
|
||||
@ -317,13 +318,14 @@ static ssize_t ibmebus_store_remove(struct bus_type *bus,
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
static BUS_ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove);
|
||||
|
||||
|
||||
static struct bus_attribute ibmebus_bus_attrs[] = {
|
||||
__ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe),
|
||||
__ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove),
|
||||
__ATTR_NULL
|
||||
static struct attribute *ibmbus_bus_attrs[] = {
|
||||
&bus_attr_probe.attr,
|
||||
&bus_attr_remove.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ibmbus_bus);
|
||||
|
||||
static int ibmebus_bus_bus_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
@ -713,7 +715,7 @@ static struct dev_pm_ops ibmebus_bus_dev_pm_ops = {
|
||||
struct bus_type ibmebus_bus_type = {
|
||||
.name = "ibmebus",
|
||||
.uevent = of_device_uevent_modalias,
|
||||
.bus_attrs = ibmebus_bus_attrs,
|
||||
.bus_groups = ibmbus_bus_groups,
|
||||
.match = ibmebus_bus_bus_match,
|
||||
.probe = ibmebus_bus_device_probe,
|
||||
.remove = ibmebus_bus_device_remove,
|
||||
|
@ -997,21 +997,36 @@ static struct device_attribute vio_cmo_dev_attrs[] = {
|
||||
/* sysfs bus functions and data structures for CMO */
|
||||
|
||||
#define viobus_cmo_rd_attr(name) \
|
||||
static ssize_t \
|
||||
viobus_cmo_##name##_show(struct bus_type *bt, char *buf) \
|
||||
static ssize_t cmo_##name##_show(struct bus_type *bt, char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, "%lu\n", vio_cmo.name); \
|
||||
}
|
||||
} \
|
||||
static BUS_ATTR_RO(cmo_##name)
|
||||
|
||||
#define viobus_cmo_pool_rd_attr(name, var) \
|
||||
static ssize_t \
|
||||
viobus_cmo_##name##_pool_show_##var(struct bus_type *bt, char *buf) \
|
||||
cmo_##name##_##var##_show(struct bus_type *bt, char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, "%lu\n", vio_cmo.name.var); \
|
||||
} \
|
||||
static BUS_ATTR_RO(cmo_##name##_##var)
|
||||
|
||||
viobus_cmo_rd_attr(entitled);
|
||||
viobus_cmo_rd_attr(spare);
|
||||
viobus_cmo_rd_attr(min);
|
||||
viobus_cmo_rd_attr(desired);
|
||||
viobus_cmo_rd_attr(curr);
|
||||
viobus_cmo_pool_rd_attr(reserve, size);
|
||||
viobus_cmo_pool_rd_attr(excess, size);
|
||||
viobus_cmo_pool_rd_attr(excess, free);
|
||||
|
||||
static ssize_t cmo_high_show(struct bus_type *bt, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%lu\n", vio_cmo.high);
|
||||
}
|
||||
|
||||
static ssize_t viobus_cmo_high_reset(struct bus_type *bt, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t cmo_high_store(struct bus_type *bt, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@ -1021,35 +1036,26 @@ static ssize_t viobus_cmo_high_reset(struct bus_type *bt, const char *buf,
|
||||
|
||||
return count;
|
||||
}
|
||||
static BUS_ATTR_RW(cmo_high);
|
||||
|
||||
viobus_cmo_rd_attr(entitled);
|
||||
viobus_cmo_pool_rd_attr(reserve, size);
|
||||
viobus_cmo_pool_rd_attr(excess, size);
|
||||
viobus_cmo_pool_rd_attr(excess, free);
|
||||
viobus_cmo_rd_attr(spare);
|
||||
viobus_cmo_rd_attr(min);
|
||||
viobus_cmo_rd_attr(desired);
|
||||
viobus_cmo_rd_attr(curr);
|
||||
viobus_cmo_rd_attr(high);
|
||||
|
||||
static struct bus_attribute vio_cmo_bus_attrs[] = {
|
||||
__ATTR(cmo_entitled, S_IRUGO, viobus_cmo_entitled_show, NULL),
|
||||
__ATTR(cmo_reserve_size, S_IRUGO, viobus_cmo_reserve_pool_show_size, NULL),
|
||||
__ATTR(cmo_excess_size, S_IRUGO, viobus_cmo_excess_pool_show_size, NULL),
|
||||
__ATTR(cmo_excess_free, S_IRUGO, viobus_cmo_excess_pool_show_free, NULL),
|
||||
__ATTR(cmo_spare, S_IRUGO, viobus_cmo_spare_show, NULL),
|
||||
__ATTR(cmo_min, S_IRUGO, viobus_cmo_min_show, NULL),
|
||||
__ATTR(cmo_desired, S_IRUGO, viobus_cmo_desired_show, NULL),
|
||||
__ATTR(cmo_curr, S_IRUGO, viobus_cmo_curr_show, NULL),
|
||||
__ATTR(cmo_high, S_IWUSR|S_IRUSR|S_IWGRP|S_IRGRP|S_IROTH,
|
||||
viobus_cmo_high_show, viobus_cmo_high_reset),
|
||||
__ATTR_NULL
|
||||
static struct attribute *vio_bus_attrs[] = {
|
||||
&bus_attr_cmo_entitled.attr,
|
||||
&bus_attr_cmo_spare.attr,
|
||||
&bus_attr_cmo_min.attr,
|
||||
&bus_attr_cmo_desired.attr,
|
||||
&bus_attr_cmo_curr.attr,
|
||||
&bus_attr_cmo_high.attr,
|
||||
&bus_attr_cmo_reserve_size.attr,
|
||||
&bus_attr_cmo_excess_size.attr,
|
||||
&bus_attr_cmo_excess_free.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(vio_bus);
|
||||
|
||||
static void vio_cmo_sysfs_init(void)
|
||||
{
|
||||
vio_bus_type.dev_attrs = vio_cmo_dev_attrs;
|
||||
vio_bus_type.bus_attrs = vio_cmo_bus_attrs;
|
||||
vio_bus_type.bus_groups = vio_bus_groups;
|
||||
}
|
||||
#else /* CONFIG_PPC_SMLPAR */
|
||||
int vio_cmo_entitlement_update(size_t new_entitlement) { return 0; }
|
||||
|
@ -591,37 +591,6 @@ void bus_remove_device(struct device *dev)
|
||||
bus_put(dev->bus);
|
||||
}
|
||||
|
||||
static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv)
|
||||
{
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
if (bus->drv_attrs) {
|
||||
for (i = 0; bus->drv_attrs[i].attr.name; i++) {
|
||||
error = driver_create_file(drv, &bus->drv_attrs[i]);
|
||||
if (error)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
done:
|
||||
return error;
|
||||
err:
|
||||
while (--i >= 0)
|
||||
driver_remove_file(drv, &bus->drv_attrs[i]);
|
||||
goto done;
|
||||
}
|
||||
|
||||
static void driver_remove_attrs(struct bus_type *bus,
|
||||
struct device_driver *drv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bus->drv_attrs) {
|
||||
for (i = 0; bus->drv_attrs[i].attr.name; i++)
|
||||
driver_remove_file(drv, &bus->drv_attrs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int __must_check add_bind_files(struct device_driver *drv)
|
||||
{
|
||||
int ret;
|
||||
@ -720,16 +689,12 @@ int bus_add_driver(struct device_driver *drv)
|
||||
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
|
||||
__func__, drv->name);
|
||||
}
|
||||
error = driver_add_attrs(bus, drv);
|
||||
error = driver_add_groups(drv, bus->drv_groups);
|
||||
if (error) {
|
||||
/* How the hell do we get out of this pickle? Give up */
|
||||
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
|
||||
__func__, drv->name);
|
||||
}
|
||||
error = driver_add_groups(drv, bus->drv_groups);
|
||||
if (error)
|
||||
printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
|
||||
__func__, drv->name);
|
||||
}
|
||||
|
||||
if (!drv->suppress_bind_attrs) {
|
||||
error = add_bind_files(drv);
|
||||
@ -766,7 +731,6 @@ void bus_remove_driver(struct device_driver *drv)
|
||||
|
||||
if (!drv->suppress_bind_attrs)
|
||||
remove_bind_files(drv);
|
||||
driver_remove_attrs(drv->bus, drv);
|
||||
driver_remove_groups(drv, drv->bus->drv_groups);
|
||||
driver_remove_file(drv, &driver_attr_uevent);
|
||||
klist_remove(&drv->p->knode_bus);
|
||||
@ -846,42 +810,6 @@ struct bus_type *find_bus(char *name)
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
|
||||
/**
|
||||
* bus_add_attrs - Add default attributes for this bus.
|
||||
* @bus: Bus that has just been registered.
|
||||
*/
|
||||
|
||||
static int bus_add_attrs(struct bus_type *bus)
|
||||
{
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
if (bus->bus_attrs) {
|
||||
for (i = 0; bus->bus_attrs[i].attr.name; i++) {
|
||||
error = bus_create_file(bus, &bus->bus_attrs[i]);
|
||||
if (error)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
done:
|
||||
return error;
|
||||
err:
|
||||
while (--i >= 0)
|
||||
bus_remove_file(bus, &bus->bus_attrs[i]);
|
||||
goto done;
|
||||
}
|
||||
|
||||
static void bus_remove_attrs(struct bus_type *bus)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bus->bus_attrs) {
|
||||
for (i = 0; bus->bus_attrs[i].attr.name; i++)
|
||||
bus_remove_file(bus, &bus->bus_attrs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int bus_add_groups(struct bus_type *bus,
|
||||
const struct attribute_group **groups)
|
||||
{
|
||||
@ -983,9 +911,6 @@ int bus_register(struct bus_type *bus)
|
||||
if (retval)
|
||||
goto bus_probe_files_fail;
|
||||
|
||||
retval = bus_add_attrs(bus);
|
||||
if (retval)
|
||||
goto bus_attrs_fail;
|
||||
retval = bus_add_groups(bus, bus->bus_groups);
|
||||
if (retval)
|
||||
goto bus_groups_fail;
|
||||
@ -994,8 +919,6 @@ int bus_register(struct bus_type *bus)
|
||||
return 0;
|
||||
|
||||
bus_groups_fail:
|
||||
bus_remove_attrs(bus);
|
||||
bus_attrs_fail:
|
||||
remove_probe_files(bus);
|
||||
bus_probe_files_fail:
|
||||
kset_unregister(bus->p->drivers_kset);
|
||||
@ -1024,7 +947,6 @@ void bus_unregister(struct bus_type *bus)
|
||||
pr_debug("bus: '%s': unregistering\n", bus->name);
|
||||
if (bus->dev_root)
|
||||
device_unregister(bus->dev_root);
|
||||
bus_remove_attrs(bus);
|
||||
bus_remove_groups(bus, bus->bus_groups);
|
||||
remove_probe_files(bus);
|
||||
kset_unregister(bus->p->drivers_kset);
|
||||
|
@ -47,18 +47,6 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const void *class_attr_namespace(struct kobject *kobj,
|
||||
const struct attribute *attr)
|
||||
{
|
||||
struct class_attribute *class_attr = to_class_attr(attr);
|
||||
struct subsys_private *cp = to_subsys_private(kobj);
|
||||
const void *ns = NULL;
|
||||
|
||||
if (class_attr->namespace)
|
||||
ns = class_attr->namespace(cp->class, class_attr);
|
||||
return ns;
|
||||
}
|
||||
|
||||
static void class_release(struct kobject *kobj)
|
||||
{
|
||||
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
|
||||
static const struct sysfs_ops class_sysfs_ops = {
|
||||
.show = class_attr_show,
|
||||
.store = class_attr_store,
|
||||
.namespace = class_attr_namespace,
|
||||
};
|
||||
|
||||
static struct kobj_type class_ktype = {
|
||||
@ -99,21 +86,23 @@ static struct kobj_type class_ktype = {
|
||||
static struct kset *class_kset;
|
||||
|
||||
|
||||
int class_create_file(struct class *cls, const struct class_attribute *attr)
|
||||
int class_create_file_ns(struct class *cls, const struct class_attribute *attr,
|
||||
const void *ns)
|
||||
{
|
||||
int error;
|
||||
if (cls)
|
||||
error = sysfs_create_file(&cls->p->subsys.kobj,
|
||||
&attr->attr);
|
||||
error = sysfs_create_file_ns(&cls->p->subsys.kobj,
|
||||
&attr->attr, ns);
|
||||
else
|
||||
error = -EINVAL;
|
||||
return error;
|
||||
}
|
||||
|
||||
void class_remove_file(struct class *cls, const struct class_attribute *attr)
|
||||
void class_remove_file_ns(struct class *cls, const struct class_attribute *attr,
|
||||
const void *ns)
|
||||
{
|
||||
if (cls)
|
||||
sysfs_remove_file(&cls->p->subsys.kobj, &attr->attr);
|
||||
sysfs_remove_file_ns(&cls->p->subsys.kobj, &attr->attr, ns);
|
||||
}
|
||||
|
||||
static struct class *class_get(struct class *cls)
|
||||
@ -600,8 +589,8 @@ int __init classes_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(class_create_file);
|
||||
EXPORT_SYMBOL_GPL(class_remove_file);
|
||||
EXPORT_SYMBOL_GPL(class_create_file_ns);
|
||||
EXPORT_SYMBOL_GPL(class_remove_file_ns);
|
||||
EXPORT_SYMBOL_GPL(class_unregister);
|
||||
EXPORT_SYMBOL_GPL(class_destroy);
|
||||
|
||||
|
@ -455,64 +455,6 @@ static ssize_t online_store(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
static DEVICE_ATTR_RW(online);
|
||||
|
||||
static int device_add_attributes(struct device *dev,
|
||||
struct device_attribute *attrs)
|
||||
{
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
if (attrs) {
|
||||
for (i = 0; attrs[i].attr.name; i++) {
|
||||
error = device_create_file(dev, &attrs[i]);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
if (error)
|
||||
while (--i >= 0)
|
||||
device_remove_file(dev, &attrs[i]);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static void device_remove_attributes(struct device *dev,
|
||||
struct device_attribute *attrs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (attrs)
|
||||
for (i = 0; attrs[i].attr.name; i++)
|
||||
device_remove_file(dev, &attrs[i]);
|
||||
}
|
||||
|
||||
static int device_add_bin_attributes(struct device *dev,
|
||||
struct bin_attribute *attrs)
|
||||
{
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
if (attrs) {
|
||||
for (i = 0; attrs[i].attr.name; i++) {
|
||||
error = device_create_bin_file(dev, &attrs[i]);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
if (error)
|
||||
while (--i >= 0)
|
||||
device_remove_bin_file(dev, &attrs[i]);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static void device_remove_bin_attributes(struct device *dev,
|
||||
struct bin_attribute *attrs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (attrs)
|
||||
for (i = 0; attrs[i].attr.name; i++)
|
||||
device_remove_bin_file(dev, &attrs[i]);
|
||||
}
|
||||
|
||||
int device_add_groups(struct device *dev, const struct attribute_group **groups)
|
||||
{
|
||||
return sysfs_create_groups(&dev->kobj, groups);
|
||||
@ -534,18 +476,12 @@ static int device_add_attrs(struct device *dev)
|
||||
error = device_add_groups(dev, class->dev_groups);
|
||||
if (error)
|
||||
return error;
|
||||
error = device_add_attributes(dev, class->dev_attrs);
|
||||
if (error)
|
||||
goto err_remove_class_groups;
|
||||
error = device_add_bin_attributes(dev, class->dev_bin_attrs);
|
||||
if (error)
|
||||
goto err_remove_class_attrs;
|
||||
}
|
||||
|
||||
if (type) {
|
||||
error = device_add_groups(dev, type->groups);
|
||||
if (error)
|
||||
goto err_remove_class_bin_attrs;
|
||||
goto err_remove_class_groups;
|
||||
}
|
||||
|
||||
error = device_add_groups(dev, dev->groups);
|
||||
@ -563,12 +499,6 @@ static int device_add_attrs(struct device *dev)
|
||||
err_remove_type_groups:
|
||||
if (type)
|
||||
device_remove_groups(dev, type->groups);
|
||||
err_remove_class_bin_attrs:
|
||||
if (class)
|
||||
device_remove_bin_attributes(dev, class->dev_bin_attrs);
|
||||
err_remove_class_attrs:
|
||||
if (class)
|
||||
device_remove_attributes(dev, class->dev_attrs);
|
||||
err_remove_class_groups:
|
||||
if (class)
|
||||
device_remove_groups(dev, class->dev_groups);
|
||||
@ -587,11 +517,8 @@ static void device_remove_attrs(struct device *dev)
|
||||
if (type)
|
||||
device_remove_groups(dev, type->groups);
|
||||
|
||||
if (class) {
|
||||
device_remove_attributes(dev, class->dev_attrs);
|
||||
device_remove_bin_attributes(dev, class->dev_bin_attrs);
|
||||
if (class)
|
||||
device_remove_groups(dev, class->dev_groups);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t dev_show(struct device *dev, struct device_attribute *attr,
|
||||
@ -1881,6 +1808,7 @@ EXPORT_SYMBOL_GPL(device_destroy);
|
||||
*/
|
||||
int device_rename(struct device *dev, const char *new_name)
|
||||
{
|
||||
struct kobject *kobj = &dev->kobj;
|
||||
char *old_device_name = NULL;
|
||||
int error;
|
||||
|
||||
@ -1888,8 +1816,7 @@ int device_rename(struct device *dev, const char *new_name)
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("device: '%s': %s: renaming to '%s'\n", dev_name(dev),
|
||||
__func__, new_name);
|
||||
dev_dbg(dev, "renaming to %s\n", new_name);
|
||||
|
||||
old_device_name = kstrdup(dev_name(dev), GFP_KERNEL);
|
||||
if (!old_device_name) {
|
||||
@ -1898,13 +1825,14 @@ int device_rename(struct device *dev, const char *new_name)
|
||||
}
|
||||
|
||||
if (dev->class) {
|
||||
error = sysfs_rename_link(&dev->class->p->subsys.kobj,
|
||||
&dev->kobj, old_device_name, new_name);
|
||||
error = sysfs_rename_link_ns(&dev->class->p->subsys.kobj,
|
||||
kobj, old_device_name,
|
||||
new_name, kobject_namespace(kobj));
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = kobject_rename(&dev->kobj, new_name);
|
||||
error = kobject_rename(kobj, new_name);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
|
@ -91,7 +91,8 @@ static __always_inline struct devres * alloc_dr(dr_release_t release,
|
||||
if (unlikely(!dr))
|
||||
return NULL;
|
||||
|
||||
memset(dr, 0, tot_size);
|
||||
memset(dr, 0, offsetof(struct devres, data));
|
||||
|
||||
INIT_LIST_HEAD(&dr->node.entry);
|
||||
dr->node.release = release;
|
||||
return dr;
|
||||
@ -110,7 +111,7 @@ void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
|
||||
{
|
||||
struct devres *dr;
|
||||
|
||||
dr = alloc_dr(release, size, gfp);
|
||||
dr = alloc_dr(release, size, gfp | __GFP_ZERO);
|
||||
if (unlikely(!dr))
|
||||
return NULL;
|
||||
set_node_dbginfo(&dr->node, name, size);
|
||||
@ -135,7 +136,7 @@ void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
|
||||
{
|
||||
struct devres *dr;
|
||||
|
||||
dr = alloc_dr(release, size, gfp);
|
||||
dr = alloc_dr(release, size, gfp | __GFP_ZERO);
|
||||
if (unlikely(!dr))
|
||||
return NULL;
|
||||
return dr->data;
|
||||
@ -745,58 +746,62 @@ void devm_remove_action(struct device *dev, void (*action)(void *), void *data)
|
||||
EXPORT_SYMBOL_GPL(devm_remove_action);
|
||||
|
||||
/*
|
||||
* Managed kzalloc/kfree
|
||||
* Managed kmalloc/kfree
|
||||
*/
|
||||
static void devm_kzalloc_release(struct device *dev, void *res)
|
||||
static void devm_kmalloc_release(struct device *dev, void *res)
|
||||
{
|
||||
/* noop */
|
||||
}
|
||||
|
||||
static int devm_kzalloc_match(struct device *dev, void *res, void *data)
|
||||
static int devm_kmalloc_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
return res == data;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_kzalloc - Resource-managed kzalloc
|
||||
* devm_kmalloc - Resource-managed kmalloc
|
||||
* @dev: Device to allocate memory for
|
||||
* @size: Allocation size
|
||||
* @gfp: Allocation gfp flags
|
||||
*
|
||||
* Managed kzalloc. Memory allocated with this function is
|
||||
* Managed kmalloc. Memory allocated with this function is
|
||||
* automatically freed on driver detach. Like all other devres
|
||||
* resources, guaranteed alignment is unsigned long long.
|
||||
*
|
||||
* RETURNS:
|
||||
* Pointer to allocated memory on success, NULL on failure.
|
||||
*/
|
||||
void * devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
|
||||
void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
|
||||
{
|
||||
struct devres *dr;
|
||||
|
||||
/* use raw alloc_dr for kmalloc caller tracing */
|
||||
dr = alloc_dr(devm_kzalloc_release, size, gfp);
|
||||
dr = alloc_dr(devm_kmalloc_release, size, gfp);
|
||||
if (unlikely(!dr))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* This is named devm_kzalloc_release for historical reasons
|
||||
* The initial implementation did not support kmalloc, only kzalloc
|
||||
*/
|
||||
set_node_dbginfo(&dr->node, "devm_kzalloc_release", size);
|
||||
devres_add(dev, dr->data);
|
||||
return dr->data;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_kzalloc);
|
||||
EXPORT_SYMBOL_GPL(devm_kmalloc);
|
||||
|
||||
/**
|
||||
* devm_kfree - Resource-managed kfree
|
||||
* @dev: Device this memory belongs to
|
||||
* @p: Memory to free
|
||||
*
|
||||
* Free memory allocated with devm_kzalloc().
|
||||
* Free memory allocated with devm_kmalloc().
|
||||
*/
|
||||
void devm_kfree(struct device *dev, void *p)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = devres_destroy(dev, devm_kzalloc_release, devm_kzalloc_match, p);
|
||||
rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p);
|
||||
WARN_ON(rc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_kfree);
|
||||
|
@ -282,31 +282,35 @@ static noinline_for_stack long fw_file_size(struct file *file)
|
||||
return st.size;
|
||||
}
|
||||
|
||||
static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf)
|
||||
static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf)
|
||||
{
|
||||
long size;
|
||||
char *buf;
|
||||
int rc;
|
||||
|
||||
size = fw_file_size(file);
|
||||
if (size <= 0)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
buf = vmalloc(size);
|
||||
if (!buf)
|
||||
return false;
|
||||
if (kernel_read(file, 0, buf, size) != size) {
|
||||
return -ENOMEM;
|
||||
rc = kernel_read(file, 0, buf, size);
|
||||
if (rc != size) {
|
||||
if (rc > 0)
|
||||
rc = -EIO;
|
||||
vfree(buf);
|
||||
return false;
|
||||
return rc;
|
||||
}
|
||||
fw_buf->data = buf;
|
||||
fw_buf->size = size;
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool fw_get_filesystem_firmware(struct device *device,
|
||||
static int fw_get_filesystem_firmware(struct device *device,
|
||||
struct firmware_buf *buf)
|
||||
{
|
||||
int i;
|
||||
bool success = false;
|
||||
int rc = -ENOENT;
|
||||
char *path = __getname();
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
|
||||
@ -321,14 +325,17 @@ static bool fw_get_filesystem_firmware(struct device *device,
|
||||
file = filp_open(path, O_RDONLY, 0);
|
||||
if (IS_ERR(file))
|
||||
continue;
|
||||
success = fw_read_file_contents(file, buf);
|
||||
rc = fw_read_file_contents(file, buf);
|
||||
fput(file);
|
||||
if (success)
|
||||
if (rc)
|
||||
dev_warn(device, "firmware, attempted to load %s, but failed with error %d\n",
|
||||
path, rc);
|
||||
else
|
||||
break;
|
||||
}
|
||||
__putname(path);
|
||||
|
||||
if (success) {
|
||||
if (!rc) {
|
||||
dev_dbg(device, "firmware: direct-loading firmware %s\n",
|
||||
buf->fw_id);
|
||||
mutex_lock(&fw_lock);
|
||||
@ -337,7 +344,7 @@ static bool fw_get_filesystem_firmware(struct device *device,
|
||||
mutex_unlock(&fw_lock);
|
||||
}
|
||||
|
||||
return success;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* firmware holds the ownership of pages */
|
||||
@ -1086,9 +1093,14 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
|
||||
}
|
||||
}
|
||||
|
||||
if (!fw_get_filesystem_firmware(device, fw->priv))
|
||||
ret = fw_get_filesystem_firmware(device, fw->priv);
|
||||
if (ret) {
|
||||
dev_warn(device, "Direct firmware load failed with error %d\n",
|
||||
ret);
|
||||
dev_warn(device, "Falling back to user helper\n");
|
||||
ret = fw_load_from_user_helper(fw, name, device,
|
||||
uevent, nowait, timeout);
|
||||
}
|
||||
|
||||
/* don't cache firmware handled without uevent */
|
||||
if (!ret)
|
||||
|
@ -488,6 +488,11 @@ static int platform_drv_probe(struct device *_dev)
|
||||
if (ret && ACPI_HANDLE(_dev))
|
||||
acpi_dev_pm_detach(_dev, true);
|
||||
|
||||
if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
|
||||
dev_warn(_dev, "probe deferral not supported\n");
|
||||
ret = -ENXIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -553,8 +558,7 @@ EXPORT_SYMBOL_GPL(platform_driver_unregister);
|
||||
/**
|
||||
* platform_driver_probe - register driver for non-hotpluggable device
|
||||
* @drv: platform driver structure
|
||||
* @probe: the driver probe routine, probably from an __init section,
|
||||
* must not return -EPROBE_DEFER.
|
||||
* @probe: the driver probe routine, probably from an __init section
|
||||
*
|
||||
* Use this instead of platform_driver_register() when you know the device
|
||||
* is not hotpluggable and has already been registered, and you want to
|
||||
@ -565,8 +569,7 @@ EXPORT_SYMBOL_GPL(platform_driver_unregister);
|
||||
* into system-on-chip processors, where the controller devices have been
|
||||
* configured as part of board setup.
|
||||
*
|
||||
* This is incompatible with deferred probing so probe() must not
|
||||
* return -EPROBE_DEFER.
|
||||
* Note that this is incompatible with deferred probing.
|
||||
*
|
||||
* Returns zero if the driver registered and bound to a device, else returns
|
||||
* 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,
|
||||
{
|
||||
int retval, code;
|
||||
|
||||
/*
|
||||
* Prevent driver from requesting probe deferral to avoid further
|
||||
* futile probe attempts.
|
||||
*/
|
||||
drv->prevent_deferred_probe = true;
|
||||
|
||||
/* make sure driver won't have bind/unbind attributes */
|
||||
drv->driver.suppress_bind_attrs = true;
|
||||
|
||||
|
@ -30,28 +30,37 @@ static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, cha
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
return sprintf(buf, "0x%03X\n", core->id.manuf);
|
||||
}
|
||||
static DEVICE_ATTR_RO(manuf);
|
||||
|
||||
static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
return sprintf(buf, "0x%03X\n", core->id.id);
|
||||
}
|
||||
static DEVICE_ATTR_RO(id);
|
||||
|
||||
static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
return sprintf(buf, "0x%02X\n", core->id.rev);
|
||||
}
|
||||
static DEVICE_ATTR_RO(rev);
|
||||
|
||||
static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
return sprintf(buf, "0x%X\n", core->id.class);
|
||||
}
|
||||
static struct device_attribute bcma_device_attrs[] = {
|
||||
__ATTR_RO(manuf),
|
||||
__ATTR_RO(id),
|
||||
__ATTR_RO(rev),
|
||||
__ATTR_RO(class),
|
||||
__ATTR_NULL,
|
||||
static DEVICE_ATTR_RO(class);
|
||||
|
||||
static struct attribute *bcma_device_attrs[] = {
|
||||
&dev_attr_manuf.attr,
|
||||
&dev_attr_id.attr,
|
||||
&dev_attr_rev.attr,
|
||||
&dev_attr_class.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(bcma_device);
|
||||
|
||||
static struct bus_type bcma_bus_type = {
|
||||
.name = "bcma",
|
||||
@ -59,7 +68,7 @@ static struct bus_type bcma_bus_type = {
|
||||
.probe = bcma_device_probe,
|
||||
.remove = bcma_device_remove,
|
||||
.uevent = bcma_device_uevent,
|
||||
.dev_attrs = bcma_device_attrs,
|
||||
.dev_groups = bcma_device_groups,
|
||||
};
|
||||
|
||||
static u16 bcma_cc_core_id(struct bcma_bus *bus)
|
||||
|
@ -408,7 +408,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
|
||||
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
|
||||
|
||||
if (!value_sd) {
|
||||
value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value");
|
||||
value_sd = sysfs_get_dirent(dev->kobj.sd, "value");
|
||||
if (!value_sd) {
|
||||
ret = -ENODEV;
|
||||
goto err_out;
|
||||
|
@ -33,11 +33,13 @@ static ssize_t modalias_show(struct device *dev,
|
||||
{
|
||||
return sprintf(buf, "hsi:%s\n", dev_name(dev));
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct device_attribute hsi_bus_dev_attrs[] = {
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *hsi_bus_dev_attrs[] = {
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(hsi_bus_dev);
|
||||
|
||||
static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
@ -53,7 +55,7 @@ static int hsi_bus_match(struct device *dev, struct device_driver *driver)
|
||||
|
||||
static struct bus_type hsi_bus_type = {
|
||||
.name = "hsi",
|
||||
.dev_attrs = hsi_bus_dev_attrs,
|
||||
.dev_groups = hsi_bus_dev_groups,
|
||||
.match = hsi_bus_match,
|
||||
.uevent = hsi_bus_uevent,
|
||||
};
|
||||
|
@ -25,6 +25,7 @@ static ssize_t media_show(struct device *dev, struct device_attribute *attr,
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", ide_media_string(drive));
|
||||
}
|
||||
static DEVICE_ATTR_RO(media);
|
||||
|
||||
static ssize_t drivename_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -32,6 +33,7 @@ static ssize_t drivename_show(struct device *dev, struct device_attribute *attr,
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", drive->name);
|
||||
}
|
||||
static DEVICE_ATTR_RO(drivename);
|
||||
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -39,6 +41,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "ide:m-%s\n", ide_media_string(drive));
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static ssize_t model_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -46,6 +49,7 @@ static ssize_t model_show(struct device *dev, struct device_attribute *attr,
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]);
|
||||
}
|
||||
static DEVICE_ATTR_RO(model);
|
||||
|
||||
static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -53,6 +57,7 @@ static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]);
|
||||
}
|
||||
static DEVICE_ATTR_RO(firmware);
|
||||
|
||||
static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -60,16 +65,28 @@ static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]);
|
||||
}
|
||||
static DEVICE_ATTR(serial, 0400, serial_show, NULL);
|
||||
|
||||
struct device_attribute ide_dev_attrs[] = {
|
||||
__ATTR_RO(media),
|
||||
__ATTR_RO(drivename),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_RO(model),
|
||||
__ATTR_RO(firmware),
|
||||
__ATTR(serial, 0400, serial_show, NULL),
|
||||
__ATTR(unload_heads, 0644, ide_park_show, ide_park_store),
|
||||
__ATTR_NULL
|
||||
static DEVICE_ATTR(unload_heads, 0644, ide_park_show, ide_park_store);
|
||||
|
||||
static struct attribute *ide_attrs[] = {
|
||||
&dev_attr_media.attr,
|
||||
&dev_attr_drivename.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_model.attr,
|
||||
&dev_attr_firmware.attr,
|
||||
&dev_attr_serial.attr,
|
||||
&dev_attr_unload_heads.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group ide_attr_group = {
|
||||
.attrs = ide_attrs,
|
||||
};
|
||||
|
||||
const struct attribute_group *ide_dev_groups[] = {
|
||||
&ide_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static ssize_t store_delete_devices(struct device *portdev,
|
||||
|
@ -158,7 +158,7 @@ struct bus_type ide_bus_type = {
|
||||
.probe = generic_ide_probe,
|
||||
.remove = generic_ide_remove,
|
||||
.shutdown = generic_ide_shutdown,
|
||||
.dev_attrs = ide_dev_attrs,
|
||||
.dev_groups = ide_dev_groups,
|
||||
.suspend = generic_ide_suspend,
|
||||
.resume = generic_ide_resume,
|
||||
};
|
||||
|
@ -422,14 +422,15 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
|
||||
* Gameport port operations
|
||||
*/
|
||||
|
||||
static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t gameport_description_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct gameport *gameport = to_gameport_port(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", gameport->name);
|
||||
}
|
||||
static DEVICE_ATTR(description, S_IRUGO, gameport_description_show, NULL);
|
||||
|
||||
static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct gameport *gameport = to_gameport_port(dev);
|
||||
struct device_driver *drv;
|
||||
@ -457,12 +458,14 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut
|
||||
|
||||
return error ? error : count;
|
||||
}
|
||||
static DEVICE_ATTR_WO(drvctl);
|
||||
|
||||
static struct device_attribute gameport_device_attrs[] = {
|
||||
__ATTR(description, S_IRUGO, gameport_show_description, NULL),
|
||||
__ATTR(drvctl, S_IWUSR, NULL, gameport_rebind_driver),
|
||||
__ATTR_NULL
|
||||
static struct attribute *gameport_device_attrs[] = {
|
||||
&dev_attr_description.attr,
|
||||
&dev_attr_drvctl.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(gameport_device);
|
||||
|
||||
static void gameport_release_port(struct device *dev)
|
||||
{
|
||||
@ -750,7 +753,7 @@ static int gameport_bus_match(struct device *dev, struct device_driver *drv)
|
||||
|
||||
static struct bus_type gameport_bus = {
|
||||
.name = "gameport",
|
||||
.dev_attrs = gameport_device_attrs,
|
||||
.dev_groups = gameport_device_groups,
|
||||
.drv_groups = gameport_driver_groups,
|
||||
.match = gameport_bus_match,
|
||||
.probe = gameport_driver_probe,
|
||||
|
@ -365,7 +365,7 @@ static ssize_t serio_show_description(struct device *dev, struct device_attribut
|
||||
return sprintf(buf, "%s\n", serio->name);
|
||||
}
|
||||
|
||||
static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serio *serio = to_serio_port(dev);
|
||||
|
||||
@ -373,54 +373,31 @@ static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *
|
||||
serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
|
||||
}
|
||||
|
||||
static ssize_t serio_show_id_type(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serio *serio = to_serio_port(dev);
|
||||
return sprintf(buf, "%02x\n", serio->id.type);
|
||||
}
|
||||
|
||||
static ssize_t serio_show_id_proto(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t proto_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serio *serio = to_serio_port(dev);
|
||||
return sprintf(buf, "%02x\n", serio->id.proto);
|
||||
}
|
||||
|
||||
static ssize_t serio_show_id_id(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serio *serio = to_serio_port(dev);
|
||||
return sprintf(buf, "%02x\n", serio->id.id);
|
||||
}
|
||||
|
||||
static ssize_t serio_show_id_extra(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t extra_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serio *serio = to_serio_port(dev);
|
||||
return sprintf(buf, "%02x\n", serio->id.extra);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(type, S_IRUGO, serio_show_id_type, NULL);
|
||||
static DEVICE_ATTR(proto, S_IRUGO, serio_show_id_proto, NULL);
|
||||
static DEVICE_ATTR(id, S_IRUGO, serio_show_id_id, NULL);
|
||||
static DEVICE_ATTR(extra, S_IRUGO, serio_show_id_extra, NULL);
|
||||
|
||||
static struct attribute *serio_device_id_attrs[] = {
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_proto.attr,
|
||||
&dev_attr_id.attr,
|
||||
&dev_attr_extra.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group serio_id_attr_group = {
|
||||
.name = "id",
|
||||
.attrs = serio_device_id_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *serio_device_attr_groups[] = {
|
||||
&serio_id_attr_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct serio *serio = to_serio_port(dev);
|
||||
struct device_driver *drv;
|
||||
@ -474,14 +451,36 @@ static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute *
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct device_attribute serio_device_attrs[] = {
|
||||
__ATTR(description, S_IRUGO, serio_show_description, NULL),
|
||||
__ATTR(modalias, S_IRUGO, serio_show_modalias, NULL),
|
||||
__ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver),
|
||||
__ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),
|
||||
__ATTR_NULL
|
||||
static DEVICE_ATTR_RO(type);
|
||||
static DEVICE_ATTR_RO(proto);
|
||||
static DEVICE_ATTR_RO(id);
|
||||
static DEVICE_ATTR_RO(extra);
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
static DEVICE_ATTR_WO(drvctl);
|
||||
static DEVICE_ATTR(description, S_IRUGO, serio_show_description, NULL);
|
||||
static DEVICE_ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode);
|
||||
|
||||
static struct attribute *serio_device_id_attrs[] = {
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_proto.attr,
|
||||
&dev_attr_id.attr,
|
||||
&dev_attr_extra.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_description.attr,
|
||||
&dev_attr_drvctl.attr,
|
||||
&dev_attr_bind_mode.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group serio_id_attr_group = {
|
||||
.name = "id",
|
||||
.attrs = serio_device_id_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *serio_device_attr_groups[] = {
|
||||
&serio_id_attr_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void serio_release_port(struct device *dev)
|
||||
{
|
||||
@ -996,7 +995,6 @@ EXPORT_SYMBOL(serio_interrupt);
|
||||
|
||||
static struct bus_type serio_bus = {
|
||||
.name = "serio",
|
||||
.dev_attrs = serio_device_attrs,
|
||||
.drv_groups = serio_driver_groups,
|
||||
.match = serio_bus_match,
|
||||
.uevent = serio_uevent,
|
||||
|
@ -180,20 +180,28 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
ipack_device_attr(id_format, "0x%hhu\n");
|
||||
|
||||
static struct device_attribute ipack_dev_attrs[] = {
|
||||
__ATTR_RO(id),
|
||||
__ATTR_RO(id_device),
|
||||
__ATTR_RO(id_format),
|
||||
__ATTR_RO(id_vendor),
|
||||
__ATTR_RO(modalias),
|
||||
static DEVICE_ATTR_RO(id);
|
||||
static DEVICE_ATTR_RO(id_device);
|
||||
static DEVICE_ATTR_RO(id_format);
|
||||
static DEVICE_ATTR_RO(id_vendor);
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct attribute *ipack_attrs[] = {
|
||||
&dev_attr_id.attr,
|
||||
&dev_attr_id_device.attr,
|
||||
&dev_attr_id_format.attr,
|
||||
&dev_attr_id_vendor.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ipack);
|
||||
|
||||
static struct bus_type ipack_bus_type = {
|
||||
.name = "ipack",
|
||||
.probe = ipack_bus_probe,
|
||||
.match = ipack_bus_match,
|
||||
.remove = ipack_bus_remove,
|
||||
.dev_attrs = ipack_dev_attrs,
|
||||
.dev_groups = ipack_groups,
|
||||
.uevent = ipack_uevent,
|
||||
};
|
||||
|
||||
|
@ -1654,9 +1654,9 @@ int bitmap_create(struct mddev *mddev)
|
||||
bitmap->mddev = mddev;
|
||||
|
||||
if (mddev->kobj.sd)
|
||||
bm = sysfs_get_dirent(mddev->kobj.sd, NULL, "bitmap");
|
||||
bm = sysfs_get_dirent(mddev->kobj.sd, "bitmap");
|
||||
if (bm) {
|
||||
bitmap->sysfs_can_clear = sysfs_get_dirent(bm, NULL, "can_clear");
|
||||
bitmap->sysfs_can_clear = sysfs_get_dirent(bm, "can_clear");
|
||||
sysfs_put(bm);
|
||||
} else
|
||||
bitmap->sysfs_can_clear = NULL;
|
||||
|
@ -3555,7 +3555,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
|
||||
printk(KERN_WARNING
|
||||
"md: cannot register extra attributes for %s\n",
|
||||
mdname(mddev));
|
||||
mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, NULL, "sync_action");
|
||||
mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action");
|
||||
}
|
||||
if (mddev->pers->sync_request != NULL &&
|
||||
pers->sync_request == NULL) {
|
||||
|
@ -501,7 +501,7 @@ extern struct attribute_group md_bitmap_group;
|
||||
static inline struct sysfs_dirent *sysfs_get_dirent_safe(struct sysfs_dirent *sd, char *name)
|
||||
{
|
||||
if (sd)
|
||||
return sysfs_get_dirent(sd, NULL, name);
|
||||
return sysfs_get_dirent(sd, name);
|
||||
return sd;
|
||||
}
|
||||
static inline void sysfs_notify_dirent_safe(struct sysfs_dirent *sd)
|
||||
|
@ -153,24 +153,24 @@ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
|
||||
struct memstick_dev *card = container_of(dev, struct memstick_dev, \
|
||||
dev); \
|
||||
return sprintf(buf, format, card->id.name); \
|
||||
}
|
||||
} \
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
MEMSTICK_ATTR(type, "%02X");
|
||||
MEMSTICK_ATTR(category, "%02X");
|
||||
MEMSTICK_ATTR(class, "%02X");
|
||||
|
||||
#define MEMSTICK_ATTR_RO(name) __ATTR(name, S_IRUGO, name##_show, NULL)
|
||||
|
||||
static struct device_attribute memstick_dev_attrs[] = {
|
||||
MEMSTICK_ATTR_RO(type),
|
||||
MEMSTICK_ATTR_RO(category),
|
||||
MEMSTICK_ATTR_RO(class),
|
||||
__ATTR_NULL
|
||||
static struct attribute *memstick_dev_attrs[] = {
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_category.attr,
|
||||
&dev_attr_class.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(memstick_dev);
|
||||
|
||||
static struct bus_type memstick_bus_type = {
|
||||
.name = "memstick",
|
||||
.dev_attrs = memstick_dev_attrs,
|
||||
.dev_groups = memstick_dev_groups,
|
||||
.match = memstick_bus_match,
|
||||
.uevent = memstick_uevent,
|
||||
.probe = memstick_device_probe,
|
||||
|
@ -33,7 +33,7 @@ extern int __init i2o_pci_init(void);
|
||||
extern void __exit i2o_pci_exit(void);
|
||||
|
||||
/* device */
|
||||
extern struct device_attribute i2o_device_attrs[];
|
||||
extern const struct attribute_group *i2o_device_groups[];
|
||||
|
||||
extern void i2o_device_remove(struct i2o_device *);
|
||||
extern int i2o_device_parse_lct(struct i2o_controller *);
|
||||
|
@ -138,45 +138,55 @@ static void i2o_device_release(struct device *dev)
|
||||
}
|
||||
|
||||
/**
|
||||
* i2o_device_show_class_id - Displays class id of I2O device
|
||||
* class_id_show - Displays class id of I2O device
|
||||
* @dev: device of which the class id should be displayed
|
||||
* @attr: pointer to device attribute
|
||||
* @buf: buffer into which the class id should be printed
|
||||
*
|
||||
* Returns the number of bytes which are printed into the buffer.
|
||||
*/
|
||||
static ssize_t i2o_device_show_class_id(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
static ssize_t class_id_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2o_device *i2o_dev = to_i2o_device(dev);
|
||||
|
||||
sprintf(buf, "0x%03x\n", i2o_dev->lct_data.class_id);
|
||||
return strlen(buf) + 1;
|
||||
}
|
||||
static DEVICE_ATTR_RO(class_id);
|
||||
|
||||
/**
|
||||
* i2o_device_show_tid - Displays TID of I2O device
|
||||
* tid_show - Displays TID of I2O device
|
||||
* @dev: device of which the TID should be displayed
|
||||
* @attr: pointer to device attribute
|
||||
* @buf: buffer into which the TID should be printed
|
||||
*
|
||||
* Returns the number of bytes which are printed into the buffer.
|
||||
*/
|
||||
static ssize_t i2o_device_show_tid(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t tid_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2o_device *i2o_dev = to_i2o_device(dev);
|
||||
|
||||
sprintf(buf, "0x%03x\n", i2o_dev->lct_data.tid);
|
||||
return strlen(buf) + 1;
|
||||
}
|
||||
static DEVICE_ATTR_RO(tid);
|
||||
|
||||
/* I2O device attributes */
|
||||
struct device_attribute i2o_device_attrs[] = {
|
||||
__ATTR(class_id, S_IRUGO, i2o_device_show_class_id, NULL),
|
||||
__ATTR(tid, S_IRUGO, i2o_device_show_tid, NULL),
|
||||
__ATTR_NULL
|
||||
static struct attribute *i2o_device_attrs[] = {
|
||||
&dev_attr_class_id.attr,
|
||||
&dev_attr_tid.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group i2o_device_group = {
|
||||
.attrs = i2o_device_attrs,
|
||||
};
|
||||
|
||||
const struct attribute_group *i2o_device_groups[] = {
|
||||
&i2o_device_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -62,7 +62,7 @@ static int i2o_bus_match(struct device *dev, struct device_driver *drv)
|
||||
struct bus_type i2o_bus_type = {
|
||||
.name = "i2o",
|
||||
.match = i2o_bus_match,
|
||||
.dev_attrs = i2o_device_attrs
|
||||
.dev_groups = i2o_device_groups,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -374,8 +374,7 @@ static int mic_probe(struct pci_dev *pdev,
|
||||
"device_create_with_groups failed rc %d\n", rc);
|
||||
goto smpt_uninit;
|
||||
}
|
||||
mdev->state_sysfs = sysfs_get_dirent(mdev->sdev->kobj.sd,
|
||||
NULL, "state");
|
||||
mdev->state_sysfs = sysfs_get_dirent(mdev->sdev->kobj.sd, "state");
|
||||
if (!mdev->state_sysfs) {
|
||||
rc = -ENODEV;
|
||||
dev_err(&pdev->dev, "sysfs_get_dirent failed rc %d\n", rc);
|
||||
|
@ -145,15 +145,17 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr,
|
||||
struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
|
||||
return sprintf(buf, "%x", sock->type);
|
||||
}
|
||||
static DEVICE_ATTR_RO(type);
|
||||
|
||||
static struct device_attribute tifm_dev_attrs[] = {
|
||||
__ATTR(type, S_IRUGO, type_show, NULL),
|
||||
__ATTR_NULL
|
||||
static struct attribute *tifm_dev_attrs[] = {
|
||||
&dev_attr_type.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(tifm_dev);
|
||||
|
||||
static struct bus_type tifm_bus_type = {
|
||||
.name = "tifm",
|
||||
.dev_attrs = tifm_dev_attrs,
|
||||
.dev_groups = tifm_dev_groups,
|
||||
.match = tifm_bus_match,
|
||||
.uevent = tifm_uevent,
|
||||
.probe = tifm_device_probe,
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
|
||||
|
||||
static ssize_t mmc_type_show(struct device *dev,
|
||||
static ssize_t type_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mmc_card *card = mmc_dev_to_card(dev);
|
||||
@ -45,11 +45,13 @@ static ssize_t mmc_type_show(struct device *dev,
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
static DEVICE_ATTR_RO(type);
|
||||
|
||||
static struct device_attribute mmc_dev_attrs[] = {
|
||||
__ATTR(type, S_IRUGO, mmc_type_show, NULL),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *mmc_dev_attrs[] = {
|
||||
&dev_attr_type.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(mmc_dev);
|
||||
|
||||
/*
|
||||
* 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 = {
|
||||
|
||||
static struct bus_type mmc_bus_type = {
|
||||
.name = "mmc",
|
||||
.dev_attrs = mmc_dev_attrs,
|
||||
.dev_groups = mmc_dev_groups,
|
||||
.match = mmc_bus_match,
|
||||
.uevent = mmc_bus_uevent,
|
||||
.probe = mmc_bus_probe,
|
||||
|
@ -34,7 +34,8 @@ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
\
|
||||
func = dev_to_sdio_func (dev); \
|
||||
return sprintf (buf, format_string, func->field); \
|
||||
}
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field)
|
||||
|
||||
sdio_config_attr(class, "0x%02x\n");
|
||||
sdio_config_attr(vendor, "0x%04x\n");
|
||||
@ -47,14 +48,16 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
|
||||
func->class, func->vendor, func->device);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct device_attribute sdio_dev_attrs[] = {
|
||||
__ATTR_RO(class),
|
||||
__ATTR_RO(vendor),
|
||||
__ATTR_RO(device),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *sdio_dev_attrs[] = {
|
||||
&dev_attr_class.attr,
|
||||
&dev_attr_vendor.attr,
|
||||
&dev_attr_device.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(sdio_dev);
|
||||
|
||||
static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
@ -225,7 +228,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {
|
||||
|
||||
static struct bus_type sdio_bus_type = {
|
||||
.name = "sdio",
|
||||
.dev_attrs = sdio_dev_attrs,
|
||||
.dev_groups = sdio_dev_groups,
|
||||
.match = sdio_bus_match,
|
||||
.uevent = sdio_bus_uevent,
|
||||
.probe = sdio_bus_probe,
|
||||
|
@ -655,7 +655,7 @@ static const struct mmc_host_ops mvsd_ops = {
|
||||
.enable_sdio_irq = mvsd_enable_sdio_irq,
|
||||
};
|
||||
|
||||
static void __init
|
||||
static void
|
||||
mv_conf_mbus_windows(struct mvsd_host *host,
|
||||
const struct mbus_dram_target_info *dram)
|
||||
{
|
||||
@ -677,7 +677,7 @@ mv_conf_mbus_windows(struct mvsd_host *host,
|
||||
}
|
||||
}
|
||||
|
||||
static int __init mvsd_probe(struct platform_device *pdev)
|
||||
static int mvsd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct mmc_host *mmc = NULL;
|
||||
@ -819,7 +819,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit mvsd_remove(struct platform_device *pdev)
|
||||
static int mvsd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_host *mmc = platform_get_drvdata(pdev);
|
||||
|
||||
@ -872,7 +872,8 @@ static const struct of_device_id mvsdio_dt_ids[] = {
|
||||
MODULE_DEVICE_TABLE(of, mvsdio_dt_ids);
|
||||
|
||||
static struct platform_driver mvsd_driver = {
|
||||
.remove = __exit_p(mvsd_remove),
|
||||
.probe = mvsd_probe,
|
||||
.remove = mvsd_remove,
|
||||
.suspend = mvsd_suspend,
|
||||
.resume = mvsd_resume,
|
||||
.driver = {
|
||||
@ -881,7 +882,7 @@ static struct platform_driver mvsd_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(mvsd_driver, mvsd_probe);
|
||||
module_platform_driver(mvsd_driver);
|
||||
|
||||
/* maximum card clock frequency (default 50MHz) */
|
||||
module_param(maxfreq, int, 0);
|
||||
|
@ -1139,7 +1139,7 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
struct atmel_nand_host *host)
|
||||
{
|
||||
struct mtd_info *mtd = &host->mtd;
|
||||
@ -1548,7 +1548,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
|
||||
static int atmel_hw_nand_init_params(struct platform_device *pdev,
|
||||
struct atmel_nand_host *host)
|
||||
{
|
||||
struct mtd_info *mtd = &host->mtd;
|
||||
@ -1987,7 +1987,7 @@ static struct platform_driver atmel_nand_nfc_driver;
|
||||
/*
|
||||
* Probe for the NAND device.
|
||||
*/
|
||||
static int __init atmel_nand_probe(struct platform_device *pdev)
|
||||
static int atmel_nand_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_nand_host *host;
|
||||
struct mtd_info *mtd;
|
||||
@ -2184,7 +2184,7 @@ err_nand_ioremap:
|
||||
/*
|
||||
* Remove a NAND device.
|
||||
*/
|
||||
static int __exit atmel_nand_remove(struct platform_device *pdev)
|
||||
static int atmel_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_nand_host *host = platform_get_drvdata(pdev);
|
||||
struct mtd_info *mtd = &host->mtd;
|
||||
@ -2270,7 +2270,8 @@ static struct platform_driver atmel_nand_nfc_driver = {
|
||||
};
|
||||
|
||||
static struct platform_driver atmel_nand_driver = {
|
||||
.remove = __exit_p(atmel_nand_remove),
|
||||
.probe = atmel_nand_probe,
|
||||
.remove = atmel_nand_remove,
|
||||
.driver = {
|
||||
.name = "atmel_nand",
|
||||
.owner = THIS_MODULE,
|
||||
@ -2278,7 +2279,7 @@ static struct platform_driver atmel_nand_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(atmel_nand_driver, atmel_nand_probe);
|
||||
module_platform_driver(atmel_nand_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Rick Bronson");
|
||||
|
@ -149,14 +149,6 @@ err_no_cmd:
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static const void *bonding_namespace(struct class *cls,
|
||||
const struct class_attribute *attr)
|
||||
{
|
||||
const struct bond_net *bn =
|
||||
container_of(attr, struct bond_net, class_attr_bonding_masters);
|
||||
return bn->net;
|
||||
}
|
||||
|
||||
/* class attribute for bond_masters file. This ends up in /sys/class/net */
|
||||
static const struct class_attribute class_attr_bonding_masters = {
|
||||
.attr = {
|
||||
@ -165,7 +157,6 @@ static const struct class_attribute class_attr_bonding_masters = {
|
||||
},
|
||||
.show = bonding_show_bonds,
|
||||
.store = bonding_store_bonds,
|
||||
.namespace = bonding_namespace,
|
||||
};
|
||||
|
||||
int bond_create_slave_symlinks(struct net_device *master,
|
||||
@ -1787,7 +1778,8 @@ int bond_create_sysfs(struct bond_net *bn)
|
||||
bn->class_attr_bonding_masters = class_attr_bonding_masters;
|
||||
sysfs_attr_init(&bn->class_attr_bonding_masters.attr);
|
||||
|
||||
ret = netdev_class_create_file(&bn->class_attr_bonding_masters);
|
||||
ret = netdev_class_create_file_ns(&bn->class_attr_bonding_masters,
|
||||
bn->net);
|
||||
/*
|
||||
* Permit multiple loads of the module by ignoring failures to
|
||||
* create the bonding_masters sysfs file. Bonding devices
|
||||
@ -1817,7 +1809,7 @@ int bond_create_sysfs(struct bond_net *bn)
|
||||
*/
|
||||
void bond_destroy_sysfs(struct bond_net *bn)
|
||||
{
|
||||
netdev_class_remove_file(&bn->class_attr_bonding_masters);
|
||||
netdev_class_remove_file_ns(&bn->class_attr_bonding_masters, bn->net);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -438,17 +438,19 @@ phy_id_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
||||
return sprintf(buf, "0x%.8lx\n", (unsigned long)phydev->phy_id);
|
||||
}
|
||||
static DEVICE_ATTR_RO(phy_id);
|
||||
|
||||
static struct device_attribute mdio_dev_attrs[] = {
|
||||
__ATTR_RO(phy_id),
|
||||
__ATTR_NULL
|
||||
static struct attribute *mdio_dev_attrs[] = {
|
||||
&dev_attr_phy_id.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(mdio_dev);
|
||||
|
||||
struct bus_type mdio_bus_type = {
|
||||
.name = "mdio_bus",
|
||||
.match = mdio_bus_match,
|
||||
.pm = MDIO_BUS_PM_OPS,
|
||||
.dev_attrs = mdio_dev_attrs,
|
||||
.dev_groups = mdio_dev_groups,
|
||||
};
|
||||
EXPORT_SYMBOL(mdio_bus_type);
|
||||
|
||||
|
@ -135,6 +135,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
|
||||
return retval;
|
||||
return count;
|
||||
}
|
||||
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
return retval;
|
||||
return count;
|
||||
}
|
||||
static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
|
||||
|
||||
static struct driver_attribute pci_drv_attrs[] = {
|
||||
__ATTR(new_id, S_IWUSR, NULL, store_new_id),
|
||||
__ATTR(remove_id, S_IWUSR, NULL, store_remove_id),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *pci_drv_attrs[] = {
|
||||
&driver_attr_new_id.attr,
|
||||
&driver_attr_remove_id.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(pci_drv);
|
||||
|
||||
/**
|
||||
* pci_match_id - See if a pci device matches a given pci_id table
|
||||
@ -1317,8 +1320,8 @@ struct bus_type pci_bus_type = {
|
||||
.remove = pci_device_remove,
|
||||
.shutdown = pci_device_shutdown,
|
||||
.dev_attrs = pci_dev_attrs,
|
||||
.bus_attrs = pci_bus_attrs,
|
||||
.drv_attrs = pci_drv_attrs,
|
||||
.bus_groups = pci_bus_groups,
|
||||
.drv_groups = pci_drv_groups,
|
||||
.pm = PCI_PM_OPS_PTR,
|
||||
};
|
||||
|
||||
|
@ -302,10 +302,20 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
|
||||
}
|
||||
return count;
|
||||
}
|
||||
static BUS_ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store);
|
||||
|
||||
struct bus_attribute pci_bus_attrs[] = {
|
||||
__ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store),
|
||||
__ATTR_NULL
|
||||
struct attribute *pci_bus_attrs[] = {
|
||||
&bus_attr_rescan.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group pci_bus_group = {
|
||||
.attrs = pci_bus_attrs,
|
||||
};
|
||||
|
||||
const struct attribute_group *pci_bus_groups[] = {
|
||||
&pci_bus_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
|
@ -156,7 +156,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
|
||||
extern struct device_attribute pci_dev_attrs[];
|
||||
extern const struct attribute_group *pcibus_groups[];
|
||||
extern struct device_type pci_dev_type;
|
||||
extern struct bus_attribute pci_bus_attrs[];
|
||||
extern const struct attribute_group *pci_bus_groups[];
|
||||
|
||||
|
||||
/**
|
||||
|
@ -245,7 +245,7 @@ static int at91_cf_dt_init(struct platform_device *pdev)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init at91_cf_probe(struct platform_device *pdev)
|
||||
static int at91_cf_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct at91_cf_socket *cf;
|
||||
struct at91_cf_data *board = pdev->dev.platform_data;
|
||||
@ -354,7 +354,7 @@ fail0a:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __exit at91_cf_remove(struct platform_device *pdev)
|
||||
static int at91_cf_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct at91_cf_socket *cf = platform_get_drvdata(pdev);
|
||||
|
||||
@ -404,14 +404,13 @@ static struct platform_driver at91_cf_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(at91_cf_dt_ids),
|
||||
},
|
||||
.remove = __exit_p(at91_cf_remove),
|
||||
.probe = at91_cf_probe,
|
||||
.remove = at91_cf_remove,
|
||||
.suspend = at91_cf_suspend,
|
||||
.resume = at91_cf_resume,
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
module_platform_driver_probe(at91_cf_driver, at91_cf_probe);
|
||||
module_platform_driver(at91_cf_driver);
|
||||
|
||||
MODULE_DESCRIPTION("AT91 Compact Flash Driver");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
@ -992,16 +992,17 @@ static ssize_t field##_show (struct device *dev, struct device_attribute *attr,
|
||||
{ \
|
||||
struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
|
||||
return p_dev->test ? sprintf(buf, format, p_dev->field) : -ENODEV; \
|
||||
}
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field);
|
||||
|
||||
#define pcmcia_device_stringattr(name, field) \
|
||||
static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
|
||||
return p_dev->field ? sprintf(buf, "%s\n", p_dev->field) : -ENODEV; \
|
||||
}
|
||||
} \
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
pcmcia_device_attr(func, socket, "0x%02x\n");
|
||||
pcmcia_device_attr(func_id, has_func_id, "0x%02x\n");
|
||||
pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n");
|
||||
pcmcia_device_attr(card_id, has_card_id, "0x%04x\n");
|
||||
@ -1010,8 +1011,16 @@ pcmcia_device_stringattr(prod_id2, prod_id[1]);
|
||||
pcmcia_device_stringattr(prod_id3, prod_id[2]);
|
||||
pcmcia_device_stringattr(prod_id4, prod_id[3]);
|
||||
|
||||
static ssize_t pcmcia_show_resources(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t function_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
|
||||
return p_dev->socket ? sprintf(buf, "0x%02x\n", p_dev->func) : -ENODEV;
|
||||
}
|
||||
static DEVICE_ATTR_RO(function);
|
||||
|
||||
static ssize_t resources_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
|
||||
char *str = buf;
|
||||
@ -1022,8 +1031,9 @@ static ssize_t pcmcia_show_resources(struct device *dev,
|
||||
|
||||
return str - buf;
|
||||
}
|
||||
static DEVICE_ATTR_RO(resources);
|
||||
|
||||
static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t pm_state_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
|
||||
|
||||
@ -1033,8 +1043,8 @@ static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute
|
||||
return sprintf(buf, "on\n");
|
||||
}
|
||||
|
||||
static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t pm_state_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
|
||||
int ret = 0;
|
||||
@ -1049,7 +1059,7 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute
|
||||
|
||||
return ret ? ret : count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(pm_state);
|
||||
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -1072,8 +1082,9 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
p_dev->func, p_dev->device_no,
|
||||
hash[0], hash[1], hash[2], hash[3]);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static ssize_t pcmcia_store_allow_func_id_match(struct device *dev,
|
||||
static ssize_t allow_func_id_match_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
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,
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_WO(allow_func_id_match);
|
||||
|
||||
static struct device_attribute pcmcia_dev_attrs[] = {
|
||||
__ATTR(function, 0444, func_show, NULL),
|
||||
__ATTR(pm_state, 0644, pcmcia_show_pm_state, pcmcia_store_pm_state),
|
||||
__ATTR(resources, 0444, pcmcia_show_resources, NULL),
|
||||
__ATTR_RO(func_id),
|
||||
__ATTR_RO(manf_id),
|
||||
__ATTR_RO(card_id),
|
||||
__ATTR_RO(prod_id1),
|
||||
__ATTR_RO(prod_id2),
|
||||
__ATTR_RO(prod_id3),
|
||||
__ATTR_RO(prod_id4),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *pcmcia_dev_attrs[] = {
|
||||
&dev_attr_resources.attr,
|
||||
&dev_attr_pm_state.attr,
|
||||
&dev_attr_function.attr,
|
||||
&dev_attr_func_id.attr,
|
||||
&dev_attr_manf_id.attr,
|
||||
&dev_attr_card_id.attr,
|
||||
&dev_attr_prod_id1.attr,
|
||||
&dev_attr_prod_id2.attr,
|
||||
&dev_attr_prod_id3.attr,
|
||||
&dev_attr_prod_id4.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_allow_func_id_match.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(pcmcia_dev);
|
||||
|
||||
/* PM support, also needed for reset */
|
||||
|
||||
@ -1389,7 +1402,7 @@ struct bus_type pcmcia_bus_type = {
|
||||
.name = "pcmcia",
|
||||
.uevent = pcmcia_bus_uevent,
|
||||
.match = pcmcia_bus_match,
|
||||
.dev_attrs = pcmcia_dev_attrs,
|
||||
.dev_groups = pcmcia_dev_groups,
|
||||
.probe = pcmcia_device_probe,
|
||||
.remove = pcmcia_device_remove,
|
||||
.suspend = pcmcia_dev_suspend,
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
extern spinlock_t pnp_lock;
|
||||
extern struct device_attribute pnp_interface_attrs[];
|
||||
extern const struct attribute_group *pnp_dev_groups[];
|
||||
void *pnp_alloc(long size);
|
||||
|
||||
int pnp_register_protocol(struct pnp_protocol *protocol);
|
||||
|
@ -246,7 +246,7 @@ struct bus_type pnp_bus_type = {
|
||||
.remove = pnp_device_remove,
|
||||
.shutdown = pnp_device_shutdown,
|
||||
.pm = &pnp_bus_dev_pm_ops,
|
||||
.dev_attrs = pnp_interface_attrs,
|
||||
.dev_groups = pnp_dev_groups,
|
||||
};
|
||||
|
||||
int pnp_register_driver(struct pnp_driver *drv)
|
||||
|
@ -203,8 +203,8 @@ static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t pnp_show_options(struct device *dmdev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t options_show(struct device *dmdev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct pnp_dev *dev = to_pnp_dev(dmdev);
|
||||
pnp_info_buffer_t *buffer;
|
||||
@ -241,10 +241,10 @@ static ssize_t pnp_show_options(struct device *dmdev,
|
||||
kfree(buffer);
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR_RO(options);
|
||||
|
||||
static ssize_t pnp_show_current_resources(struct device *dmdev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
static ssize_t resources_show(struct device *dmdev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pnp_dev *dev = to_pnp_dev(dmdev);
|
||||
pnp_info_buffer_t *buffer;
|
||||
@ -331,9 +331,9 @@ static char *pnp_get_resource_value(char *buf,
|
||||
return buf;
|
||||
}
|
||||
|
||||
static ssize_t pnp_set_current_resources(struct device *dmdev,
|
||||
struct device_attribute *attr,
|
||||
const char *ubuf, size_t count)
|
||||
static ssize_t resources_store(struct device *dmdev,
|
||||
struct device_attribute *attr, const char *ubuf,
|
||||
size_t count)
|
||||
{
|
||||
struct pnp_dev *dev = to_pnp_dev(dmdev);
|
||||
char *buf = (void *)ubuf;
|
||||
@ -434,9 +434,10 @@ done:
|
||||
return retval;
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(resources);
|
||||
|
||||
static ssize_t pnp_show_current_ids(struct device *dmdev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t id_show(struct device *dmdev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
char *str = buf;
|
||||
struct pnp_dev *dev = to_pnp_dev(dmdev);
|
||||
@ -448,12 +449,20 @@ static ssize_t pnp_show_current_ids(struct device *dmdev,
|
||||
}
|
||||
return (str - buf);
|
||||
}
|
||||
static DEVICE_ATTR_RO(id);
|
||||
|
||||
struct device_attribute pnp_interface_attrs[] = {
|
||||
__ATTR(resources, S_IRUGO | S_IWUSR,
|
||||
pnp_show_current_resources,
|
||||
pnp_set_current_resources),
|
||||
__ATTR(options, S_IRUGO, pnp_show_options, NULL),
|
||||
__ATTR(id, S_IRUGO, pnp_show_current_ids, NULL),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *pnp_dev_attrs[] = {
|
||||
&dev_attr_resources.attr,
|
||||
&dev_attr_options.attr,
|
||||
&dev_attr_id.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group pnp_dev_group = {
|
||||
.attrs = pnp_dev_attrs,
|
||||
};
|
||||
|
||||
const struct attribute_group *pnp_dev_groups[] = {
|
||||
&pnp_dev_group,
|
||||
NULL,
|
||||
};
|
||||
|
@ -223,8 +223,8 @@ struct device rio_bus = {
|
||||
struct bus_type rio_bus_type = {
|
||||
.name = "rapidio",
|
||||
.match = rio_match_bus,
|
||||
.dev_attrs = rio_dev_attrs,
|
||||
.bus_attrs = rio_bus_attrs,
|
||||
.dev_groups = rio_dev_groups,
|
||||
.bus_groups = rio_bus_groups,
|
||||
.probe = rio_device_probe,
|
||||
.remove = rio_device_remove,
|
||||
.uevent = rio_uevent,
|
||||
|
@ -27,6 +27,7 @@ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
\
|
||||
return sprintf(buf, format_string, rdev->field); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field);
|
||||
|
||||
rio_config_attr(did, "0x%04x\n");
|
||||
rio_config_attr(vid, "0x%04x\n");
|
||||
@ -54,6 +55,7 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch
|
||||
|
||||
return (str - buf);
|
||||
}
|
||||
static DEVICE_ATTR_RO(routes);
|
||||
|
||||
static ssize_t lprev_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
@ -63,6 +65,7 @@ static ssize_t lprev_show(struct device *dev,
|
||||
return sprintf(buf, "%s\n",
|
||||
(rdev->prev) ? rio_name(rdev->prev) : "root");
|
||||
}
|
||||
static DEVICE_ATTR_RO(lprev);
|
||||
|
||||
static ssize_t lnext_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
@ -83,6 +86,7 @@ static ssize_t lnext_show(struct device *dev,
|
||||
|
||||
return str - buf;
|
||||
}
|
||||
static DEVICE_ATTR_RO(lnext);
|
||||
|
||||
static ssize_t modalias_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
@ -92,23 +96,29 @@ static ssize_t modalias_show(struct device *dev,
|
||||
return sprintf(buf, "rapidio:v%04Xd%04Xav%04Xad%04X\n",
|
||||
rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
struct device_attribute rio_dev_attrs[] = {
|
||||
__ATTR_RO(did),
|
||||
__ATTR_RO(vid),
|
||||
__ATTR_RO(device_rev),
|
||||
__ATTR_RO(asm_did),
|
||||
__ATTR_RO(asm_vid),
|
||||
__ATTR_RO(asm_rev),
|
||||
__ATTR_RO(lprev),
|
||||
__ATTR_RO(destid),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *rio_dev_attrs[] = {
|
||||
&dev_attr_did.attr,
|
||||
&dev_attr_vid.attr,
|
||||
&dev_attr_device_rev.attr,
|
||||
&dev_attr_asm_did.attr,
|
||||
&dev_attr_asm_vid.attr,
|
||||
&dev_attr_asm_rev.attr,
|
||||
&dev_attr_lprev.attr,
|
||||
&dev_attr_destid.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL);
|
||||
static DEVICE_ATTR(lnext, S_IRUGO, lnext_show, NULL);
|
||||
static DEVICE_ATTR(hopcount, S_IRUGO, hopcount_show, NULL);
|
||||
static const struct attribute_group rio_dev_group = {
|
||||
.attrs = rio_dev_attrs,
|
||||
};
|
||||
|
||||
const struct attribute_group *rio_dev_groups[] = {
|
||||
&rio_dev_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
rio_read_config(struct file *filp, struct kobject *kobj,
|
||||
@ -316,8 +326,18 @@ exit:
|
||||
|
||||
return rc;
|
||||
}
|
||||
static BUS_ATTR(scan, (S_IWUSR|S_IWGRP), NULL, bus_scan_store);
|
||||
|
||||
struct bus_attribute rio_bus_attrs[] = {
|
||||
__ATTR(scan, (S_IWUSR|S_IWGRP), NULL, bus_scan_store),
|
||||
__ATTR_NULL
|
||||
static struct attribute *rio_bus_attrs[] = {
|
||||
&bus_attr_scan.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group rio_bus_group = {
|
||||
.attrs = rio_bus_attrs,
|
||||
};
|
||||
|
||||
const struct attribute_group *rio_bus_groups[] = {
|
||||
&rio_bus_group,
|
||||
NULL,
|
||||
};
|
||||
|
@ -48,8 +48,8 @@ extern struct rio_mport *rio_find_mport(int mport_id);
|
||||
extern int rio_mport_scan(int mport_id);
|
||||
|
||||
/* Structures internal to the RIO core code */
|
||||
extern struct device_attribute rio_dev_attrs[];
|
||||
extern struct bus_attribute rio_bus_attrs[];
|
||||
extern const struct attribute_group *rio_dev_groups[];
|
||||
extern const struct attribute_group *rio_bus_groups[];
|
||||
|
||||
#define RIO_GET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
|
||||
#define RIO_SET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
|
||||
|
@ -553,16 +553,20 @@ static struct device_type fcoe_fcf_device_type = {
|
||||
.release = fcoe_fcf_device_release,
|
||||
};
|
||||
|
||||
static struct bus_attribute fcoe_bus_attr_group[] = {
|
||||
__ATTR(ctlr_create, S_IWUSR, NULL, fcoe_ctlr_create_store),
|
||||
__ATTR(ctlr_destroy, S_IWUSR, NULL, fcoe_ctlr_destroy_store),
|
||||
__ATTR_NULL
|
||||
static BUS_ATTR(ctlr_create, S_IWUSR, NULL, fcoe_ctlr_create_store);
|
||||
static BUS_ATTR(ctlr_destroy, S_IWUSR, NULL, fcoe_ctlr_destroy_store);
|
||||
|
||||
static struct attribute *fcoe_bus_attrs[] = {
|
||||
&bus_attr_ctlr_create.attr,
|
||||
&bus_attr_ctlr_destroy.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(fcoe_bus);
|
||||
|
||||
static struct bus_type fcoe_bus_type = {
|
||||
.name = "fcoe",
|
||||
.match = &fcoe_bus_match,
|
||||
.bus_attrs = fcoe_bus_attr_group,
|
||||
.bus_groups = fcoe_bus_groups,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -374,7 +374,8 @@ static ssize_t \
|
||||
attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
|
||||
}
|
||||
} \
|
||||
static DEVICE_ATTR_RO(attrib);
|
||||
|
||||
ssb_config_attr(core_num, core_index, "%u\n")
|
||||
ssb_config_attr(coreid, id.coreid, "0x%04x\n")
|
||||
@ -387,16 +388,18 @@ name_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
return sprintf(buf, "%s\n",
|
||||
ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
|
||||
}
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
static struct device_attribute ssb_device_attrs[] = {
|
||||
__ATTR_RO(name),
|
||||
__ATTR_RO(core_num),
|
||||
__ATTR_RO(coreid),
|
||||
__ATTR_RO(vendor),
|
||||
__ATTR_RO(revision),
|
||||
__ATTR_RO(irq),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *ssb_device_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_core_num.attr,
|
||||
&dev_attr_coreid.attr,
|
||||
&dev_attr_vendor.attr,
|
||||
&dev_attr_revision.attr,
|
||||
&dev_attr_irq.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ssb_device);
|
||||
|
||||
static struct bus_type ssb_bustype = {
|
||||
.name = "ssb",
|
||||
@ -407,7 +410,7 @@ static struct bus_type ssb_bustype = {
|
||||
.suspend = ssb_device_suspend,
|
||||
.resume = ssb_device_resume,
|
||||
.uevent = ssb_device_uevent,
|
||||
.dev_attrs = ssb_device_attrs,
|
||||
.dev_groups = ssb_device_groups,
|
||||
};
|
||||
|
||||
static void ssb_buses_lock(void)
|
||||
|
@ -201,6 +201,7 @@ static ssize_t capability_id_show(struct device *dev, struct device_attribute *a
|
||||
|
||||
return sprintf(buf, "0x%02x\n", umc->cap_id);
|
||||
}
|
||||
static DEVICE_ATTR_RO(capability_id);
|
||||
|
||||
static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -208,12 +209,14 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, c
|
||||
|
||||
return sprintf(buf, "0x%04x\n", umc->version);
|
||||
}
|
||||
static DEVICE_ATTR_RO(version);
|
||||
|
||||
static struct device_attribute umc_dev_attrs[] = {
|
||||
__ATTR_RO(capability_id),
|
||||
__ATTR_RO(version),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *umc_dev_attrs[] = {
|
||||
&dev_attr_capability_id.attr,
|
||||
&dev_attr_version.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(umc_dev);
|
||||
|
||||
struct bus_type umc_bus_type = {
|
||||
.name = "umc",
|
||||
@ -222,7 +225,7 @@ struct bus_type umc_bus_type = {
|
||||
.remove = umc_device_remove,
|
||||
.suspend = umc_device_suspend,
|
||||
.resume = umc_device_resume,
|
||||
.dev_attrs = umc_dev_attrs,
|
||||
.dev_groups = umc_dev_groups,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(umc_bus_type);
|
||||
|
||||
|
@ -118,7 +118,7 @@ static const struct backlight_ops atmel_pwm_bl_ops = {
|
||||
.update_status = atmel_pwm_bl_set_intensity,
|
||||
};
|
||||
|
||||
static int __init atmel_pwm_bl_probe(struct platform_device *pdev)
|
||||
static int atmel_pwm_bl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct backlight_properties props;
|
||||
const struct atmel_pwm_bl_platform_data *pdata;
|
||||
@ -202,7 +202,7 @@ err_free_mem:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int __exit atmel_pwm_bl_remove(struct platform_device *pdev)
|
||||
static int atmel_pwm_bl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev);
|
||||
|
||||
@ -220,10 +220,11 @@ static struct platform_driver atmel_pwm_bl_driver = {
|
||||
.name = "atmel-pwm-bl",
|
||||
},
|
||||
/* REVISIT add suspend() and resume() */
|
||||
.remove = __exit_p(atmel_pwm_bl_remove),
|
||||
.probe = atmel_pwm_bl_probe,
|
||||
.remove = atmel_pwm_bl_remove,
|
||||
};
|
||||
|
||||
module_platform_driver_probe(atmel_pwm_bl_driver, atmel_pwm_bl_probe);
|
||||
module_platform_driver(atmel_pwm_bl_driver);
|
||||
|
||||
MODULE_AUTHOR("Hans-Christian egtvedt <hans-christian.egtvedt@atmel.com>");
|
||||
MODULE_DESCRIPTION("Atmel PWM backlight driver");
|
||||
|
@ -13,18 +13,24 @@ static ssize_t device_show(struct device *_d,
|
||||
struct virtio_device *dev = dev_to_virtio(_d);
|
||||
return sprintf(buf, "0x%04x\n", dev->id.device);
|
||||
}
|
||||
static DEVICE_ATTR_RO(device);
|
||||
|
||||
static ssize_t vendor_show(struct device *_d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct virtio_device *dev = dev_to_virtio(_d);
|
||||
return sprintf(buf, "0x%04x\n", dev->id.vendor);
|
||||
}
|
||||
static DEVICE_ATTR_RO(vendor);
|
||||
|
||||
static ssize_t status_show(struct device *_d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct virtio_device *dev = dev_to_virtio(_d);
|
||||
return sprintf(buf, "0x%08x\n", dev->config->get_status(dev));
|
||||
}
|
||||
static DEVICE_ATTR_RO(status);
|
||||
|
||||
static ssize_t modalias_show(struct device *_d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -32,6 +38,8 @@ static ssize_t modalias_show(struct device *_d,
|
||||
return sprintf(buf, "virtio:d%08Xv%08X\n",
|
||||
dev->id.device, dev->id.vendor);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static ssize_t features_show(struct device *_d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -47,14 +55,17 @@ static ssize_t features_show(struct device *_d,
|
||||
len += sprintf(buf+len, "\n");
|
||||
return len;
|
||||
}
|
||||
static struct device_attribute virtio_dev_attrs[] = {
|
||||
__ATTR_RO(device),
|
||||
__ATTR_RO(vendor),
|
||||
__ATTR_RO(status),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_RO(features),
|
||||
__ATTR_NULL
|
||||
static DEVICE_ATTR_RO(features);
|
||||
|
||||
static struct attribute *virtio_dev_attrs[] = {
|
||||
&dev_attr_device.attr,
|
||||
&dev_attr_vendor.attr,
|
||||
&dev_attr_status.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_features.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(virtio_dev);
|
||||
|
||||
static inline int virtio_id_match(const struct virtio_device *dev,
|
||||
const struct virtio_device_id *id)
|
||||
@ -165,7 +176,7 @@ static int virtio_dev_remove(struct device *_d)
|
||||
static struct bus_type virtio_bus = {
|
||||
.name = "virtio",
|
||||
.match = virtio_dev_match,
|
||||
.dev_attrs = virtio_dev_attrs,
|
||||
.dev_groups = virtio_dev_groups,
|
||||
.uevent = virtio_uevent,
|
||||
.probe = virtio_dev_probe,
|
||||
.remove = virtio_dev_remove,
|
||||
|
@ -384,12 +384,14 @@ static ssize_t nodename_show(struct device *dev,
|
||||
{
|
||||
return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
|
||||
}
|
||||
static DEVICE_ATTR_RO(nodename);
|
||||
|
||||
static ssize_t devtype_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
|
||||
}
|
||||
static DEVICE_ATTR_RO(devtype);
|
||||
|
||||
static ssize_t modalias_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
@ -397,14 +399,24 @@ static ssize_t modalias_show(struct device *dev,
|
||||
return sprintf(buf, "%s:%s\n", dev->bus->name,
|
||||
to_xenbus_device(dev)->devicetype);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
struct device_attribute xenbus_dev_attrs[] = {
|
||||
__ATTR_RO(nodename),
|
||||
__ATTR_RO(devtype),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL
|
||||
static struct attribute *xenbus_dev_attrs[] = {
|
||||
&dev_attr_nodename.attr,
|
||||
&dev_attr_devtype.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(xenbus_dev_attrs);
|
||||
|
||||
static const struct attribute_group xenbus_dev_group = {
|
||||
.attrs = xenbus_dev_attrs,
|
||||
};
|
||||
|
||||
const struct attribute_group *xenbus_dev_groups[] = {
|
||||
&xenbus_dev_group,
|
||||
NULL,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(xenbus_dev_groups);
|
||||
|
||||
int xenbus_probe_node(struct xen_bus_type *bus,
|
||||
const char *type,
|
||||
|
@ -54,7 +54,7 @@ enum xenstore_init {
|
||||
XS_LOCAL,
|
||||
};
|
||||
|
||||
extern struct device_attribute xenbus_dev_attrs[];
|
||||
extern const struct attribute_group *xenbus_dev_groups[];
|
||||
|
||||
extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
|
||||
extern int xenbus_dev_probe(struct device *_dev);
|
||||
|
@ -200,7 +200,7 @@ static struct xen_bus_type xenbus_backend = {
|
||||
.probe = xenbus_dev_probe,
|
||||
.remove = xenbus_dev_remove,
|
||||
.shutdown = xenbus_dev_shutdown,
|
||||
.dev_attrs = xenbus_dev_attrs,
|
||||
.dev_groups = xenbus_dev_groups,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -154,7 +154,7 @@ static struct xen_bus_type xenbus_frontend = {
|
||||
.probe = xenbus_frontend_dev_probe,
|
||||
.remove = xenbus_dev_remove,
|
||||
.shutdown = xenbus_dev_shutdown,
|
||||
.dev_attrs = xenbus_dev_attrs,
|
||||
.dev_groups = xenbus_dev_groups,
|
||||
|
||||
.pm = &xenbus_pm_ops,
|
||||
},
|
||||
|
@ -2,5 +2,4 @@
|
||||
# Makefile for the sysfs virtual filesystem
|
||||
#
|
||||
|
||||
obj-y := inode.o file.o dir.o symlink.o mount.o bin.o \
|
||||
group.o
|
||||
obj-y := inode.o file.o dir.o symlink.o mount.o group.o
|
||||
|
502
fs/sysfs/bin.c
502
fs/sysfs/bin.c
@ -1,502 +0,0 @@
|
||||
/*
|
||||
* fs/sysfs/bin.c - sysfs binary file implementation
|
||||
*
|
||||
* Copyright (c) 2003 Patrick Mochel
|
||||
* Copyright (c) 2003 Matthew Wilcox
|
||||
* Copyright (c) 2004 Silicon Graphics, Inc.
|
||||
* Copyright (c) 2007 SUSE Linux Products GmbH
|
||||
* Copyright (c) 2007 Tejun Heo <teheo@suse.de>
|
||||
*
|
||||
* This file is released under the GPLv2.
|
||||
*
|
||||
* Please see Documentation/filesystems/sysfs.txt for more information.
|
||||
*/
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "sysfs.h"
|
||||
|
||||
/*
|
||||
* There's one bin_buffer for each open file.
|
||||
*
|
||||
* filp->private_data points to bin_buffer and
|
||||
* sysfs_dirent->s_bin_attr.buffers points to a the bin_buffer s
|
||||
* sysfs_dirent->s_bin_attr.buffers is protected by sysfs_bin_lock
|
||||
*/
|
||||
static DEFINE_MUTEX(sysfs_bin_lock);
|
||||
|
||||
struct bin_buffer {
|
||||
struct mutex mutex;
|
||||
void *buffer;
|
||||
int mmapped;
|
||||
const struct vm_operations_struct *vm_ops;
|
||||
struct file *file;
|
||||
struct hlist_node list;
|
||||
};
|
||||
|
||||
static int
|
||||
fill_read(struct file *file, char *buffer, loff_t off, size_t count)
|
||||
{
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
|
||||
int rc;
|
||||
|
||||
/* need attr_sd for attr, its parent for kobj */
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
return -ENODEV;
|
||||
|
||||
rc = -EIO;
|
||||
if (attr->read)
|
||||
rc = attr->read(file, kobj, attr, buffer, off, count);
|
||||
|
||||
sysfs_put_active(attr_sd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
|
||||
{
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
int size = file_inode(file)->i_size;
|
||||
loff_t offs = *off;
|
||||
int count = min_t(size_t, bytes, PAGE_SIZE);
|
||||
char *temp;
|
||||
|
||||
if (!bytes)
|
||||
return 0;
|
||||
|
||||
if (size) {
|
||||
if (offs > size)
|
||||
return 0;
|
||||
if (offs + count > size)
|
||||
count = size - offs;
|
||||
}
|
||||
|
||||
temp = kmalloc(count, GFP_KERNEL);
|
||||
if (!temp)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&bb->mutex);
|
||||
|
||||
count = fill_read(file, bb->buffer, offs, count);
|
||||
if (count < 0) {
|
||||
mutex_unlock(&bb->mutex);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
memcpy(temp, bb->buffer, count);
|
||||
|
||||
mutex_unlock(&bb->mutex);
|
||||
|
||||
if (copy_to_user(userbuf, temp, count)) {
|
||||
count = -EFAULT;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);
|
||||
|
||||
*off = offs + count;
|
||||
|
||||
out_free:
|
||||
kfree(temp);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int
|
||||
flush_write(struct file *file, char *buffer, loff_t offset, size_t count)
|
||||
{
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
|
||||
int rc;
|
||||
|
||||
/* need attr_sd for attr, its parent for kobj */
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
return -ENODEV;
|
||||
|
||||
rc = -EIO;
|
||||
if (attr->write)
|
||||
rc = attr->write(file, kobj, attr, buffer, offset, count);
|
||||
|
||||
sysfs_put_active(attr_sd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t write(struct file *file, const char __user *userbuf,
|
||||
size_t bytes, loff_t *off)
|
||||
{
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
int size = file_inode(file)->i_size;
|
||||
loff_t offs = *off;
|
||||
int count = min_t(size_t, bytes, PAGE_SIZE);
|
||||
char *temp;
|
||||
|
||||
if (!bytes)
|
||||
return 0;
|
||||
|
||||
if (size) {
|
||||
if (offs > size)
|
||||
return 0;
|
||||
if (offs + count > size)
|
||||
count = size - offs;
|
||||
}
|
||||
|
||||
temp = memdup_user(userbuf, count);
|
||||
if (IS_ERR(temp))
|
||||
return PTR_ERR(temp);
|
||||
|
||||
mutex_lock(&bb->mutex);
|
||||
|
||||
memcpy(bb->buffer, temp, count);
|
||||
|
||||
count = flush_write(file, bb->buffer, offs, count);
|
||||
mutex_unlock(&bb->mutex);
|
||||
|
||||
if (count > 0)
|
||||
*off = offs + count;
|
||||
|
||||
kfree(temp);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void bin_vma_open(struct vm_area_struct *vma)
|
||||
{
|
||||
struct file *file = vma->vm_file;
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
|
||||
if (!bb->vm_ops)
|
||||
return;
|
||||
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
return;
|
||||
|
||||
if (bb->vm_ops->open)
|
||||
bb->vm_ops->open(vma);
|
||||
|
||||
sysfs_put_active(attr_sd);
|
||||
}
|
||||
|
||||
static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
{
|
||||
struct file *file = vma->vm_file;
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
int ret;
|
||||
|
||||
if (!bb->vm_ops)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
ret = VM_FAULT_SIGBUS;
|
||||
if (bb->vm_ops->fault)
|
||||
ret = bb->vm_ops->fault(vma, vmf);
|
||||
|
||||
sysfs_put_active(attr_sd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
{
|
||||
struct file *file = vma->vm_file;
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
int ret;
|
||||
|
||||
if (!bb->vm_ops)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
ret = 0;
|
||||
if (bb->vm_ops->page_mkwrite)
|
||||
ret = bb->vm_ops->page_mkwrite(vma, vmf);
|
||||
else
|
||||
file_update_time(file);
|
||||
|
||||
sysfs_put_active(attr_sd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bin_access(struct vm_area_struct *vma, unsigned long addr,
|
||||
void *buf, int len, int write)
|
||||
{
|
||||
struct file *file = vma->vm_file;
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
int ret;
|
||||
|
||||
if (!bb->vm_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
return -EINVAL;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (bb->vm_ops->access)
|
||||
ret = bb->vm_ops->access(vma, addr, buf, len, write);
|
||||
|
||||
sysfs_put_active(attr_sd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
static int bin_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
|
||||
{
|
||||
struct file *file = vma->vm_file;
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
int ret;
|
||||
|
||||
if (!bb->vm_ops)
|
||||
return 0;
|
||||
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
return -EINVAL;
|
||||
|
||||
ret = 0;
|
||||
if (bb->vm_ops->set_policy)
|
||||
ret = bb->vm_ops->set_policy(vma, new);
|
||||
|
||||
sysfs_put_active(attr_sd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct mempolicy *bin_get_policy(struct vm_area_struct *vma,
|
||||
unsigned long addr)
|
||||
{
|
||||
struct file *file = vma->vm_file;
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
struct mempolicy *pol;
|
||||
|
||||
if (!bb->vm_ops)
|
||||
return vma->vm_policy;
|
||||
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
return vma->vm_policy;
|
||||
|
||||
pol = vma->vm_policy;
|
||||
if (bb->vm_ops->get_policy)
|
||||
pol = bb->vm_ops->get_policy(vma, addr);
|
||||
|
||||
sysfs_put_active(attr_sd);
|
||||
return pol;
|
||||
}
|
||||
|
||||
static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from,
|
||||
const nodemask_t *to, unsigned long flags)
|
||||
{
|
||||
struct file *file = vma->vm_file;
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
int ret;
|
||||
|
||||
if (!bb->vm_ops)
|
||||
return 0;
|
||||
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
return 0;
|
||||
|
||||
ret = 0;
|
||||
if (bb->vm_ops->migrate)
|
||||
ret = bb->vm_ops->migrate(vma, from, to, flags);
|
||||
|
||||
sysfs_put_active(attr_sd);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct vm_operations_struct bin_vm_ops = {
|
||||
.open = bin_vma_open,
|
||||
.fault = bin_fault,
|
||||
.page_mkwrite = bin_page_mkwrite,
|
||||
.access = bin_access,
|
||||
#ifdef CONFIG_NUMA
|
||||
.set_policy = bin_set_policy,
|
||||
.get_policy = bin_get_policy,
|
||||
.migrate = bin_migrate,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&bb->mutex);
|
||||
|
||||
/* need attr_sd for attr, its parent for kobj */
|
||||
rc = -ENODEV;
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
goto out_unlock;
|
||||
|
||||
rc = -EINVAL;
|
||||
if (!attr->mmap)
|
||||
goto out_put;
|
||||
|
||||
rc = attr->mmap(file, kobj, attr, vma);
|
||||
if (rc)
|
||||
goto out_put;
|
||||
|
||||
/*
|
||||
* PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup()
|
||||
* to satisfy versions of X which crash if the mmap fails: that
|
||||
* substitutes a new vm_file, and we don't then want bin_vm_ops.
|
||||
*/
|
||||
if (vma->vm_file != file)
|
||||
goto out_put;
|
||||
|
||||
rc = -EINVAL;
|
||||
if (bb->mmapped && bb->vm_ops != vma->vm_ops)
|
||||
goto out_put;
|
||||
|
||||
/*
|
||||
* It is not possible to successfully wrap close.
|
||||
* So error if someone is trying to use close.
|
||||
*/
|
||||
rc = -EINVAL;
|
||||
if (vma->vm_ops && vma->vm_ops->close)
|
||||
goto out_put;
|
||||
|
||||
rc = 0;
|
||||
bb->mmapped = 1;
|
||||
bb->vm_ops = vma->vm_ops;
|
||||
vma->vm_ops = &bin_vm_ops;
|
||||
out_put:
|
||||
sysfs_put_active(attr_sd);
|
||||
out_unlock:
|
||||
mutex_unlock(&bb->mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
|
||||
struct bin_buffer *bb = NULL;
|
||||
int error;
|
||||
|
||||
/* binary file operations requires both @sd and its parent */
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
return -ENODEV;
|
||||
|
||||
error = -EACCES;
|
||||
if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap))
|
||||
goto err_out;
|
||||
if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap))
|
||||
goto err_out;
|
||||
|
||||
error = -ENOMEM;
|
||||
bb = kzalloc(sizeof(*bb), GFP_KERNEL);
|
||||
if (!bb)
|
||||
goto err_out;
|
||||
|
||||
bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!bb->buffer)
|
||||
goto err_out;
|
||||
|
||||
mutex_init(&bb->mutex);
|
||||
bb->file = file;
|
||||
file->private_data = bb;
|
||||
|
||||
mutex_lock(&sysfs_bin_lock);
|
||||
hlist_add_head(&bb->list, &attr_sd->s_bin_attr.buffers);
|
||||
mutex_unlock(&sysfs_bin_lock);
|
||||
|
||||
/* open succeeded, put active references */
|
||||
sysfs_put_active(attr_sd);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
sysfs_put_active(attr_sd);
|
||||
kfree(bb);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
|
||||
mutex_lock(&sysfs_bin_lock);
|
||||
hlist_del(&bb->list);
|
||||
mutex_unlock(&sysfs_bin_lock);
|
||||
|
||||
kfree(bb->buffer);
|
||||
kfree(bb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations bin_fops = {
|
||||
.read = read,
|
||||
.write = write,
|
||||
.mmap = mmap,
|
||||
.llseek = generic_file_llseek,
|
||||
.open = open,
|
||||
.release = release,
|
||||
};
|
||||
|
||||
|
||||
void unmap_bin_file(struct sysfs_dirent *attr_sd)
|
||||
{
|
||||
struct bin_buffer *bb;
|
||||
|
||||
if (sysfs_type(attr_sd) != SYSFS_KOBJ_BIN_ATTR)
|
||||
return;
|
||||
|
||||
mutex_lock(&sysfs_bin_lock);
|
||||
|
||||
hlist_for_each_entry(bb, &attr_sd->s_bin_attr.buffers, list) {
|
||||
struct inode *inode = file_inode(bb->file);
|
||||
|
||||
unmap_mapping_range(inode->i_mapping, 0, 0, 1);
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_bin_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_create_bin_file - create binary file for object.
|
||||
* @kobj: object.
|
||||
* @attr: attribute descriptor.
|
||||
*/
|
||||
int sysfs_create_bin_file(struct kobject *kobj,
|
||||
const struct bin_attribute *attr)
|
||||
{
|
||||
BUG_ON(!kobj || !kobj->sd || !attr);
|
||||
|
||||
return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
|
||||
|
||||
/**
|
||||
* sysfs_remove_bin_file - remove binary file for object.
|
||||
* @kobj: object.
|
||||
* @attr: attribute descriptor.
|
||||
*/
|
||||
void sysfs_remove_bin_file(struct kobject *kobj,
|
||||
const struct bin_attribute *attr)
|
||||
{
|
||||
sysfs_hash_and_remove(kobj->sd, NULL, attr->attr.name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
|
428
fs/sysfs/dir.c
428
fs/sysfs/dir.c
@ -26,21 +26,21 @@
|
||||
#include "sysfs.h"
|
||||
|
||||
DEFINE_MUTEX(sysfs_mutex);
|
||||
DEFINE_SPINLOCK(sysfs_assoc_lock);
|
||||
DEFINE_SPINLOCK(sysfs_symlink_target_lock);
|
||||
|
||||
#define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb);
|
||||
#define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb)
|
||||
|
||||
static DEFINE_SPINLOCK(sysfs_ino_lock);
|
||||
static DEFINE_IDA(sysfs_ino_ida);
|
||||
|
||||
/**
|
||||
* sysfs_name_hash
|
||||
* @ns: Namespace tag to hash
|
||||
* @name: Null terminated string to hash
|
||||
* @ns: Namespace tag to hash
|
||||
*
|
||||
* Returns 31 bit hash of ns + name (so it fits in an off_t )
|
||||
*/
|
||||
static unsigned int sysfs_name_hash(const void *ns, const char *name)
|
||||
static unsigned int sysfs_name_hash(const char *name, const void *ns)
|
||||
{
|
||||
unsigned long hash = init_name_hash();
|
||||
unsigned int len = strlen(name);
|
||||
@ -56,8 +56,8 @@ static unsigned int sysfs_name_hash(const void *ns, const char *name)
|
||||
return hash;
|
||||
}
|
||||
|
||||
static int sysfs_name_compare(unsigned int hash, const void *ns,
|
||||
const char *name, const struct sysfs_dirent *sd)
|
||||
static int sysfs_name_compare(unsigned int hash, const char *name,
|
||||
const void *ns, const struct sysfs_dirent *sd)
|
||||
{
|
||||
if (hash != sd->s_hash)
|
||||
return hash - sd->s_hash;
|
||||
@ -69,7 +69,7 @@ static int sysfs_name_compare(unsigned int hash, const void *ns,
|
||||
static int sysfs_sd_compare(const struct sysfs_dirent *left,
|
||||
const struct sysfs_dirent *right)
|
||||
{
|
||||
return sysfs_name_compare(left->s_hash, left->s_ns, left->s_name,
|
||||
return sysfs_name_compare(left->s_hash, left->s_name, left->s_ns,
|
||||
right);
|
||||
}
|
||||
|
||||
@ -111,6 +111,11 @@ static int sysfs_link_sibling(struct sysfs_dirent *sd)
|
||||
/* add new node and rebalance the tree */
|
||||
rb_link_node(&sd->s_rb, parent, node);
|
||||
rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children);
|
||||
|
||||
/* if @sd has ns tag, mark the parent to enable ns filtering */
|
||||
if (sd->s_ns)
|
||||
sd->s_parent->s_flags |= SYSFS_FLAG_HAS_NS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -130,26 +135,15 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
|
||||
sd->s_parent->s_dir.subdirs--;
|
||||
|
||||
rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children);
|
||||
|
||||
/*
|
||||
* Either all or none of the children have tags. Clearing HAS_NS
|
||||
* when there's no child left is enough to keep the flag synced.
|
||||
*/
|
||||
if (RB_EMPTY_ROOT(&sd->s_parent->s_dir.children))
|
||||
sd->s_parent->s_flags &= ~SYSFS_FLAG_HAS_NS;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
|
||||
/* Test for attributes that want to ignore lockdep for read-locking */
|
||||
static bool ignore_lockdep(struct sysfs_dirent *sd)
|
||||
{
|
||||
return sysfs_type(sd) == SYSFS_KOBJ_ATTR &&
|
||||
sd->s_attr.attr->ignore_lockdep;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline bool ignore_lockdep(struct sysfs_dirent *sd)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* sysfs_get_active - get an active reference to sysfs_dirent
|
||||
* @sd: sysfs_dirent to get an active reference to
|
||||
@ -168,7 +162,7 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
|
||||
if (!atomic_inc_unless_negative(&sd->s_active))
|
||||
return NULL;
|
||||
|
||||
if (likely(!ignore_lockdep(sd)))
|
||||
if (likely(!sysfs_ignore_lockdep(sd)))
|
||||
rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_);
|
||||
return sd;
|
||||
}
|
||||
@ -187,7 +181,7 @@ void sysfs_put_active(struct sysfs_dirent *sd)
|
||||
if (unlikely(!sd))
|
||||
return;
|
||||
|
||||
if (likely(!ignore_lockdep(sd)))
|
||||
if (likely(!sysfs_ignore_lockdep(sd)))
|
||||
rwsem_release(&sd->dep_map, 1, _RET_IP_);
|
||||
v = atomic_dec_return(&sd->s_active);
|
||||
if (likely(v != SD_DEACTIVATED_BIAS))
|
||||
@ -297,7 +291,6 @@ static int sysfs_dentry_delete(const struct dentry *dentry)
|
||||
static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct sysfs_dirent *sd;
|
||||
int type;
|
||||
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
@ -318,13 +311,8 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
goto out_bad;
|
||||
|
||||
/* The sysfs dirent has been moved to a different namespace */
|
||||
type = KOBJ_NS_TYPE_NONE;
|
||||
if (sd->s_parent) {
|
||||
type = sysfs_ns_type(sd->s_parent);
|
||||
if (type != KOBJ_NS_TYPE_NONE &&
|
||||
sysfs_info(dentry->d_sb)->ns[type] != sd->s_ns)
|
||||
goto out_bad;
|
||||
}
|
||||
if (sd->s_ns && sd->s_ns != sysfs_info(dentry->d_sb)->ns)
|
||||
goto out_bad;
|
||||
|
||||
mutex_unlock(&sysfs_mutex);
|
||||
out_valid:
|
||||
@ -400,22 +388,19 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
|
||||
/**
|
||||
* sysfs_addrm_start - prepare for sysfs_dirent add/remove
|
||||
* @acxt: pointer to sysfs_addrm_cxt to be used
|
||||
* @parent_sd: parent sysfs_dirent
|
||||
*
|
||||
* This function is called when the caller is about to add or
|
||||
* remove sysfs_dirent under @parent_sd. This function acquires
|
||||
* sysfs_mutex. @acxt is used to keep and pass context to
|
||||
* other addrm functions.
|
||||
* This function is called when the caller is about to add or remove
|
||||
* sysfs_dirent. This function acquires sysfs_mutex. @acxt is used
|
||||
* to keep and pass context to other addrm functions.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep). sysfs_mutex is locked on
|
||||
* return.
|
||||
*/
|
||||
void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
|
||||
struct sysfs_dirent *parent_sd)
|
||||
void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt)
|
||||
__acquires(sysfs_mutex)
|
||||
{
|
||||
memset(acxt, 0, sizeof(*acxt));
|
||||
acxt->parent_sd = parent_sd;
|
||||
|
||||
mutex_lock(&sysfs_mutex);
|
||||
}
|
||||
@ -424,10 +409,11 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
|
||||
* __sysfs_add_one - add sysfs_dirent to parent without warning
|
||||
* @acxt: addrm context to use
|
||||
* @sd: sysfs_dirent to be added
|
||||
* @parent_sd: the parent sysfs_dirent to add @sd to
|
||||
*
|
||||
* Get @acxt->parent_sd and set sd->s_parent to it and increment
|
||||
* nlink of parent inode if @sd is a directory and link into the
|
||||
* children list of the parent.
|
||||
* Get @parent_sd and set @sd->s_parent to it and increment nlink of
|
||||
* the parent inode if @sd is a directory and link into the children
|
||||
* list of the parent.
|
||||
*
|
||||
* This function should be called between calls to
|
||||
* sysfs_addrm_start() and sysfs_addrm_finish() and should be
|
||||
@ -440,27 +426,21 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
|
||||
* 0 on success, -EEXIST if entry with the given name already
|
||||
* exists.
|
||||
*/
|
||||
int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
|
||||
int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd,
|
||||
struct sysfs_dirent *parent_sd)
|
||||
{
|
||||
struct sysfs_inode_attrs *ps_iattr;
|
||||
int ret;
|
||||
|
||||
if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) {
|
||||
WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
|
||||
sysfs_ns_type(acxt->parent_sd) ? "required" : "invalid",
|
||||
acxt->parent_sd->s_name, sd->s_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name);
|
||||
sd->s_parent = sysfs_get(acxt->parent_sd);
|
||||
sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns);
|
||||
sd->s_parent = sysfs_get(parent_sd);
|
||||
|
||||
ret = sysfs_link_sibling(sd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Update timestamps on the parent */
|
||||
ps_iattr = acxt->parent_sd->s_iattr;
|
||||
ps_iattr = parent_sd->s_iattr;
|
||||
if (ps_iattr) {
|
||||
struct iattr *ps_iattrs = &ps_iattr->ia_iattr;
|
||||
ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;
|
||||
@ -490,14 +470,32 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)
|
||||
return path;
|
||||
}
|
||||
|
||||
void sysfs_warn_dup(struct sysfs_dirent *parent, const char *name)
|
||||
{
|
||||
char *path;
|
||||
|
||||
path = kzalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (path) {
|
||||
sysfs_pathname(parent, path);
|
||||
strlcat(path, "/", PATH_MAX);
|
||||
strlcat(path, name, PATH_MAX);
|
||||
}
|
||||
|
||||
WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n",
|
||||
path ? path : name);
|
||||
|
||||
kfree(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_add_one - add sysfs_dirent to parent
|
||||
* @acxt: addrm context to use
|
||||
* @sd: sysfs_dirent to be added
|
||||
* @parent_sd: the parent sysfs_dirent to add @sd to
|
||||
*
|
||||
* Get @acxt->parent_sd and set sd->s_parent to it and increment
|
||||
* nlink of parent inode if @sd is a directory and link into the
|
||||
* children list of the parent.
|
||||
* Get @parent_sd and set @sd->s_parent to it and increment nlink of
|
||||
* the parent inode if @sd is a directory and link into the children
|
||||
* list of the parent.
|
||||
*
|
||||
* This function should be called between calls to
|
||||
* sysfs_addrm_start() and sysfs_addrm_finish() and should be
|
||||
@ -510,23 +508,15 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)
|
||||
* 0 on success, -EEXIST if entry with the given name already
|
||||
* exists.
|
||||
*/
|
||||
int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
|
||||
int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd,
|
||||
struct sysfs_dirent *parent_sd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __sysfs_add_one(acxt, sd);
|
||||
if (ret == -EEXIST) {
|
||||
char *path = kzalloc(PATH_MAX, GFP_KERNEL);
|
||||
WARN(1, KERN_WARNING
|
||||
"sysfs: cannot create duplicate filename '%s'\n",
|
||||
(path == NULL) ? sd->s_name
|
||||
: (sysfs_pathname(acxt->parent_sd, path),
|
||||
strlcat(path, "/", PATH_MAX),
|
||||
strlcat(path, sd->s_name, PATH_MAX),
|
||||
path));
|
||||
kfree(path);
|
||||
}
|
||||
ret = __sysfs_add_one(acxt, sd, parent_sd);
|
||||
|
||||
if (ret == -EEXIST)
|
||||
sysfs_warn_dup(parent_sd, sd->s_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -545,16 +535,22 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
|
||||
* LOCKING:
|
||||
* Determined by sysfs_addrm_start().
|
||||
*/
|
||||
void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
|
||||
static void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
|
||||
struct sysfs_dirent *sd)
|
||||
{
|
||||
struct sysfs_inode_attrs *ps_iattr;
|
||||
|
||||
BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED);
|
||||
/*
|
||||
* Removal can be called multiple times on the same node. Only the
|
||||
* first invocation is effective and puts the base ref.
|
||||
*/
|
||||
if (sd->s_flags & SYSFS_FLAG_REMOVED)
|
||||
return;
|
||||
|
||||
sysfs_unlink_sibling(sd);
|
||||
|
||||
/* Update timestamps on the parent */
|
||||
ps_iattr = acxt->parent_sd->s_iattr;
|
||||
ps_iattr = sd->s_parent->s_iattr;
|
||||
if (ps_iattr) {
|
||||
struct iattr *ps_iattrs = &ps_iattr->ia_iattr;
|
||||
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)
|
||||
* sysfs_mutex is released.
|
||||
*/
|
||||
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
|
||||
__releases(sysfs_mutex)
|
||||
{
|
||||
/* release resources acquired by sysfs_addrm_start() */
|
||||
mutex_unlock(&sysfs_mutex);
|
||||
@ -588,7 +585,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
|
||||
acxt->removed = sd->u.removed_list;
|
||||
|
||||
sysfs_deactivate(sd);
|
||||
unmap_bin_file(sd);
|
||||
sysfs_unmap_bin_file(sd);
|
||||
sysfs_put(sd);
|
||||
}
|
||||
}
|
||||
@ -597,6 +594,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
|
||||
* sysfs_find_dirent - find sysfs_dirent with the given name
|
||||
* @parent_sd: sysfs_dirent to search under
|
||||
* @name: name to look for
|
||||
* @ns: the namespace tag to use
|
||||
*
|
||||
* Look for sysfs_dirent with name @name under @parent_sd.
|
||||
*
|
||||
@ -607,26 +605,19 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
|
||||
* Pointer to sysfs_dirent if found, NULL if not.
|
||||
*/
|
||||
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name)
|
||||
const unsigned char *name,
|
||||
const void *ns)
|
||||
{
|
||||
struct rb_node *node = parent_sd->s_dir.children.rb_node;
|
||||
unsigned int hash;
|
||||
|
||||
if (!!sysfs_ns_type(parent_sd) != !!ns) {
|
||||
WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
|
||||
sysfs_ns_type(parent_sd) ? "required" : "invalid",
|
||||
parent_sd->s_name, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hash = sysfs_name_hash(ns, name);
|
||||
hash = sysfs_name_hash(name, ns);
|
||||
while (node) {
|
||||
struct sysfs_dirent *sd;
|
||||
int result;
|
||||
|
||||
sd = to_sysfs_dirent(node);
|
||||
result = sysfs_name_compare(hash, ns, name, sd);
|
||||
result = sysfs_name_compare(hash, name, ns, sd);
|
||||
if (result < 0)
|
||||
node = node->rb_left;
|
||||
else if (result > 0)
|
||||
@ -638,9 +629,10 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_dirent - find and get sysfs_dirent with the given name
|
||||
* sysfs_get_dirent_ns - find and get sysfs_dirent with the given name
|
||||
* @parent_sd: sysfs_dirent to search under
|
||||
* @name: name to look for
|
||||
* @ns: the namespace tag to use
|
||||
*
|
||||
* Look for sysfs_dirent with name @name under @parent_sd and get
|
||||
* it if found.
|
||||
@ -651,24 +643,24 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
|
||||
* RETURNS:
|
||||
* Pointer to sysfs_dirent if found, NULL if not.
|
||||
*/
|
||||
struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name)
|
||||
struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd,
|
||||
const unsigned char *name,
|
||||
const void *ns)
|
||||
{
|
||||
struct sysfs_dirent *sd;
|
||||
|
||||
mutex_lock(&sysfs_mutex);
|
||||
sd = sysfs_find_dirent(parent_sd, ns, name);
|
||||
sd = sysfs_find_dirent(parent_sd, name, ns);
|
||||
sysfs_get(sd);
|
||||
mutex_unlock(&sysfs_mutex);
|
||||
|
||||
return sd;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sysfs_get_dirent);
|
||||
EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns);
|
||||
|
||||
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
|
||||
enum kobj_ns_type type, const void *ns, const char *name,
|
||||
struct sysfs_dirent **p_sd)
|
||||
const char *name, const void *ns,
|
||||
struct sysfs_dirent **p_sd)
|
||||
{
|
||||
umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
@ -680,13 +672,12 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
|
||||
if (!sd)
|
||||
return -ENOMEM;
|
||||
|
||||
sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT);
|
||||
sd->s_ns = ns;
|
||||
sd->s_dir.kobj = kobj;
|
||||
|
||||
/* link in */
|
||||
sysfs_addrm_start(&acxt, parent_sd);
|
||||
rc = sysfs_add_one(&acxt, sd);
|
||||
sysfs_addrm_start(&acxt);
|
||||
rc = sysfs_add_one(&acxt, sd, parent_sd);
|
||||
sysfs_addrm_finish(&acxt);
|
||||
|
||||
if (rc == 0)
|
||||
@ -700,44 +691,17 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
|
||||
int sysfs_create_subdir(struct kobject *kobj, const char *name,
|
||||
struct sysfs_dirent **p_sd)
|
||||
{
|
||||
return create_dir(kobj, kobj->sd,
|
||||
KOBJ_NS_TYPE_NONE, NULL, name, p_sd);
|
||||
return create_dir(kobj, kobj->sd, name, NULL, p_sd);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_read_ns_type: return associated ns_type
|
||||
* @kobj: the kobject being queried
|
||||
*
|
||||
* Each kobject can be tagged with exactly one namespace type
|
||||
* (i.e. network or user). Return the ns_type associated with
|
||||
* this object if any
|
||||
* sysfs_create_dir_ns - create a directory for an object with a namespace tag
|
||||
* @kobj: object we're creating directory for
|
||||
* @ns: the namespace tag to use
|
||||
*/
|
||||
static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj)
|
||||
int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
|
||||
{
|
||||
const struct kobj_ns_type_operations *ops;
|
||||
enum kobj_ns_type type;
|
||||
|
||||
ops = kobj_child_ns_ops(kobj);
|
||||
if (!ops)
|
||||
return KOBJ_NS_TYPE_NONE;
|
||||
|
||||
type = ops->type;
|
||||
BUG_ON(type <= KOBJ_NS_TYPE_NONE);
|
||||
BUG_ON(type >= KOBJ_NS_TYPES);
|
||||
BUG_ON(!kobj_ns_type_registered(type));
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_create_dir - create a directory for an object.
|
||||
* @kobj: object we're creating directory for.
|
||||
*/
|
||||
int sysfs_create_dir(struct kobject *kobj)
|
||||
{
|
||||
enum kobj_ns_type type;
|
||||
struct sysfs_dirent *parent_sd, *sd;
|
||||
const void *ns = NULL;
|
||||
int error = 0;
|
||||
|
||||
BUG_ON(!kobj);
|
||||
@ -750,11 +714,7 @@ int sysfs_create_dir(struct kobject *kobj)
|
||||
if (!parent_sd)
|
||||
return -ENOENT;
|
||||
|
||||
if (sysfs_ns_type(parent_sd))
|
||||
ns = kobj->ktype->namespace(kobj);
|
||||
type = sysfs_read_ns_type(kobj);
|
||||
|
||||
error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);
|
||||
error = create_dir(kobj, parent_sd, kobject_name(kobj), ns, &sd);
|
||||
if (!error)
|
||||
kobj->sd = sd;
|
||||
return error;
|
||||
@ -768,15 +728,14 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct sysfs_dirent *parent_sd = parent->d_fsdata;
|
||||
struct sysfs_dirent *sd;
|
||||
struct inode *inode;
|
||||
enum kobj_ns_type type;
|
||||
const void *ns;
|
||||
const void *ns = NULL;
|
||||
|
||||
mutex_lock(&sysfs_mutex);
|
||||
|
||||
type = sysfs_ns_type(parent_sd);
|
||||
ns = sysfs_info(dir->i_sb)->ns[type];
|
||||
if (parent_sd->s_flags & SYSFS_FLAG_HAS_NS)
|
||||
ns = sysfs_info(dir->i_sb)->ns;
|
||||
|
||||
sd = sysfs_find_dirent(parent_sd, ns, dentry->d_name.name);
|
||||
sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns);
|
||||
|
||||
/* no such entry */
|
||||
if (!sd) {
|
||||
@ -807,41 +766,128 @@ const struct inode_operations sysfs_dir_inode_operations = {
|
||||
.setxattr = sysfs_setxattr,
|
||||
};
|
||||
|
||||
static void remove_dir(struct sysfs_dirent *sd)
|
||||
static struct sysfs_dirent *sysfs_leftmost_descendant(struct sysfs_dirent *pos)
|
||||
{
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
struct sysfs_dirent *last;
|
||||
|
||||
sysfs_addrm_start(&acxt, sd->s_parent);
|
||||
sysfs_remove_one(&acxt, sd);
|
||||
sysfs_addrm_finish(&acxt);
|
||||
while (true) {
|
||||
struct rb_node *rbn;
|
||||
|
||||
last = pos;
|
||||
|
||||
if (sysfs_type(pos) != SYSFS_DIR)
|
||||
break;
|
||||
|
||||
rbn = rb_first(&pos->s_dir.children);
|
||||
if (!rbn)
|
||||
break;
|
||||
|
||||
pos = to_sysfs_dirent(rbn);
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
void sysfs_remove_subdir(struct sysfs_dirent *sd)
|
||||
/**
|
||||
* sysfs_next_descendant_post - find the next descendant for post-order walk
|
||||
* @pos: the current position (%NULL to initiate traversal)
|
||||
* @root: sysfs_dirent whose descendants to walk
|
||||
*
|
||||
* Find the next descendant to visit for post-order traversal of @root's
|
||||
* descendants. @root is included in the iteration and the last node to be
|
||||
* visited.
|
||||
*/
|
||||
static struct sysfs_dirent *sysfs_next_descendant_post(struct sysfs_dirent *pos,
|
||||
struct sysfs_dirent *root)
|
||||
{
|
||||
remove_dir(sd);
|
||||
struct rb_node *rbn;
|
||||
|
||||
lockdep_assert_held(&sysfs_mutex);
|
||||
|
||||
/* if first iteration, visit leftmost descendant which may be root */
|
||||
if (!pos)
|
||||
return sysfs_leftmost_descendant(root);
|
||||
|
||||
/* if we visited @root, we're done */
|
||||
if (pos == root)
|
||||
return NULL;
|
||||
|
||||
/* if there's an unvisited sibling, visit its leftmost descendant */
|
||||
rbn = rb_next(&pos->s_rb);
|
||||
if (rbn)
|
||||
return sysfs_leftmost_descendant(to_sysfs_dirent(rbn));
|
||||
|
||||
/* no sibling left, visit parent */
|
||||
return pos->s_parent;
|
||||
}
|
||||
|
||||
|
||||
static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
|
||||
static void __sysfs_remove(struct sysfs_addrm_cxt *acxt,
|
||||
struct sysfs_dirent *sd)
|
||||
{
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
struct rb_node *pos;
|
||||
struct sysfs_dirent *pos, *next;
|
||||
|
||||
if (!dir_sd)
|
||||
if (!sd)
|
||||
return;
|
||||
|
||||
pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
|
||||
sysfs_addrm_start(&acxt, dir_sd);
|
||||
pos = rb_first(&dir_sd->s_dir.children);
|
||||
while (pos) {
|
||||
struct sysfs_dirent *sd = to_sysfs_dirent(pos);
|
||||
pos = rb_next(pos);
|
||||
if (sysfs_type(sd) != SYSFS_DIR)
|
||||
sysfs_remove_one(&acxt, sd);
|
||||
pr_debug("sysfs %s: removing\n", sd->s_name);
|
||||
|
||||
next = NULL;
|
||||
do {
|
||||
pos = next;
|
||||
next = sysfs_next_descendant_post(pos, sd);
|
||||
if (pos)
|
||||
sysfs_remove_one(acxt, pos);
|
||||
} while (next);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_remove - remove a sysfs_dirent recursively
|
||||
* @sd: the sysfs_dirent to remove
|
||||
*
|
||||
* Remove @sd along with all its subdirectories and files.
|
||||
*/
|
||||
void sysfs_remove(struct sysfs_dirent *sd)
|
||||
{
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
|
||||
sysfs_addrm_start(&acxt);
|
||||
__sysfs_remove(&acxt, sd);
|
||||
sysfs_addrm_finish(&acxt);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_hash_and_remove - find a sysfs_dirent by name and remove it
|
||||
* @dir_sd: parent of the target
|
||||
* @name: name of the sysfs_dirent to remove
|
||||
* @ns: namespace tag of the sysfs_dirent to remove
|
||||
*
|
||||
* Look for the sysfs_dirent with @name and @ns under @dir_sd and remove
|
||||
* it. Returns 0 on success, -ENOENT if such entry doesn't exist.
|
||||
*/
|
||||
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name,
|
||||
const void *ns)
|
||||
{
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
struct sysfs_dirent *sd;
|
||||
|
||||
if (!dir_sd) {
|
||||
WARN(1, KERN_WARNING "sysfs: can not remove '%s', no directory\n",
|
||||
name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
sysfs_addrm_start(&acxt);
|
||||
|
||||
sd = sysfs_find_dirent(dir_sd, name, ns);
|
||||
if (sd)
|
||||
__sysfs_remove(&acxt, sd);
|
||||
|
||||
sysfs_addrm_finish(&acxt);
|
||||
|
||||
remove_dir(dir_sd);
|
||||
if (sd)
|
||||
return 0;
|
||||
else
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -852,21 +898,34 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
|
||||
* the directory before we remove the directory, and we've inlined
|
||||
* what used to be sysfs_rmdir() below, instead of calling separately.
|
||||
*/
|
||||
|
||||
void sysfs_remove_dir(struct kobject *kobj)
|
||||
{
|
||||
struct sysfs_dirent *sd = kobj->sd;
|
||||
|
||||
spin_lock(&sysfs_assoc_lock);
|
||||
/*
|
||||
* In general, kboject owner is responsible for ensuring removal
|
||||
* doesn't race with other operations and sysfs doesn't provide any
|
||||
* protection; however, when @kobj is used as a symlink target, the
|
||||
* symlinking entity usually doesn't own @kobj and thus has no
|
||||
* control over removal. @kobj->sd may be removed anytime and
|
||||
* symlink code may end up dereferencing an already freed sd.
|
||||
*
|
||||
* sysfs_symlink_target_lock synchronizes @kobj->sd disassociation
|
||||
* against symlink operations so that symlink code can safely
|
||||
* dereference @kobj->sd.
|
||||
*/
|
||||
spin_lock(&sysfs_symlink_target_lock);
|
||||
kobj->sd = NULL;
|
||||
spin_unlock(&sysfs_assoc_lock);
|
||||
spin_unlock(&sysfs_symlink_target_lock);
|
||||
|
||||
__sysfs_remove_dir(sd);
|
||||
if (sd) {
|
||||
WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR);
|
||||
sysfs_remove(sd);
|
||||
}
|
||||
}
|
||||
|
||||
int sysfs_rename(struct sysfs_dirent *sd,
|
||||
struct sysfs_dirent *new_parent_sd, const void *new_ns,
|
||||
const char *new_name)
|
||||
int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd,
|
||||
const char *new_name, const void *new_ns)
|
||||
{
|
||||
int error;
|
||||
|
||||
@ -878,7 +937,7 @@ int sysfs_rename(struct sysfs_dirent *sd,
|
||||
goto out; /* nothing to rename */
|
||||
|
||||
error = -EEXIST;
|
||||
if (sysfs_find_dirent(new_parent_sd, new_ns, new_name))
|
||||
if (sysfs_find_dirent(new_parent_sd, new_name, new_ns))
|
||||
goto out;
|
||||
|
||||
/* rename sysfs_dirent */
|
||||
@ -899,7 +958,7 @@ int sysfs_rename(struct sysfs_dirent *sd,
|
||||
sysfs_get(new_parent_sd);
|
||||
sysfs_put(sd->s_parent);
|
||||
sd->s_ns = new_ns;
|
||||
sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name);
|
||||
sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns);
|
||||
sd->s_parent = new_parent_sd;
|
||||
sysfs_link_sibling(sd);
|
||||
|
||||
@ -909,30 +968,25 @@ int sysfs_rename(struct sysfs_dirent *sd,
|
||||
return error;
|
||||
}
|
||||
|
||||
int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
|
||||
int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
|
||||
const void *new_ns)
|
||||
{
|
||||
struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
|
||||
const void *new_ns = NULL;
|
||||
|
||||
if (sysfs_ns_type(parent_sd))
|
||||
new_ns = kobj->ktype->namespace(kobj);
|
||||
|
||||
return sysfs_rename(kobj->sd, parent_sd, new_ns, new_name);
|
||||
return sysfs_rename(kobj->sd, parent_sd, new_name, new_ns);
|
||||
}
|
||||
|
||||
int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
|
||||
int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
|
||||
const void *new_ns)
|
||||
{
|
||||
struct sysfs_dirent *sd = kobj->sd;
|
||||
struct sysfs_dirent *new_parent_sd;
|
||||
const void *new_ns = NULL;
|
||||
|
||||
BUG_ON(!sd->s_parent);
|
||||
if (sysfs_ns_type(sd->s_parent))
|
||||
new_ns = kobj->ktype->namespace(kobj);
|
||||
new_parent_sd = new_parent_kobj && new_parent_kobj->sd ?
|
||||
new_parent_kobj->sd : &sysfs_root;
|
||||
|
||||
return sysfs_rename(sd, new_parent_sd, new_ns, sd->s_name);
|
||||
return sysfs_rename(sd, new_parent_sd, sd->s_name, new_ns);
|
||||
}
|
||||
|
||||
/* Relationship between s_mode and the DT_xxx types */
|
||||
@ -1002,15 +1056,15 @@ static int sysfs_readdir(struct file *file, struct dir_context *ctx)
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct sysfs_dirent *parent_sd = dentry->d_fsdata;
|
||||
struct sysfs_dirent *pos = file->private_data;
|
||||
enum kobj_ns_type type;
|
||||
const void *ns;
|
||||
|
||||
type = sysfs_ns_type(parent_sd);
|
||||
ns = sysfs_info(dentry->d_sb)->ns[type];
|
||||
const void *ns = NULL;
|
||||
|
||||
if (!dir_emit_dots(file, ctx))
|
||||
return 0;
|
||||
mutex_lock(&sysfs_mutex);
|
||||
|
||||
if (parent_sd->s_flags & SYSFS_FLAG_HAS_NS)
|
||||
ns = sysfs_info(dentry->d_sb)->ns;
|
||||
|
||||
for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos);
|
||||
pos;
|
||||
pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) {
|
||||
|
878
fs/sysfs/file.c
878
fs/sysfs/file.c
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,7 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
|
||||
|
||||
if (grp->attrs)
|
||||
for (attr = grp->attrs; *attr; attr++)
|
||||
sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
|
||||
sysfs_hash_and_remove(dir_sd, (*attr)->name, NULL);
|
||||
if (grp->bin_attrs)
|
||||
for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++)
|
||||
sysfs_remove_bin_file(kobj, *bin_attr);
|
||||
@ -49,16 +49,17 @@ static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
|
||||
* re-adding (if required) the file.
|
||||
*/
|
||||
if (update)
|
||||
sysfs_hash_and_remove(dir_sd, NULL,
|
||||
(*attr)->name);
|
||||
sysfs_hash_and_remove(dir_sd, (*attr)->name,
|
||||
NULL);
|
||||
if (grp->is_visible) {
|
||||
mode = grp->is_visible(kobj, *attr, i);
|
||||
if (!mode)
|
||||
continue;
|
||||
}
|
||||
error = sysfs_add_file_mode(dir_sd, *attr,
|
||||
SYSFS_KOBJ_ATTR,
|
||||
(*attr)->mode | mode);
|
||||
error = sysfs_add_file_mode_ns(dir_sd, *attr,
|
||||
SYSFS_KOBJ_ATTR,
|
||||
(*attr)->mode | mode,
|
||||
NULL);
|
||||
if (unlikely(error))
|
||||
break;
|
||||
}
|
||||
@ -110,7 +111,7 @@ static int internal_create_group(struct kobject *kobj, int update,
|
||||
error = create_files(sd, kobj, grp, update);
|
||||
if (error) {
|
||||
if (grp->name)
|
||||
sysfs_remove_subdir(sd);
|
||||
sysfs_remove(sd);
|
||||
}
|
||||
sysfs_put(sd);
|
||||
return error;
|
||||
@ -206,7 +207,7 @@ void sysfs_remove_group(struct kobject *kobj,
|
||||
struct sysfs_dirent *sd;
|
||||
|
||||
if (grp->name) {
|
||||
sd = sysfs_get_dirent(dir_sd, NULL, grp->name);
|
||||
sd = sysfs_get_dirent(dir_sd, grp->name);
|
||||
if (!sd) {
|
||||
WARN(!sd, KERN_WARNING
|
||||
"sysfs group %p not found for kobject '%s'\n",
|
||||
@ -218,7 +219,7 @@ void sysfs_remove_group(struct kobject *kobj,
|
||||
|
||||
remove_files(sd, kobj, grp);
|
||||
if (grp->name)
|
||||
sysfs_remove_subdir(sd);
|
||||
sysfs_remove(sd);
|
||||
|
||||
sysfs_put(sd);
|
||||
}
|
||||
@ -261,7 +262,7 @@ int sysfs_merge_group(struct kobject *kobj,
|
||||
struct attribute *const *attr;
|
||||
int i;
|
||||
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, NULL, grp->name);
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, grp->name);
|
||||
if (!dir_sd)
|
||||
return -ENOENT;
|
||||
|
||||
@ -269,7 +270,7 @@ int sysfs_merge_group(struct kobject *kobj,
|
||||
error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
|
||||
if (error) {
|
||||
while (--i >= 0)
|
||||
sysfs_hash_and_remove(dir_sd, NULL, (*--attr)->name);
|
||||
sysfs_hash_and_remove(dir_sd, (*--attr)->name, NULL);
|
||||
}
|
||||
sysfs_put(dir_sd);
|
||||
|
||||
@ -288,10 +289,10 @@ void sysfs_unmerge_group(struct kobject *kobj,
|
||||
struct sysfs_dirent *dir_sd;
|
||||
struct attribute *const *attr;
|
||||
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, NULL, grp->name);
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, grp->name);
|
||||
if (dir_sd) {
|
||||
for (attr = grp->attrs; *attr; ++attr)
|
||||
sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
|
||||
sysfs_hash_and_remove(dir_sd, (*attr)->name, NULL);
|
||||
sysfs_put(dir_sd);
|
||||
}
|
||||
}
|
||||
@ -310,7 +311,7 @@ int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name,
|
||||
struct sysfs_dirent *dir_sd;
|
||||
int error = 0;
|
||||
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, NULL, group_name);
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, group_name);
|
||||
if (!dir_sd)
|
||||
return -ENOENT;
|
||||
|
||||
@ -332,9 +333,9 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
|
||||
{
|
||||
struct sysfs_dirent *dir_sd;
|
||||
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, NULL, group_name);
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, group_name);
|
||||
if (dir_sd) {
|
||||
sysfs_hash_and_remove(dir_sd, NULL, link_name);
|
||||
sysfs_hash_and_remove(dir_sd, link_name, NULL);
|
||||
sysfs_put(dir_sd);
|
||||
}
|
||||
}
|
||||
|
@ -258,9 +258,9 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
|
||||
inode->i_fop = &sysfs_file_operations;
|
||||
break;
|
||||
case SYSFS_KOBJ_BIN_ATTR:
|
||||
bin_attr = sd->s_bin_attr.bin_attr;
|
||||
bin_attr = sd->s_attr.bin_attr;
|
||||
inode->i_size = bin_attr->size;
|
||||
inode->i_fop = &bin_fops;
|
||||
inode->i_fop = &sysfs_bin_operations;
|
||||
break;
|
||||
case SYSFS_KOBJ_LINK:
|
||||
inode->i_op = &sysfs_symlink_inode_operations;
|
||||
@ -314,32 +314,6 @@ void sysfs_evict_inode(struct inode *inode)
|
||||
sysfs_put(sd);
|
||||
}
|
||||
|
||||
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns,
|
||||
const char *name)
|
||||
{
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
struct sysfs_dirent *sd;
|
||||
|
||||
if (!dir_sd) {
|
||||
WARN(1, KERN_WARNING "sysfs: can not remove '%s', no directory\n",
|
||||
name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
sysfs_addrm_start(&acxt, dir_sd);
|
||||
|
||||
sd = sysfs_find_dirent(dir_sd, ns, name);
|
||||
if (sd)
|
||||
sysfs_remove_one(&acxt, sd);
|
||||
|
||||
sysfs_addrm_finish(&acxt);
|
||||
|
||||
if (sd)
|
||||
return 0;
|
||||
else
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int sysfs_permission(struct inode *inode, int mask)
|
||||
{
|
||||
struct sysfs_dirent *sd;
|
||||
|
@ -36,7 +36,7 @@ static const struct super_operations sysfs_ops = {
|
||||
struct sysfs_dirent sysfs_root = {
|
||||
.s_name = "",
|
||||
.s_count = ATOMIC_INIT(1),
|
||||
.s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT),
|
||||
.s_flags = SYSFS_DIR,
|
||||
.s_mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
.s_ino = 1,
|
||||
};
|
||||
@ -77,14 +77,8 @@ static int sysfs_test_super(struct super_block *sb, void *data)
|
||||
{
|
||||
struct sysfs_super_info *sb_info = sysfs_info(sb);
|
||||
struct sysfs_super_info *info = data;
|
||||
enum kobj_ns_type type;
|
||||
int found = 1;
|
||||
|
||||
for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) {
|
||||
if (sb_info->ns[type] != info->ns[type])
|
||||
found = 0;
|
||||
}
|
||||
return found;
|
||||
return sb_info->ns == info->ns;
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
static void free_sysfs_super_info(struct sysfs_super_info *info)
|
||||
{
|
||||
int type;
|
||||
for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
|
||||
kobj_ns_drop(type, info->ns[type]);
|
||||
kobj_ns_drop(KOBJ_NS_TYPE_NET, info->ns);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
@ -108,7 +100,6 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data)
|
||||
{
|
||||
struct sysfs_super_info *info;
|
||||
enum kobj_ns_type type;
|
||||
struct super_block *sb;
|
||||
int error;
|
||||
|
||||
@ -116,18 +107,15 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
|
||||
if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) {
|
||||
if (!kobj_ns_current_may_mount(type))
|
||||
return ERR_PTR(-EPERM);
|
||||
}
|
||||
if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET))
|
||||
return ERR_PTR(-EPERM);
|
||||
}
|
||||
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
|
||||
info->ns[type] = kobj_ns_grab_current(type);
|
||||
info->ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
|
||||
|
||||
sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info);
|
||||
if (IS_ERR(sb) || sb->s_fs_info != info)
|
||||
|
@ -28,18 +28,19 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd,
|
||||
struct sysfs_dirent *target_sd = NULL;
|
||||
struct sysfs_dirent *sd = NULL;
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
enum kobj_ns_type ns_type;
|
||||
int error;
|
||||
|
||||
BUG_ON(!name || !parent_sd);
|
||||
|
||||
/* target->sd can go away beneath us but is protected with
|
||||
* sysfs_assoc_lock. Fetch target_sd from it.
|
||||
/*
|
||||
* We don't own @target and it may be removed at any time.
|
||||
* Synchronize using sysfs_symlink_target_lock. See
|
||||
* sysfs_remove_dir() for details.
|
||||
*/
|
||||
spin_lock(&sysfs_assoc_lock);
|
||||
spin_lock(&sysfs_symlink_target_lock);
|
||||
if (target->sd)
|
||||
target_sd = sysfs_get(target->sd);
|
||||
spin_unlock(&sysfs_assoc_lock);
|
||||
spin_unlock(&sysfs_symlink_target_lock);
|
||||
|
||||
error = -ENOENT;
|
||||
if (!target_sd)
|
||||
@ -50,29 +51,15 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd,
|
||||
if (!sd)
|
||||
goto out_put;
|
||||
|
||||
ns_type = sysfs_ns_type(parent_sd);
|
||||
if (ns_type)
|
||||
sd->s_ns = target->ktype->namespace(target);
|
||||
sd->s_ns = target_sd->s_ns;
|
||||
sd->s_symlink.target_sd = target_sd;
|
||||
target_sd = NULL; /* reference is now owned by the symlink */
|
||||
|
||||
sysfs_addrm_start(&acxt, parent_sd);
|
||||
/* Symlinks must be between directories with the same ns_type */
|
||||
if (!ns_type ||
|
||||
(ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) {
|
||||
if (warn)
|
||||
error = sysfs_add_one(&acxt, sd);
|
||||
else
|
||||
error = __sysfs_add_one(&acxt, sd);
|
||||
} else {
|
||||
error = -EINVAL;
|
||||
WARN(1, KERN_WARNING
|
||||
"sysfs: symlink across ns_types %s/%s -> %s/%s\n",
|
||||
parent_sd->s_name,
|
||||
sd->s_name,
|
||||
sd->s_symlink.target_sd->s_parent->s_name,
|
||||
sd->s_symlink.target_sd->s_name);
|
||||
}
|
||||
sysfs_addrm_start(&acxt);
|
||||
if (warn)
|
||||
error = sysfs_add_one(&acxt, sd, parent_sd);
|
||||
else
|
||||
error = __sysfs_add_one(&acxt, sd, parent_sd);
|
||||
sysfs_addrm_finish(&acxt);
|
||||
|
||||
if (error)
|
||||
@ -155,11 +142,17 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
|
||||
const char *name)
|
||||
{
|
||||
const void *ns = NULL;
|
||||
spin_lock(&sysfs_assoc_lock);
|
||||
if (targ->sd && sysfs_ns_type(kobj->sd))
|
||||
|
||||
/*
|
||||
* We don't own @target and it may be removed at any time.
|
||||
* Synchronize using sysfs_symlink_target_lock. See
|
||||
* sysfs_remove_dir() for details.
|
||||
*/
|
||||
spin_lock(&sysfs_symlink_target_lock);
|
||||
if (targ->sd)
|
||||
ns = targ->sd->s_ns;
|
||||
spin_unlock(&sysfs_assoc_lock);
|
||||
sysfs_hash_and_remove(kobj->sd, ns, name);
|
||||
spin_unlock(&sysfs_symlink_target_lock);
|
||||
sysfs_hash_and_remove(kobj->sd, name, ns);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,24 +169,25 @@ void sysfs_remove_link(struct kobject *kobj, const char *name)
|
||||
else
|
||||
parent_sd = kobj->sd;
|
||||
|
||||
sysfs_hash_and_remove(parent_sd, NULL, name);
|
||||
sysfs_hash_and_remove(parent_sd, name, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sysfs_remove_link);
|
||||
|
||||
/**
|
||||
* sysfs_rename_link - rename symlink in object's directory.
|
||||
* sysfs_rename_link_ns - rename symlink in object's directory.
|
||||
* @kobj: object we're acting for.
|
||||
* @targ: object we're pointing to.
|
||||
* @old: previous name of the symlink.
|
||||
* @new: new name of the symlink.
|
||||
* @new_ns: new namespace of the symlink.
|
||||
*
|
||||
* A helper function for the common rename symlink idiom.
|
||||
*/
|
||||
int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
|
||||
const char *old, const char *new)
|
||||
int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ,
|
||||
const char *old, const char *new, const void *new_ns)
|
||||
{
|
||||
struct sysfs_dirent *parent_sd, *sd = NULL;
|
||||
const void *old_ns = NULL, *new_ns = NULL;
|
||||
const void *old_ns = NULL;
|
||||
int result;
|
||||
|
||||
if (!kobj)
|
||||
@ -205,7 +199,7 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
|
||||
old_ns = targ->sd->s_ns;
|
||||
|
||||
result = -ENOENT;
|
||||
sd = sysfs_get_dirent(parent_sd, old_ns, old);
|
||||
sd = sysfs_get_dirent_ns(parent_sd, old, old_ns);
|
||||
if (!sd)
|
||||
goto out;
|
||||
|
||||
@ -215,16 +209,13 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
|
||||
if (sd->s_symlink.target_sd->s_dir.kobj != targ)
|
||||
goto out;
|
||||
|
||||
if (sysfs_ns_type(parent_sd))
|
||||
new_ns = targ->ktype->namespace(targ);
|
||||
|
||||
result = sysfs_rename(sd, parent_sd, new_ns, new);
|
||||
result = sysfs_rename(sd, parent_sd, new, new_ns);
|
||||
|
||||
out:
|
||||
sysfs_put(sd);
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sysfs_rename_link);
|
||||
EXPORT_SYMBOL_GPL(sysfs_rename_link_ns);
|
||||
|
||||
static int sysfs_get_target_path(struct sysfs_dirent *parent_sd,
|
||||
struct sysfs_dirent *target_sd, char *path)
|
||||
|
@ -29,15 +29,13 @@ struct sysfs_elem_symlink {
|
||||
};
|
||||
|
||||
struct sysfs_elem_attr {
|
||||
struct attribute *attr;
|
||||
union {
|
||||
struct attribute *attr;
|
||||
struct bin_attribute *bin_attr;
|
||||
};
|
||||
struct sysfs_open_dirent *open;
|
||||
};
|
||||
|
||||
struct sysfs_elem_bin_attr {
|
||||
struct bin_attribute *bin_attr;
|
||||
struct hlist_head buffers;
|
||||
};
|
||||
|
||||
struct sysfs_inode_attrs {
|
||||
struct iattr ia_iattr;
|
||||
void *ia_secdata;
|
||||
@ -74,7 +72,6 @@ struct sysfs_dirent {
|
||||
struct sysfs_elem_dir s_dir;
|
||||
struct sysfs_elem_symlink s_symlink;
|
||||
struct sysfs_elem_attr s_attr;
|
||||
struct sysfs_elem_bin_attr s_bin_attr;
|
||||
};
|
||||
|
||||
unsigned short s_flags;
|
||||
@ -93,11 +90,8 @@ struct sysfs_dirent {
|
||||
#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)
|
||||
#define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR)
|
||||
|
||||
/* identify any namespace tag on sysfs_dirents */
|
||||
#define SYSFS_NS_TYPE_MASK 0xf00
|
||||
#define SYSFS_NS_TYPE_SHIFT 8
|
||||
|
||||
#define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK)
|
||||
#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK
|
||||
#define SYSFS_FLAG_HAS_NS 0x01000
|
||||
#define SYSFS_FLAG_REMOVED 0x02000
|
||||
|
||||
static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
|
||||
@ -105,16 +99,8 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
|
||||
return sd->s_flags & SYSFS_TYPE_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return any namespace tags on this dirent.
|
||||
* enum kobj_ns_type is defined in linux/kobject.h
|
||||
*/
|
||||
static inline enum kobj_ns_type sysfs_ns_type(struct sysfs_dirent *sd)
|
||||
{
|
||||
return (sd->s_flags & SYSFS_NS_TYPE_MASK) >> SYSFS_NS_TYPE_SHIFT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
|
||||
#define sysfs_dirent_init_lockdep(sd) \
|
||||
do { \
|
||||
struct attribute *attr = sd->s_attr.attr; \
|
||||
@ -124,15 +110,31 @@ do { \
|
||||
\
|
||||
lockdep_init_map(&sd->dep_map, "s_active", key, 0); \
|
||||
} while (0)
|
||||
|
||||
/* Test for attributes that want to ignore lockdep for read-locking */
|
||||
static inline bool sysfs_ignore_lockdep(struct sysfs_dirent *sd)
|
||||
{
|
||||
int type = sysfs_type(sd);
|
||||
|
||||
return (type == SYSFS_KOBJ_ATTR || type == SYSFS_KOBJ_BIN_ATTR) &&
|
||||
sd->s_attr.attr->ignore_lockdep;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define sysfs_dirent_init_lockdep(sd) do {} while (0)
|
||||
|
||||
static inline bool sysfs_ignore_lockdep(struct sysfs_dirent *sd)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Context structure to be used while adding/removing nodes.
|
||||
*/
|
||||
struct sysfs_addrm_cxt {
|
||||
struct sysfs_dirent *parent_sd;
|
||||
struct sysfs_dirent *removed;
|
||||
};
|
||||
|
||||
@ -141,12 +143,13 @@ struct sysfs_addrm_cxt {
|
||||
*/
|
||||
|
||||
/*
|
||||
* Each sb is associated with a set of namespace tags (i.e.
|
||||
* the network namespace of the task which mounted this sysfs
|
||||
* instance).
|
||||
* Each sb is associated with one namespace tag, currently the network
|
||||
* namespace of the task which mounted this sysfs instance. If multiple
|
||||
* tags become necessary, make the following an array and compare
|
||||
* sysfs_dirent tag against every entry.
|
||||
*/
|
||||
struct sysfs_super_info {
|
||||
void *ns[KOBJ_NS_TYPES];
|
||||
void *ns;
|
||||
};
|
||||
#define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info))
|
||||
extern struct sysfs_dirent sysfs_root;
|
||||
@ -156,38 +159,37 @@ extern struct kmem_cache *sysfs_dir_cachep;
|
||||
* dir.c
|
||||
*/
|
||||
extern struct mutex sysfs_mutex;
|
||||
extern spinlock_t sysfs_assoc_lock;
|
||||
extern spinlock_t sysfs_symlink_target_lock;
|
||||
extern const struct dentry_operations sysfs_dentry_ops;
|
||||
|
||||
extern const struct file_operations sysfs_dir_operations;
|
||||
extern const struct inode_operations sysfs_dir_inode_operations;
|
||||
|
||||
struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
|
||||
struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
|
||||
void sysfs_put_active(struct sysfs_dirent *sd);
|
||||
void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
|
||||
struct sysfs_dirent *parent_sd);
|
||||
int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
|
||||
int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
|
||||
void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
|
||||
void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt);
|
||||
void sysfs_warn_dup(struct sysfs_dirent *parent, const char *name);
|
||||
int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd,
|
||||
struct sysfs_dirent *parent_sd);
|
||||
int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd,
|
||||
struct sysfs_dirent *parent_sd);
|
||||
void sysfs_remove(struct sysfs_dirent *sd);
|
||||
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name,
|
||||
const void *ns);
|
||||
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
|
||||
|
||||
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name);
|
||||
struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name);
|
||||
const unsigned char *name,
|
||||
const void *ns);
|
||||
struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type);
|
||||
|
||||
void release_sysfs_dirent(struct sysfs_dirent *sd);
|
||||
|
||||
int sysfs_create_subdir(struct kobject *kobj, const char *name,
|
||||
struct sysfs_dirent **p_sd);
|
||||
void sysfs_remove_subdir(struct sysfs_dirent *sd);
|
||||
|
||||
int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd,
|
||||
const void *ns, const char *new_name);
|
||||
const char *new_name, const void *new_ns);
|
||||
|
||||
static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd)
|
||||
{
|
||||
@ -218,25 +220,21 @@ int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
struct kstat *stat);
|
||||
int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns,
|
||||
const char *name);
|
||||
int sysfs_inode_init(void);
|
||||
|
||||
/*
|
||||
* file.c
|
||||
*/
|
||||
extern const struct file_operations sysfs_file_operations;
|
||||
extern const struct file_operations sysfs_bin_operations;
|
||||
|
||||
int sysfs_add_file(struct sysfs_dirent *dir_sd,
|
||||
const struct attribute *attr, int type);
|
||||
|
||||
int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
|
||||
const struct attribute *attr, int type, umode_t amode);
|
||||
/*
|
||||
* bin.c
|
||||
*/
|
||||
extern const struct file_operations bin_fops;
|
||||
void unmap_bin_file(struct sysfs_dirent *attr_sd);
|
||||
int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd,
|
||||
const struct attribute *attr, int type,
|
||||
umode_t amode, const void *ns);
|
||||
void sysfs_unmap_bin_file(struct sysfs_dirent *sd);
|
||||
|
||||
/*
|
||||
* symlink.c
|
||||
|
@ -206,6 +206,12 @@ static inline struct dentry *debugfs_create_size_t(const char *name, umode_t mod
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, atomic_t *value)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct dentry *debugfs_create_bool(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
u32 *value)
|
||||
@ -227,6 +233,12 @@ static inline struct dentry *debugfs_create_regset32(const char *name,
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline int debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
|
||||
int nregs, void __iomem *base, char *prefix)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool debugfs_initialized(void)
|
||||
{
|
||||
return false;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/uidgid.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <asm/device.h>
|
||||
|
||||
struct device;
|
||||
@ -63,9 +64,7 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
|
||||
* @name: The name of the bus.
|
||||
* @dev_name: Used for subsystems to enumerate devices like ("foo%u", dev->id).
|
||||
* @dev_root: Default device to use as the parent.
|
||||
* @bus_attrs: Default attributes of the bus.
|
||||
* @dev_attrs: Default attributes of the devices on the bus.
|
||||
* @drv_attrs: Default attributes of the device drivers on the bus.
|
||||
* @bus_groups: Default attributes of the bus.
|
||||
* @dev_groups: Default attributes of the devices on the bus.
|
||||
* @drv_groups: Default attributes of the device drivers on the bus.
|
||||
@ -106,9 +105,7 @@ struct bus_type {
|
||||
const char *name;
|
||||
const char *dev_name;
|
||||
struct device *dev_root;
|
||||
struct bus_attribute *bus_attrs; /* use bus_groups instead */
|
||||
struct device_attribute *dev_attrs; /* use dev_groups instead */
|
||||
struct driver_attribute *drv_attrs; /* use drv_groups instead */
|
||||
const struct attribute_group **bus_groups;
|
||||
const struct attribute_group **dev_groups;
|
||||
const struct attribute_group **drv_groups;
|
||||
@ -329,8 +326,6 @@ int subsys_virtual_register(struct bus_type *subsys,
|
||||
* @owner: The module owner.
|
||||
* @class_attrs: Default attributes of this class.
|
||||
* @dev_groups: Default attributes of the devices that belong to the class.
|
||||
* @dev_attrs: Default attributes of the devices belong to the class.
|
||||
* @dev_bin_attrs: Default binary attributes of the devices belong to the class.
|
||||
* @dev_kobj: The kobject that represents this class and links it into the hierarchy.
|
||||
* @dev_uevent: Called when a device is added, removed from this class, or a
|
||||
* few other things that generate uevents to add the environment
|
||||
@ -358,9 +353,7 @@ struct class {
|
||||
struct module *owner;
|
||||
|
||||
struct class_attribute *class_attrs;
|
||||
struct device_attribute *dev_attrs; /* use dev_groups instead */
|
||||
const struct attribute_group **dev_groups;
|
||||
struct bin_attribute *dev_bin_attrs;
|
||||
struct kobject *dev_kobj;
|
||||
|
||||
int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
|
||||
@ -427,8 +420,6 @@ struct class_attribute {
|
||||
char *buf);
|
||||
ssize_t (*store)(struct class *class, struct class_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
const void *(*namespace)(struct class *class,
|
||||
const struct class_attribute *attr);
|
||||
};
|
||||
|
||||
#define CLASS_ATTR(_name, _mode, _show, _store) \
|
||||
@ -438,10 +429,24 @@ struct class_attribute {
|
||||
#define CLASS_ATTR_RO(_name) \
|
||||
struct class_attribute class_attr_##_name = __ATTR_RO(_name)
|
||||
|
||||
extern int __must_check class_create_file(struct class *class,
|
||||
const struct class_attribute *attr);
|
||||
extern void class_remove_file(struct class *class,
|
||||
const struct class_attribute *attr);
|
||||
extern int __must_check class_create_file_ns(struct class *class,
|
||||
const struct class_attribute *attr,
|
||||
const void *ns);
|
||||
extern void class_remove_file_ns(struct class *class,
|
||||
const struct class_attribute *attr,
|
||||
const void *ns);
|
||||
|
||||
static inline int __must_check class_create_file(struct class *class,
|
||||
const struct class_attribute *attr)
|
||||
{
|
||||
return class_create_file_ns(class, attr, NULL);
|
||||
}
|
||||
|
||||
static inline void class_remove_file(struct class *class,
|
||||
const struct class_attribute *attr)
|
||||
{
|
||||
return class_remove_file_ns(class, attr, NULL);
|
||||
}
|
||||
|
||||
/* Simple class attribute that is just a static string */
|
||||
struct class_attribute_string {
|
||||
@ -602,8 +607,24 @@ extern void devres_close_group(struct device *dev, void *id);
|
||||
extern void devres_remove_group(struct device *dev, void *id);
|
||||
extern int devres_release_group(struct device *dev, void *id);
|
||||
|
||||
/* managed kzalloc/kfree for device drivers, no kmalloc, always use kzalloc */
|
||||
extern void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp);
|
||||
/* managed devm_k.alloc/kfree for device drivers */
|
||||
extern void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp);
|
||||
static inline void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
|
||||
{
|
||||
return devm_kmalloc(dev, size, gfp | __GFP_ZERO);
|
||||
}
|
||||
static inline void *devm_kmalloc_array(struct device *dev,
|
||||
size_t n, size_t size, gfp_t flags)
|
||||
{
|
||||
if (size != 0 && n > SIZE_MAX / size)
|
||||
return NULL;
|
||||
return devm_kmalloc(dev, n * size, flags);
|
||||
}
|
||||
static inline void *devm_kcalloc(struct device *dev,
|
||||
size_t n, size_t size, gfp_t flags)
|
||||
{
|
||||
return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
|
||||
}
|
||||
extern void devm_kfree(struct device *dev, void *p);
|
||||
|
||||
void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res);
|
||||
@ -1149,16 +1170,15 @@ do { \
|
||||
#endif
|
||||
|
||||
/*
|
||||
* dev_WARN*() acts like dev_printk(), but with the key difference
|
||||
* of using a WARN/WARN_ON to get the message out, including the
|
||||
* file/line information and a backtrace.
|
||||
* dev_WARN*() acts like dev_printk(), but with the key difference of
|
||||
* using WARN/WARN_ONCE to include file/line information and a backtrace.
|
||||
*/
|
||||
#define dev_WARN(dev, format, arg...) \
|
||||
WARN(1, "Device: %s\n" format, dev_driver_string(dev), ## arg);
|
||||
WARN(1, "%s %s: " format, dev_driver_string(dev), dev_name(dev), ## arg);
|
||||
|
||||
#define dev_WARN_ONCE(dev, condition, format, arg...) \
|
||||
WARN_ONCE(condition, "Device %s\n" format, \
|
||||
dev_driver_string(dev), ## arg)
|
||||
WARN_ONCE(condition, "%s %s: " format, \
|
||||
dev_driver_string(dev), dev_name(dev), ## arg)
|
||||
|
||||
/* Create alias, so I can be autoloaded. */
|
||||
#define MODULE_ALIAS_CHARDEV(major,minor) \
|
||||
|
@ -1514,7 +1514,7 @@ static inline void ide_set_max_pio(ide_drive_t *drive)
|
||||
|
||||
char *ide_media_string(ide_drive_t *);
|
||||
|
||||
extern struct device_attribute ide_dev_attrs[];
|
||||
extern const struct attribute_group *ide_dev_groups[];
|
||||
extern struct bus_type ide_bus_type;
|
||||
extern struct class *ide_port_class;
|
||||
|
||||
|
18
include/linux/kobj_completion.h
Normal file
18
include/linux/kobj_completion.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef _KOBJ_COMPLETION_H_
|
||||
#define _KOBJ_COMPLETION_H_
|
||||
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
struct kobj_completion {
|
||||
struct kobject kc_kobj;
|
||||
struct completion kc_unregister;
|
||||
};
|
||||
|
||||
#define kobj_to_kobj_completion(kobj) \
|
||||
container_of(kobj, struct kobj_completion, kc_kobj)
|
||||
|
||||
void kobj_completion_init(struct kobj_completion *kc, struct kobj_type *ktype);
|
||||
void kobj_completion_release(struct kobject *kobj);
|
||||
void kobj_completion_del_and_wait(struct kobj_completion *kc);
|
||||
#endif /* _KOBJ_COMPLETION_H_ */
|
@ -107,6 +107,7 @@ extern int __must_check kobject_move(struct kobject *, struct kobject *);
|
||||
extern struct kobject *kobject_get(struct kobject *kobj);
|
||||
extern void kobject_put(struct kobject *kobj);
|
||||
|
||||
extern const void *kobject_namespace(struct kobject *kobj);
|
||||
extern char *kobject_get_path(struct kobject *kobj, gfp_t flag);
|
||||
|
||||
struct kobj_type {
|
||||
|
@ -2874,8 +2874,20 @@ extern int __init dev_proc_init(void);
|
||||
#define dev_proc_init() 0
|
||||
#endif
|
||||
|
||||
extern int netdev_class_create_file(struct class_attribute *class_attr);
|
||||
extern void netdev_class_remove_file(struct class_attribute *class_attr);
|
||||
extern int netdev_class_create_file_ns(struct class_attribute *class_attr,
|
||||
const void *ns);
|
||||
extern void netdev_class_remove_file_ns(struct class_attribute *class_attr,
|
||||
const void *ns);
|
||||
|
||||
static inline int netdev_class_create_file(struct class_attribute *class_attr)
|
||||
{
|
||||
return netdev_class_create_file_ns(class_attr, NULL);
|
||||
}
|
||||
|
||||
static inline void netdev_class_remove_file(struct class_attribute *class_attr)
|
||||
{
|
||||
netdev_class_remove_file_ns(class_attr, NULL);
|
||||
}
|
||||
|
||||
extern struct kobj_ns_type_operations net_ns_type_operations;
|
||||
|
||||
|
@ -178,6 +178,7 @@ struct platform_driver {
|
||||
int (*resume)(struct platform_device *);
|
||||
struct device_driver driver;
|
||||
const struct platform_device_id *id_table;
|
||||
bool prevent_deferred_probe;
|
||||
};
|
||||
|
||||
#define to_platform_driver(drv) (container_of((drv), struct platform_driver, \
|
||||
|
@ -173,7 +173,6 @@ struct bin_attribute bin_attr_##_name = __BIN_ATTR_RW(_name, _size)
|
||||
struct sysfs_ops {
|
||||
ssize_t (*show)(struct kobject *, struct attribute *, char *);
|
||||
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
|
||||
const void *(*namespace)(struct kobject *, const struct attribute *);
|
||||
};
|
||||
|
||||
struct sysfs_dirent;
|
||||
@ -183,19 +182,23 @@ struct sysfs_dirent;
|
||||
int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
|
||||
void *data, struct module *owner);
|
||||
|
||||
int __must_check sysfs_create_dir(struct kobject *kobj);
|
||||
int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns);
|
||||
void sysfs_remove_dir(struct kobject *kobj);
|
||||
int __must_check sysfs_rename_dir(struct kobject *kobj, const char *new_name);
|
||||
int __must_check sysfs_move_dir(struct kobject *kobj,
|
||||
struct kobject *new_parent_kobj);
|
||||
int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
|
||||
const void *new_ns);
|
||||
int __must_check sysfs_move_dir_ns(struct kobject *kobj,
|
||||
struct kobject *new_parent_kobj,
|
||||
const void *new_ns);
|
||||
|
||||
int __must_check sysfs_create_file(struct kobject *kobj,
|
||||
const struct attribute *attr);
|
||||
int __must_check sysfs_create_file_ns(struct kobject *kobj,
|
||||
const struct attribute *attr,
|
||||
const void *ns);
|
||||
int __must_check sysfs_create_files(struct kobject *kobj,
|
||||
const struct attribute **attr);
|
||||
int __must_check sysfs_chmod_file(struct kobject *kobj,
|
||||
const struct attribute *attr, umode_t mode);
|
||||
void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);
|
||||
void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
|
||||
const void *ns);
|
||||
void sysfs_remove_files(struct kobject *kobj, const struct attribute **attr);
|
||||
|
||||
int __must_check sysfs_create_bin_file(struct kobject *kobj,
|
||||
@ -210,8 +213,9 @@ int __must_check sysfs_create_link_nowarn(struct kobject *kobj,
|
||||
const char *name);
|
||||
void sysfs_remove_link(struct kobject *kobj, const char *name);
|
||||
|
||||
int sysfs_rename_link(struct kobject *kobj, struct kobject *target,
|
||||
const char *old_name, const char *new_name);
|
||||
int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *target,
|
||||
const char *old_name, const char *new_name,
|
||||
const void *new_ns);
|
||||
|
||||
void sysfs_delete_link(struct kobject *dir, struct kobject *targ,
|
||||
const char *name);
|
||||
@ -241,9 +245,9 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
|
||||
|
||||
void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
|
||||
void sysfs_notify_dirent(struct sysfs_dirent *sd);
|
||||
struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name);
|
||||
struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd,
|
||||
const unsigned char *name,
|
||||
const void *ns);
|
||||
struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd);
|
||||
void sysfs_put(struct sysfs_dirent *sd);
|
||||
|
||||
@ -257,7 +261,7 @@ static inline int sysfs_schedule_callback(struct kobject *kobj,
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int sysfs_create_dir(struct kobject *kobj)
|
||||
static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -266,19 +270,22 @@ static inline void sysfs_remove_dir(struct kobject *kobj)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
|
||||
static inline int sysfs_rename_dir_ns(struct kobject *kobj,
|
||||
const char *new_name, const void *new_ns)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int sysfs_move_dir(struct kobject *kobj,
|
||||
struct kobject *new_parent_kobj)
|
||||
static inline int sysfs_move_dir_ns(struct kobject *kobj,
|
||||
struct kobject *new_parent_kobj,
|
||||
const void *new_ns)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int sysfs_create_file(struct kobject *kobj,
|
||||
const struct attribute *attr)
|
||||
static inline int sysfs_create_file_ns(struct kobject *kobj,
|
||||
const struct attribute *attr,
|
||||
const void *ns)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -295,8 +302,9 @@ static inline int sysfs_chmod_file(struct kobject *kobj,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sysfs_remove_file(struct kobject *kobj,
|
||||
const struct attribute *attr)
|
||||
static inline void sysfs_remove_file_ns(struct kobject *kobj,
|
||||
const struct attribute *attr,
|
||||
const void *ns)
|
||||
{
|
||||
}
|
||||
|
||||
@ -333,8 +341,9 @@ static inline void sysfs_remove_link(struct kobject *kobj, const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int sysfs_rename_link(struct kobject *k, struct kobject *t,
|
||||
const char *old_name, const char *new_name)
|
||||
static inline int sysfs_rename_link_ns(struct kobject *k, struct kobject *t,
|
||||
const char *old_name,
|
||||
const char *new_name, const void *ns)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -413,10 +422,9 @@ static inline void sysfs_notify(struct kobject *kobj, const char *dir,
|
||||
static inline void sysfs_notify_dirent(struct sysfs_dirent *sd)
|
||||
{
|
||||
}
|
||||
static inline
|
||||
struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name)
|
||||
static inline struct sysfs_dirent *
|
||||
sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, const unsigned char *name,
|
||||
const void *ns)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -435,4 +443,28 @@ static inline int __must_check sysfs_init(void)
|
||||
|
||||
#endif /* CONFIG_SYSFS */
|
||||
|
||||
static inline int __must_check sysfs_create_file(struct kobject *kobj,
|
||||
const struct attribute *attr)
|
||||
{
|
||||
return sysfs_create_file_ns(kobj, attr, NULL);
|
||||
}
|
||||
|
||||
static inline void sysfs_remove_file(struct kobject *kobj,
|
||||
const struct attribute *attr)
|
||||
{
|
||||
return sysfs_remove_file_ns(kobj, attr, NULL);
|
||||
}
|
||||
|
||||
static inline int sysfs_rename_link(struct kobject *kobj, struct kobject *target,
|
||||
const char *old_name, const char *new_name)
|
||||
{
|
||||
return sysfs_rename_link_ns(kobj, target, old_name, new_name, NULL);
|
||||
}
|
||||
|
||||
static inline struct sysfs_dirent *
|
||||
sysfs_get_dirent(struct sysfs_dirent *parent_sd, const unsigned char *name)
|
||||
{
|
||||
return sysfs_get_dirent_ns(parent_sd, name, NULL);
|
||||
}
|
||||
|
||||
#endif /* _SYSFS_H_ */
|
||||
|
@ -6292,6 +6292,7 @@ type_show(struct device *dev, struct device_attribute *attr, char *page)
|
||||
|
||||
return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type);
|
||||
}
|
||||
static DEVICE_ATTR_RO(type);
|
||||
|
||||
static ssize_t
|
||||
perf_event_mux_interval_ms_show(struct device *dev,
|
||||
@ -6336,17 +6337,19 @@ perf_event_mux_interval_ms_store(struct device *dev,
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(perf_event_mux_interval_ms);
|
||||
|
||||
static struct device_attribute pmu_dev_attrs[] = {
|
||||
__ATTR_RO(type),
|
||||
__ATTR_RW(perf_event_mux_interval_ms),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *pmu_dev_attrs[] = {
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_perf_event_mux_interval_ms.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(pmu_dev);
|
||||
|
||||
static int pmu_bus_running;
|
||||
static struct bus_type pmu_bus = {
|
||||
.name = "event_source",
|
||||
.dev_attrs = pmu_dev_attrs,
|
||||
.dev_groups = pmu_dev_groups,
|
||||
};
|
||||
|
||||
static void pmu_dev_release(struct device *dev)
|
||||
|
@ -13,11 +13,33 @@
|
||||
*/
|
||||
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/kobj_completion.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/**
|
||||
* kobject_namespace - return @kobj's namespace tag
|
||||
* @kobj: kobject in question
|
||||
*
|
||||
* Returns namespace tag of @kobj if its parent has namespace ops enabled
|
||||
* and thus @kobj should have a namespace tag associated with it. Returns
|
||||
* %NULL otherwise.
|
||||
*/
|
||||
const void *kobject_namespace(struct kobject *kobj)
|
||||
{
|
||||
const struct kobj_ns_type_operations *ns_ops = kobj_ns_ops(kobj);
|
||||
const void *ns;
|
||||
|
||||
if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE)
|
||||
return NULL;
|
||||
|
||||
ns = kobj->ktype->namespace(kobj);
|
||||
WARN_ON(!ns); /* @kobj in a namespace is required to have !NULL tag */
|
||||
return ns;
|
||||
}
|
||||
|
||||
/*
|
||||
* populate_dir - populate directory with attributes.
|
||||
* @kobj: object we're working on.
|
||||
@ -46,13 +68,21 @@ static int populate_dir(struct kobject *kobj)
|
||||
|
||||
static int create_dir(struct kobject *kobj)
|
||||
{
|
||||
int error = 0;
|
||||
error = sysfs_create_dir(kobj);
|
||||
int error;
|
||||
|
||||
error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj));
|
||||
if (!error) {
|
||||
error = populate_dir(kobj);
|
||||
if (error)
|
||||
sysfs_remove_dir(kobj);
|
||||
}
|
||||
|
||||
/*
|
||||
* @kobj->sd may be deleted by an ancestor going away. Hold an
|
||||
* extra reference so that it stays until @kobj is gone.
|
||||
*/
|
||||
sysfs_get(kobj->sd);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -428,7 +458,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name)
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = sysfs_rename_dir(kobj, new_name);
|
||||
error = sysfs_rename_dir_ns(kobj, new_name, kobject_namespace(kobj));
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
@ -472,6 +502,7 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent)
|
||||
if (kobj->kset)
|
||||
new_parent = kobject_get(&kobj->kset->kobj);
|
||||
}
|
||||
|
||||
/* old object path */
|
||||
devpath = kobject_get_path(kobj, GFP_KERNEL);
|
||||
if (!devpath) {
|
||||
@ -486,7 +517,7 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent)
|
||||
sprintf(devpath_string, "DEVPATH_OLD=%s", devpath);
|
||||
envp[0] = devpath_string;
|
||||
envp[1] = NULL;
|
||||
error = sysfs_move_dir(kobj, new_parent);
|
||||
error = sysfs_move_dir_ns(kobj, new_parent, kobject_namespace(kobj));
|
||||
if (error)
|
||||
goto out;
|
||||
old_parent = kobj->parent;
|
||||
@ -508,10 +539,15 @@ out:
|
||||
*/
|
||||
void kobject_del(struct kobject *kobj)
|
||||
{
|
||||
struct sysfs_dirent *sd;
|
||||
|
||||
if (!kobj)
|
||||
return;
|
||||
|
||||
sd = kobj->sd;
|
||||
sysfs_remove_dir(kobj);
|
||||
sysfs_put(sd);
|
||||
|
||||
kobj->state_in_sysfs = 0;
|
||||
kobj_kset_leave(kobj);
|
||||
kobject_put(kobj->parent);
|
||||
@ -726,6 +762,55 @@ const struct sysfs_ops kobj_sysfs_ops = {
|
||||
.store = kobj_attr_store,
|
||||
};
|
||||
|
||||
/**
|
||||
* kobj_completion_init - initialize a kobj_completion object.
|
||||
* @kc: kobj_completion
|
||||
* @ktype: type of kobject to initialize
|
||||
*
|
||||
* kobj_completion structures can be embedded within structures with different
|
||||
* lifetime rules. During the release of the enclosing object, we can
|
||||
* wait on the release of the kobject so that we don't free it while it's
|
||||
* still busy.
|
||||
*/
|
||||
void kobj_completion_init(struct kobj_completion *kc, struct kobj_type *ktype)
|
||||
{
|
||||
init_completion(&kc->kc_unregister);
|
||||
kobject_init(&kc->kc_kobj, ktype);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kobj_completion_init);
|
||||
|
||||
/**
|
||||
* kobj_completion_release - release a kobj_completion object
|
||||
* @kobj: kobject embedded in kobj_completion
|
||||
*
|
||||
* Used with kobject_release to notify waiters that the kobject has been
|
||||
* released.
|
||||
*/
|
||||
void kobj_completion_release(struct kobject *kobj)
|
||||
{
|
||||
struct kobj_completion *kc = kobj_to_kobj_completion(kobj);
|
||||
complete(&kc->kc_unregister);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kobj_completion_release);
|
||||
|
||||
/**
|
||||
* kobj_completion_del_and_wait - release the kobject and wait for it
|
||||
* @kc: kobj_completion object to release
|
||||
*
|
||||
* Delete the kobject from sysfs and drop the reference count. Then wait
|
||||
* until any other outstanding references are also dropped. This routine
|
||||
* is only necessary once other references may have been taken on the
|
||||
* kobject. Typically this happens when the kobject has been published
|
||||
* to sysfs via kobject_add.
|
||||
*/
|
||||
void kobj_completion_del_and_wait(struct kobj_completion *kc)
|
||||
{
|
||||
kobject_del(&kc->kc_kobj);
|
||||
kobject_put(&kc->kc_kobj);
|
||||
wait_for_completion(&kc->kc_unregister);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kobj_completion_del_and_wait);
|
||||
|
||||
/**
|
||||
* kset_register - initialize and add a kset.
|
||||
* @k: kset.
|
||||
|
@ -1344,17 +1344,19 @@ int netdev_register_kobject(struct net_device *net)
|
||||
return error;
|
||||
}
|
||||
|
||||
int netdev_class_create_file(struct class_attribute *class_attr)
|
||||
int netdev_class_create_file_ns(struct class_attribute *class_attr,
|
||||
const void *ns)
|
||||
{
|
||||
return class_create_file(&net_class, class_attr);
|
||||
return class_create_file_ns(&net_class, class_attr, ns);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_class_create_file);
|
||||
EXPORT_SYMBOL(netdev_class_create_file_ns);
|
||||
|
||||
void netdev_class_remove_file(struct class_attribute *class_attr)
|
||||
void netdev_class_remove_file_ns(struct class_attribute *class_attr,
|
||||
const void *ns)
|
||||
{
|
||||
class_remove_file(&net_class, class_attr);
|
||||
class_remove_file_ns(&net_class, class_attr, ns);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_class_remove_file);
|
||||
EXPORT_SYMBOL(netdev_class_remove_file_ns);
|
||||
|
||||
int netdev_kobject_init(void)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user