Commit e020ff61 authored by Saravana Kannan's avatar Saravana Kannan Committed by Greg Kroah-Hartman
Browse files

driver core: Fix device link device name collision

The device link device's name was of the form:
<supplier-dev-name>--<consumer-dev-name>

This can cause name collision as reported here [1] as device names are
not globally unique. Since device names have to be unique within the
bus/class, add the bus/class name as a prefix to the device names used to
construct the device link device name.

So the devuce link device's name will be of the form:
<supplier-bus-name>:<supplier-dev-name>--<consumer-bus-name>:<consumer-dev-name>

[1] - https://lore.kernel.org/lkml/20201229033440.32142-1-michael@walle.cc/



Fixes: 287905e6 ("driver core: Expose device link details in sysfs")
Cc: stable@vger.kernel.org
Reported-by: default avatarMichael Walle <michael@walle.cc>
Tested-by: default avatarMichael Walle <michael@walle.cc>
Signed-off-by: default avatarSaravana Kannan <saravanak@google.com>
Link: https://lore.kernel.org/r/20210110175408.1465657-1-saravanak@google.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3d1cf435
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -5,8 +5,8 @@ Description:
		Provide a place in sysfs for the device link objects in the
		kernel at any given time.  The name of a device link directory,
		denoted as ... above, is of the form <supplier>--<consumer>
		where <supplier> is the supplier device name and <consumer> is
		the consumer device name.
		where <supplier> is the supplier bus:device name and <consumer>
		is the consumer bus:device name.

What:		/sys/class/devlink/.../auto_remove_on
Date:		May 2020
+3 −2
Original line number Diff line number Diff line
@@ -4,5 +4,6 @@ Contact: Saravana Kannan <saravanak@google.com>
Description:
		The /sys/devices/.../consumer:<consumer> are symlinks to device
		links where this device is the supplier. <consumer> denotes the
		name of the consumer in that device link. There can be zero or
		more of these symlinks for a given device.
		name of the consumer in that device link and is of the form
		bus:device name. There can be zero or more of these symlinks
		for a given device.
+3 −2
Original line number Diff line number Diff line
@@ -4,5 +4,6 @@ Contact: Saravana Kannan <saravanak@google.com>
Description:
		The /sys/devices/.../supplier:<supplier> are symlinks to device
		links where this device is the consumer. <supplier> denotes the
		name of the supplier in that device link. There can be zero or
		more of these symlinks for a given device.
		name of the supplier in that device link and is of the form
		bus:device name. There can be zero or more of these symlinks
		for a given device.
+15 −12
Original line number Diff line number Diff line
@@ -471,7 +471,9 @@ static int devlink_add_symlinks(struct device *dev,
	struct device *con = link->consumer;
	char *buf;

	len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
	len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)),
		  strlen(dev_bus_name(con)) + strlen(dev_name(con)));
	len += strlen(":");
	len += strlen("supplier:") + 1;
	buf = kzalloc(len, GFP_KERNEL);
	if (!buf)
@@ -485,12 +487,12 @@ static int devlink_add_symlinks(struct device *dev,
	if (ret)
		goto err_con;

	snprintf(buf, len, "consumer:%s", dev_name(con));
	snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
	ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf);
	if (ret)
		goto err_con_dev;

	snprintf(buf, len, "supplier:%s", dev_name(sup));
	snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup));
	ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf);
	if (ret)
		goto err_sup_dev;
@@ -498,7 +500,7 @@ static int devlink_add_symlinks(struct device *dev,
	goto out;

err_sup_dev:
	snprintf(buf, len, "consumer:%s", dev_name(con));
	snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
	sysfs_remove_link(&sup->kobj, buf);
err_con_dev:
	sysfs_remove_link(&link->link_dev.kobj, "consumer");
@@ -521,7 +523,9 @@ static void devlink_remove_symlinks(struct device *dev,
	sysfs_remove_link(&link->link_dev.kobj, "consumer");
	sysfs_remove_link(&link->link_dev.kobj, "supplier");

	len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
	len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)),
		  strlen(dev_bus_name(con)) + strlen(dev_name(con)));
	len += strlen(":");
	len += strlen("supplier:") + 1;
	buf = kzalloc(len, GFP_KERNEL);
	if (!buf) {
@@ -529,9 +533,9 @@ static void devlink_remove_symlinks(struct device *dev,
		return;
	}

	snprintf(buf, len, "supplier:%s", dev_name(sup));
	snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup));
	sysfs_remove_link(&con->kobj, buf);
	snprintf(buf, len, "consumer:%s", dev_name(con));
	snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
	sysfs_remove_link(&sup->kobj, buf);
	kfree(buf);
}
@@ -752,8 +756,9 @@ struct device_link *device_link_add(struct device *consumer,

	link->link_dev.class = &devlink_class;
	device_set_pm_not_required(&link->link_dev);
	dev_set_name(&link->link_dev, "%s--%s",
		     dev_name(supplier), dev_name(consumer));
	dev_set_name(&link->link_dev, "%s:%s--%s:%s",
		     dev_bus_name(supplier), dev_name(supplier),
		     dev_bus_name(consumer), dev_name(consumer));
	if (device_register(&link->link_dev)) {
		put_device(consumer);
		put_device(supplier);
@@ -1823,9 +1828,7 @@ const char *dev_driver_string(const struct device *dev)
	 * never change once they are set, so they don't need special care.
	 */
	drv = READ_ONCE(dev->driver);
	return drv ? drv->name :
			(dev->bus ? dev->bus->name :
			(dev->class ? dev->class->name : ""));
	return drv ? drv->name : dev_bus_name(dev);
}
EXPORT_SYMBOL(dev_driver_string);

+12 −0
Original line number Diff line number Diff line
@@ -609,6 +609,18 @@ static inline const char *dev_name(const struct device *dev)
	return kobject_name(&dev->kobj);
}

/**
 * dev_bus_name - Return a device's bus/class name, if at all possible
 * @dev: struct device to get the bus/class name of
 *
 * Will return the name of the bus/class the device is attached to.  If it is
 * not attached to a bus/class, an empty string will be returned.
 */
static inline const char *dev_bus_name(const struct device *dev)
{
	return dev->bus ? dev->bus->name : (dev->class ? dev->class->name : "");
}

__printf(2, 3) int dev_set_name(struct device *dev, const char *name, ...);

#ifdef CONFIG_NUMA