driver core: Use sysfs_rename_link in device_rename
[safe/jmp/linux-2.6] / drivers / base / core.c
index 99dfe96..ef55df3 100644 (file)
@@ -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,
 };
@@ -166,13 +173,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
        if (MAJOR(dev->devt)) {
                const char *tmp;
                const char *name;
+               mode_t mode = 0;
 
                add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
                add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
-               name = device_get_nodename(dev, &tmp);
+               name = device_get_devnode(dev, &mode, &tmp);
                if (name) {
                        add_uevent_var(env, "DEVNAME=%s", name);
                        kfree(tmp);
+                       if (mode)
+                               add_uevent_var(env, "DEVMODE=%#o", mode & 0777);
                }
        }
 
@@ -242,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,
@@ -296,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;
 }
 
@@ -341,7 +346,7 @@ static void device_remove_attributes(struct device *dev,
 }
 
 static int device_add_groups(struct device *dev,
-                            struct attribute_group **groups)
+                            const struct attribute_group **groups)
 {
        int error = 0;
        int i;
@@ -361,7 +366,7 @@ static int device_add_groups(struct device *dev,
 }
 
 static void device_remove_groups(struct device *dev,
-                                struct attribute_group **groups)
+                                const struct attribute_group **groups)
 {
        int i;
 
@@ -436,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)
@@ -449,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);
@@ -460,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)
@@ -474,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);
@@ -593,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;
@@ -609,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)
@@ -617,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;
        }
 
@@ -895,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__);
 
@@ -929,6 +949,8 @@ int device_add(struct device *dev)
                error = device_create_sys_dev_entry(dev);
                if (error)
                        goto devtattrError;
+
+               devtmpfs_create_node(dev);
        }
 
        error = device_add_class_symlinks(dev);
@@ -982,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))
@@ -1075,6 +1099,7 @@ void device_del(struct device *dev)
        if (parent)
                klist_del(&dev->p->knode_parent);
        if (MAJOR(dev->devt)) {
+               devtmpfs_delete_node(dev);
                device_remove_sys_dev_entry(dev);
                device_remove_file(dev, &devt_attr);
        }
@@ -1145,8 +1170,9 @@ static struct device *next_device(struct klist_iter *i)
 }
 
 /**
- * device_get_nodename - path of device node file
+ * device_get_devnode - path of device node file
  * @dev: device
+ * @mode: returned file access mode
  * @tmp: possibly allocated string
  *
  * Return the relative path of a possible device node.
@@ -1154,21 +1180,22 @@ static struct device *next_device(struct klist_iter *i)
  * a name. This memory is returned in tmp and needs to be
  * freed by the caller.
  */
-const char *device_get_nodename(struct device *dev, const char **tmp)
+const char *device_get_devnode(struct device *dev,
+                              mode_t *mode, const char **tmp)
 {
        char *s;
 
        *tmp = NULL;
 
        /* the device type may provide a specific name */
-       if (dev->type && dev->type->nodename)
-               *tmp = dev->type->nodename(dev);
+       if (dev->type && dev->type->devnode)
+               *tmp = dev->type->devnode(dev, mode);
        if (*tmp)
                return *tmp;
 
        /* the class may provide a specific name */
-       if (dev->class && dev->class->nodename)
-               *tmp = dev->class->nodename(dev);
+       if (dev->class && dev->class->devnode)
+               *tmp = dev->class->devnode(dev, mode);
        if (*tmp)
                return *tmp;
 
@@ -1551,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
 
@@ -1720,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();
 }