diff options
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r-- | drivers/base/core.c | 76 |
1 files changed, 43 insertions, 33 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 6bee6af8d8e1..ef55df34ddd0 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -56,7 +56,14 @@ static inline int device_is_not_partition(struct device *dev) */ const char *dev_driver_string(const struct device *dev) { - return dev->driver ? dev->driver->name : + struct device_driver *drv; + + /* dev->driver can change to NULL underneath us because of unbinding, + * so be careful about accessing it. dev->bus and dev->class should + * never change once they are set, so they don't need special care. + */ + drv = ACCESS_ONCE(dev->driver); + return drv ? drv->name : (dev->bus ? dev->bus->name : (dev->class ? dev->class->name : "")); } @@ -93,7 +100,7 @@ static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, return ret; } -static struct sysfs_ops dev_sysfs_ops = { +static const struct sysfs_ops dev_sysfs_ops = { .show = dev_attr_show, .store = dev_attr_store, }; @@ -245,7 +252,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, return retval; } -static struct kset_uevent_ops device_uevent_ops = { +static const struct kset_uevent_ops device_uevent_ops = { .filter = dev_uevent_filter, .name = dev_uevent_name, .uevent = dev_uevent, @@ -299,15 +306,10 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, { enum kobject_action action; - if (kobject_action_type(buf, count, &action) == 0) { + if (kobject_action_type(buf, count, &action) == 0) kobject_uevent(&dev->kobj, action); - goto out; - } - - dev_err(dev, "uevent: unsupported action-string; this will " - "be ignored in a future kernel version\n"); - kobject_uevent(&dev->kobj, KOBJ_ADD); -out: + else + dev_err(dev, "uevent: unknown action-string\n"); return count; } @@ -439,7 +441,8 @@ struct kset *devices_kset; * @dev: device. * @attr: device attribute descriptor. */ -int device_create_file(struct device *dev, struct device_attribute *attr) +int device_create_file(struct device *dev, + const struct device_attribute *attr) { int error = 0; if (dev) @@ -452,7 +455,8 @@ int device_create_file(struct device *dev, struct device_attribute *attr) * @dev: device. * @attr: device attribute descriptor. */ -void device_remove_file(struct device *dev, struct device_attribute *attr) +void device_remove_file(struct device *dev, + const struct device_attribute *attr) { if (dev) sysfs_remove_file(&dev->kobj, &attr->attr); @@ -463,7 +467,8 @@ void device_remove_file(struct device *dev, struct device_attribute *attr) * @dev: device. * @attr: device binary attribute descriptor. */ -int device_create_bin_file(struct device *dev, struct bin_attribute *attr) +int device_create_bin_file(struct device *dev, + const struct bin_attribute *attr) { int error = -EINVAL; if (dev) @@ -477,7 +482,8 @@ EXPORT_SYMBOL_GPL(device_create_bin_file); * @dev: device. * @attr: device binary attribute descriptor. */ -void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) +void device_remove_bin_file(struct device *dev, + const struct bin_attribute *attr) { if (dev) sysfs_remove_bin_file(&dev->kobj, attr); @@ -596,6 +602,7 @@ static struct kobject *get_device_parent(struct device *dev, int retval; if (dev->class) { + static DEFINE_MUTEX(gdp_mutex); struct kobject *kobj = NULL; struct kobject *parent_kobj; struct kobject *k; @@ -612,6 +619,8 @@ static struct kobject *get_device_parent(struct device *dev, else parent_kobj = &parent->kobj; + mutex_lock(&gdp_mutex); + /* find our class-directory at the parent and reference it */ spin_lock(&dev->class->p->class_dirs.list_lock); list_for_each_entry(k, &dev->class->p->class_dirs.list, entry) @@ -620,20 +629,26 @@ static struct kobject *get_device_parent(struct device *dev, break; } spin_unlock(&dev->class->p->class_dirs.list_lock); - if (kobj) + if (kobj) { + mutex_unlock(&gdp_mutex); return kobj; + } /* or create a new class-directory at the parent device */ k = kobject_create(); - if (!k) + if (!k) { + mutex_unlock(&gdp_mutex); return NULL; + } k->kset = &dev->class->p->class_dirs; retval = kobject_add(k, parent_kobj, "%s", dev->class->name); if (retval < 0) { + mutex_unlock(&gdp_mutex); kobject_put(k); return NULL; } /* do not emit an uevent for this simple "glue" directory */ + mutex_unlock(&gdp_mutex); return k; } @@ -898,8 +913,10 @@ int device_add(struct device *dev) dev->init_name = NULL; } - if (!dev_name(dev)) + if (!dev_name(dev)) { + error = -EINVAL; goto name_error; + } pr_debug("device: '%s': %s\n", dev_name(dev), __func__); @@ -987,6 +1004,8 @@ done: device_remove_class_symlinks(dev); SymlinkError: if (MAJOR(dev->devt)) + devtmpfs_delete_node(dev); + if (MAJOR(dev->devt)) device_remove_sys_dev_entry(dev); devtattrError: if (MAJOR(dev->devt)) @@ -1559,22 +1578,16 @@ int device_rename(struct device *dev, char *new_name) if (old_class_name) { new_class_name = make_class_name(dev->class->name, &dev->kobj); if (new_class_name) { - error = sysfs_create_link_nowarn(&dev->parent->kobj, - &dev->kobj, - new_class_name); - if (error) - goto out; - sysfs_remove_link(&dev->parent->kobj, old_class_name); + error = sysfs_rename_link(&dev->parent->kobj, + &dev->kobj, + old_class_name, + new_class_name); } } #else if (dev->class) { - error = sysfs_create_link_nowarn(&dev->class->p->class_subsys.kobj, - &dev->kobj, dev_name(dev)); - if (error) - goto out; - sysfs_remove_link(&dev->class->p->class_subsys.kobj, - old_device_name); + error = sysfs_rename_link(&dev->class->p->class_subsys.kobj, + &dev->kobj, old_device_name, new_name); } #endif @@ -1728,8 +1741,5 @@ void device_shutdown(void) dev->driver->shutdown(dev); } } - kobject_put(sysfs_dev_char_kobj); - kobject_put(sysfs_dev_block_kobj); - kobject_put(dev_kobj); async_synchronize_full(); } |