@@ -75,7 +75,9 @@ driver is compiled as a module, the device link is added on module load and
orderly deleted on unload. The same restrictions that apply to device link
addition (e.g. exclusion of a parallel suspend/resume transition) apply equally
to deletion. Device links managed by the driver core are deleted automatically
-by it.
+by it, except if the consumer device is never registered (e.g. because of an
+error), in which case the device links must be explicitly removed using
+:c:func:`device_links_scrap()`.
Several flags may be specified on device link addition, two of which
have already been mentioned above: ``DL_FLAG_STATELESS`` to express that no
@@ -317,4 +319,5 @@ State machine
API
===
-See device_link_add(), device_link_del() and device_link_remove().
+See device_link_add(), device_link_del(), device_link_remove() and
+device_links_scrap().
@@ -562,7 +562,8 @@ static void devlink_remove_symlinks(struct device *dev,
struct device *con = link->consumer;
char *buf;
- sysfs_remove_link(&link->link_dev.kobj, "consumer");
+ if (device_is_registered(con))
+ sysfs_remove_link(&link->link_dev.kobj, "consumer");
sysfs_remove_link(&link->link_dev.kobj, "supplier");
len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)),
@@ -575,8 +576,10 @@ static void devlink_remove_symlinks(struct device *dev,
return;
}
- snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup));
- sysfs_remove_link(&con->kobj, buf);
+ if (device_is_registered(con)) {
+ snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup));
+ sysfs_remove_link(&con->kobj, buf);
+ }
snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
sysfs_remove_link(&sup->kobj, buf);
kfree(buf);
@@ -1538,6 +1541,19 @@ static void device_links_purge(struct device *dev)
device_links_write_unlock();
}
+/**
+ * device_links_scrap - Device was never registered, delete any device links.
+ * @dev: Target device.
+ */
+void device_links_scrap(struct device *dev)
+{
+ if (WARN_ON(device_is_registered(dev)))
+ return;
+
+ device_links_purge(dev);
+}
+EXPORT_SYMBOL_GPL(device_links_scrap);
+
#define FW_DEVLINK_FLAGS_PERMISSIVE (DL_FLAG_INFERRED | \
DL_FLAG_SYNC_STATE_ONLY)
#define FW_DEVLINK_FLAGS_ON (DL_FLAG_INFERRED | \
@@ -967,6 +967,7 @@ struct device_link *device_link_add(struct device *consumer,
struct device *supplier, u32 flags);
void device_link_del(struct device_link *link);
void device_link_remove(void *consumer, struct device *supplier);
+void device_links_scrap(struct device *dev);
void device_links_supplier_sync_state_pause(void);
void device_links_supplier_sync_state_resume(void);
Managed device links are deleted by device_del(). However it is possible to add a device link to a consumer before device_add(), and then discover an error prevents the device from being used. In that case normally references to the device would be dropped and the device would be deleted. However the device link holds a reference to the device, so the device link and device remain indefinitely. Add a function to delete device links of an unregistered device, so that drivers can get rid of unregistered devices and their device links. To do that, the devlink_remove_symlinks() function must be amended to cope with the absence of the consumer's sysfs presence, otherwise sysfs_remove_link() will generate warnings. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> --- Documentation/driver-api/device_link.rst | 7 +++++-- drivers/base/core.c | 22 +++++++++++++++++++--- include/linux/device.h | 1 + 3 files changed, 25 insertions(+), 5 deletions(-)