Commit 2ee97caf authored by Cornelia Huck's avatar Cornelia Huck Committed by Greg Kroah-Hartman

Driver core: check return code of sysfs_create_link()

Check for return value of sysfs_create_link() in device_add() and
device_rename().  Add helper functions device_add_class_symlinks() and
device_remove_class_symlinks() to make the code easier to read.

[akpm@linux-foundation.org: fix unused var warnings]
Signed-off-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Acked-by: default avatarJeff Garzik <jeff@garzik.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent be388494
...@@ -660,6 +660,82 @@ static int setup_parent(struct device *dev, struct device *parent) ...@@ -660,6 +660,82 @@ static int setup_parent(struct device *dev, struct device *parent)
return 0; return 0;
} }
static int device_add_class_symlinks(struct device *dev)
{
int error;
if (!dev->class)
return 0;
error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
"subsystem");
if (error)
goto out;
/*
* If this is not a "fake" compatible device, then create the
* symlink from the class to the device.
*/
if (dev->kobj.parent != &dev->class->subsys.kobj) {
error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
dev->bus_id);
if (error)
goto out_subsys;
}
/* only bus-device parents get a "device"-link */
if (dev->parent && dev->parent->bus) {
error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
"device");
if (error)
goto out_busid;
#ifdef CONFIG_SYSFS_DEPRECATED
{
char * class_name = make_class_name(dev->class->name,
&dev->kobj);
if (class_name)
error = sysfs_create_link(&dev->parent->kobj,
&dev->kobj, class_name);
kfree(class_name);
if (error)
goto out_device;
}
#endif
}
return 0;
#ifdef CONFIG_SYSFS_DEPRECATED
out_device:
if (dev->parent)
sysfs_remove_link(&dev->kobj, "device");
#endif
out_busid:
if (dev->kobj.parent != &dev->class->subsys.kobj)
sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
out_subsys:
sysfs_remove_link(&dev->kobj, "subsystem");
out:
return error;
}
static void device_remove_class_symlinks(struct device *dev)
{
if (!dev->class)
return;
if (dev->parent) {
#ifdef CONFIG_SYSFS_DEPRECATED
char *class_name;
class_name = make_class_name(dev->class->name, &dev->kobj);
if (class_name) {
sysfs_remove_link(&dev->parent->kobj, class_name);
kfree(class_name);
}
#endif
sysfs_remove_link(&dev->kobj, "device");
}
if (dev->kobj.parent != &dev->class->subsys.kobj)
sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
sysfs_remove_link(&dev->kobj, "subsystem");
}
/** /**
* device_add - add device to device hierarchy. * device_add - add device to device hierarchy.
* @dev: device. * @dev: device.
...@@ -674,7 +750,6 @@ static int setup_parent(struct device *dev, struct device *parent) ...@@ -674,7 +750,6 @@ static int setup_parent(struct device *dev, struct device *parent)
int device_add(struct device *dev) int device_add(struct device *dev)
{ {
struct device *parent = NULL; struct device *parent = NULL;
char *class_name = NULL;
struct class_interface *class_intf; struct class_interface *class_intf;
int error = -EINVAL; int error = -EINVAL;
...@@ -714,27 +789,9 @@ int device_add(struct device *dev) ...@@ -714,27 +789,9 @@ int device_add(struct device *dev)
goto ueventattrError; goto ueventattrError;
} }
if (dev->class) { error = device_add_class_symlinks(dev);
sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, if (error)
"subsystem"); goto SymlinkError;
/* If this is not a "fake" compatible device, then create the
* symlink from the class to the device. */
if (dev->kobj.parent != &dev->class->subsys.kobj)
sysfs_create_link(&dev->class->subsys.kobj,
&dev->kobj, dev->bus_id);
if (parent) {
sysfs_create_link(&dev->kobj, &dev->parent->kobj,
"device");
#ifdef CONFIG_SYSFS_DEPRECATED
class_name = make_class_name(dev->class->name,
&dev->kobj);
if (class_name)
sysfs_create_link(&dev->parent->kobj,
&dev->kobj, class_name);
#endif
}
}
error = device_add_attrs(dev); error = device_add_attrs(dev);
if (error) if (error)
goto AttrsError; goto AttrsError;
...@@ -761,7 +818,6 @@ int device_add(struct device *dev) ...@@ -761,7 +818,6 @@ int device_add(struct device *dev)
up(&dev->class->sem); up(&dev->class->sem);
} }
Done: Done:
kfree(class_name);
put_device(dev); put_device(dev);
return error; return error;
BusError: BusError:
...@@ -772,6 +828,8 @@ int device_add(struct device *dev) ...@@ -772,6 +828,8 @@ int device_add(struct device *dev)
BUS_NOTIFY_DEL_DEVICE, dev); BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_attrs(dev); device_remove_attrs(dev);
AttrsError: AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
if (MAJOR(dev->devt)) if (MAJOR(dev->devt))
device_remove_file(dev, &devt_attr); device_remove_file(dev, &devt_attr);
...@@ -1156,7 +1214,7 @@ int device_rename(struct device *dev, char *new_name) ...@@ -1156,7 +1214,7 @@ int device_rename(struct device *dev, char *new_name)
{ {
char *old_class_name = NULL; char *old_class_name = NULL;
char *new_class_name = NULL; char *new_class_name = NULL;
char *old_symlink_name = NULL; char *old_device_name = NULL;
int error; int error;
dev = get_device(dev); dev = get_device(dev);
...@@ -1170,42 +1228,49 @@ int device_rename(struct device *dev, char *new_name) ...@@ -1170,42 +1228,49 @@ int device_rename(struct device *dev, char *new_name)
old_class_name = make_class_name(dev->class->name, &dev->kobj); old_class_name = make_class_name(dev->class->name, &dev->kobj);
#endif #endif
if (dev->class) { old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); if (!old_device_name) {
if (!old_symlink_name) {
error = -ENOMEM; error = -ENOMEM;
goto out_free_old_class; goto out;
}
strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
} }
strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
error = kobject_rename(&dev->kobj, new_name); error = kobject_rename(&dev->kobj, new_name);
if (error) {
strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
goto out;
}
#ifdef CONFIG_SYSFS_DEPRECATED #ifdef CONFIG_SYSFS_DEPRECATED
if (old_class_name) { if (old_class_name) {
new_class_name = make_class_name(dev->class->name, &dev->kobj); new_class_name = make_class_name(dev->class->name, &dev->kobj);
if (new_class_name) { if (new_class_name) {
sysfs_create_link(&dev->parent->kobj, &dev->kobj, error = sysfs_create_link(&dev->parent->kobj,
new_class_name); &dev->kobj, new_class_name);
if (error)
goto out;
sysfs_remove_link(&dev->parent->kobj, old_class_name); sysfs_remove_link(&dev->parent->kobj, old_class_name);
} }
} }
#endif #endif
if (dev->class) { if (dev->class) {
sysfs_remove_link(&dev->class->subsys.kobj, sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
old_symlink_name); error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
dev->bus_id); dev->bus_id);
if (error) {
/* Uh... how to unravel this if restoring can fail? */
dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
__FUNCTION__, error);
} }
}
out:
put_device(dev); put_device(dev);
kfree(new_class_name); kfree(new_class_name);
kfree(old_symlink_name);
out_free_old_class:
kfree(old_class_name); kfree(old_class_name);
kfree(old_device_name);
return error; return error;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment