Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+105 −40
Original line number Diff line number Diff line
@@ -660,6 +660,82 @@ static int setup_parent(struct device *dev, struct device *parent)
	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.
 *	@dev:	device.
@@ -674,7 +750,6 @@ static int setup_parent(struct device *dev, struct device *parent)
int device_add(struct device *dev)
{
	struct device *parent = NULL;
	char *class_name = NULL;
	struct class_interface *class_intf;
	int error = -EINVAL;

@@ -714,27 +789,9 @@ int device_add(struct device *dev)
			goto ueventattrError;
	}

	if (dev->class) {
		sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
				  "subsystem");
		/* 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_class_symlinks(dev);
	if (error)
		goto SymlinkError;
	error = device_add_attrs(dev);
	if (error)
		goto AttrsError;
@@ -761,7 +818,6 @@ int device_add(struct device *dev)
		up(&dev->class->sem);
	}
 Done:
	kfree(class_name);
	put_device(dev);
	return error;
 BusError:
@@ -772,6 +828,8 @@ int device_add(struct device *dev)
					     BUS_NOTIFY_DEL_DEVICE, dev);
	device_remove_attrs(dev);
 AttrsError:
	device_remove_class_symlinks(dev);
 SymlinkError:
	if (MAJOR(dev->devt))
		device_remove_file(dev, &devt_attr);

@@ -1156,7 +1214,7 @@ int device_rename(struct device *dev, char *new_name)
{
	char *old_class_name = NULL;
	char *new_class_name = NULL;
	char *old_symlink_name = NULL;
	char *old_device_name = NULL;
	int error;

	dev = get_device(dev);
@@ -1170,42 +1228,49 @@ int device_rename(struct device *dev, char *new_name)
		old_class_name = make_class_name(dev->class->name, &dev->kobj);
#endif

	if (dev->class) {
		old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
		if (!old_symlink_name) {
	old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
	if (!old_device_name) {
		error = -ENOMEM;
			goto out_free_old_class;
		}
		strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
		goto out;
	}

	strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
	strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);

	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
	if (old_class_name) {
		new_class_name = make_class_name(dev->class->name, &dev->kobj);
		if (new_class_name) {
			sysfs_create_link(&dev->parent->kobj, &dev->kobj,
					  new_class_name);
			error = sysfs_create_link(&dev->parent->kobj,
						  &dev->kobj, new_class_name);
			if (error)
				goto out;
			sysfs_remove_link(&dev->parent->kobj, old_class_name);
		}
	}
#endif

	if (dev->class) {
		sysfs_remove_link(&dev->class->subsys.kobj,
				  old_symlink_name);
		sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
		sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
		error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
					  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);

	kfree(new_class_name);
	kfree(old_symlink_name);
 out_free_old_class:
	kfree(old_class_name);
	kfree(old_device_name);

	return error;
}