Commit 7eff2e7a authored by Kay Sievers's avatar Kay Sievers Committed by Greg Kroah-Hartman
Browse files

Driver core: change add_uevent_var to use a struct



This changes the uevent buffer functions to use a struct instead of a
long list of parameters. It does no longer require the caller to do the
proper buffer termination and size accounting, which is currently wrong
in some places. It fixes a known bug where parts of the uevent
environment are overwritten because of wrong index calculations.

Many thanks to Mathieu Desnoyers for finding bugs and improving the
error handling.

Signed-off-by: default avatarKay Sievers <kay.sievers@vrfy.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Cc: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 8380770c
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -66,8 +66,7 @@ static int tiocx_match(struct device *dev, struct device_driver *drv)

}

static int tiocx_uevent(struct device *dev, char **envp, int num_envp,
			 char *buffer, int buffer_size)
static int tiocx_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	return -ENODEV;
}
+11 −26
Original line number Diff line number Diff line
@@ -57,26 +57,21 @@ ssize_t of_device_get_modalias(struct of_device *ofdev,
	return tsize;
}

int of_device_uevent(struct device *dev,
		char **envp, int num_envp, char *buffer, int buffer_size)
int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	struct of_device *ofdev;
	const char *compat;
	int i = 0, length = 0, seen = 0, cplen, sl;
	int seen = 0, cplen, sl;

	if (!dev)
		return -ENODEV;

	ofdev = to_of_device(dev);

	if (add_uevent_var(envp, num_envp, &i,
			   buffer, buffer_size, &length,
			   "OF_NAME=%s", ofdev->node->name))
	if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name))
		return -ENOMEM;

	if (add_uevent_var(envp, num_envp, &i,
			   buffer, buffer_size, &length,
			   "OF_TYPE=%s", ofdev->node->type))
	if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type))
		return -ENOMEM;

        /* Since the compatible field can contain pretty much anything
@@ -85,9 +80,7 @@ int of_device_uevent(struct device *dev,

	compat = of_get_property(ofdev->node, "compatible", &cplen);
	while (compat && *compat && cplen > 0) {
		if (add_uevent_var(envp, num_envp, &i,
				   buffer, buffer_size, &length,
				   "OF_COMPATIBLE_%d=%s", seen, compat))
		if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
			return -ENOMEM;

		sl = strlen (compat) + 1;
@@ -96,25 +89,17 @@ int of_device_uevent(struct device *dev,
		seen++;
	}

	if (add_uevent_var(envp, num_envp, &i,
			   buffer, buffer_size, &length,
			   "OF_COMPATIBLE_N=%d", seen))
	if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
		return -ENOMEM;

	/* modalias is trickier, we add it in 2 steps */
	if (add_uevent_var(envp, num_envp, &i,
			   buffer, buffer_size, &length,
			   "MODALIAS="))
	if (add_uevent_var(env, "MODALIAS="))
		return -ENOMEM;

	sl = of_device_get_modalias(ofdev, &buffer[length-1],
					buffer_size-length);
	if (sl >= (buffer_size-length))
	sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1],
				    sizeof(env->buf) - env->buflen);
	if (sl >= (sizeof(env->buf) - env->buflen))
		return -ENOMEM;

	length += sl;

	envp[i] = NULL;
	env->buflen += sl;

	return 0;
}
+3 −13
Original line number Diff line number Diff line
@@ -317,30 +317,20 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv)
	return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL);
}

static int vio_hotplug(struct device *dev, char **envp, int num_envp,
			char *buffer, int buffer_size)
static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env)
{
	const struct vio_dev *vio_dev = to_vio_dev(dev);
	struct device_node *dn;
	const char *cp;
	int length;

	if (!num_envp)
		return -ENOMEM;

	dn = dev->archdata.of_node;
	if (!dn)
		return -ENODEV;
	cp = of_get_property(dn, "compatible", &length);
	cp = of_get_property(dn, "compatible", NULL);
	if (!cp)
		return -ENODEV;

	envp[0] = buffer;
	length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s",
				vio_dev->type, cp);
	if ((buffer_size - length) <= 0)
		return -ENOMEM;
	envp[1] = NULL;
	add_uevent_var(env, "MODALIAS=vio:T%sS%s", vio_dev->type, cp);
	return 0;
}

+2 −7
Original line number Diff line number Diff line
@@ -437,18 +437,13 @@ static void ps3_system_bus_shutdown(struct device *_dev)
	dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
}

static int ps3_system_bus_uevent(struct device *_dev, char **envp,
				 int num_envp, char *buffer, int buffer_size)
static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *env)
{
	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
	int i = 0, length = 0;

	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
			   &length, "MODALIAS=ps3:%d",
			   dev->match_id))
	if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id))
		return -ENOMEM;

	envp[i] = NULL;
	return 0;
}

+8 −27
Original line number Diff line number Diff line
@@ -540,60 +540,41 @@ static int block_uevent_filter(struct kset *kset, struct kobject *kobj)
	return ((ktype == &ktype_block) || (ktype == &ktype_part));
}

static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp,
			 int num_envp, char *buffer, int buffer_size)
static int block_uevent(struct kset *kset, struct kobject *kobj,
			struct kobj_uevent_env *env)
{
	struct kobj_type *ktype = get_ktype(kobj);
	struct device *physdev;
	struct gendisk *disk;
	struct hd_struct *part;
	int length = 0;
	int i = 0;

	if (ktype == &ktype_block) {
		disk = container_of(kobj, struct gendisk, kobj);
		add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
			       &length, "MINOR=%u", disk->first_minor);
		add_uevent_var(env, "MINOR=%u", disk->first_minor);
	} else if (ktype == &ktype_part) {
		disk = container_of(kobj->parent, struct gendisk, kobj);
		part = container_of(kobj, struct hd_struct, kobj);
		add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
			       &length, "MINOR=%u",
		add_uevent_var(env, "MINOR=%u",
			       disk->first_minor + part->partno);
	} else
		return 0;

	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
		       "MAJOR=%u", disk->major);
	add_uevent_var(env, "MAJOR=%u", disk->major);

	/* add physical device, backing this device  */
	physdev = disk->driverfs_dev;
	if (physdev) {
		char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);

		add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
			       &length, "PHYSDEVPATH=%s", path);
		add_uevent_var(env, "PHYSDEVPATH=%s", path);
		kfree(path);

		if (physdev->bus)
			add_uevent_var(envp, num_envp, &i,
				       buffer, buffer_size, &length,
				       "PHYSDEVBUS=%s",
				       physdev->bus->name);
			add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name);

		if (physdev->driver)
			add_uevent_var(envp, num_envp, &i,
				       buffer, buffer_size, &length,
				       "PHYSDEVDRIVER=%s",
				       physdev->driver->name);
	}

	/* terminate, set to next free slot, shrink available space */
	envp[i] = NULL;
	envp = &envp[i];
	num_envp -= i;
	buffer = &buffer[length];
	buffer_size -= length;
			add_uevent_var(env, physdev->driver->name);
	}

	return 0;
}
Loading