Skip to content

Commit 21c27f0

Browse files
Saravana Kannangregkh
authored andcommitted
driver core: Fix SYNC_STATE_ONLY device link implementation
When SYNC_STATE_ONLY support was added in commit 05ef983 ("driver core: Add device link support for SYNC_STATE_ONLY flag"), device_link_add() incorrectly skipped adding the new SYNC_STATE_ONLY device link to the supplier's and consumer's "device link" list. This causes multiple issues: - The device link is lost forever from driver core if the caller didn't keep track of it (caller typically isn't expected to). This is a memory leak. - The device link is also never visible to any other code path after device_link_add() returns. If we fix the "device link" list handling, that exposes a bunch of issues. 1. The device link "status" state management code rightfully doesn't handle the case where a DL_FLAG_MANAGED device link exists between a supplier and consumer, but the consumer manages to probe successfully before the supplier. The addition of DL_FLAG_SYNC_STATE_ONLY links break this assumption. This causes device_links_driver_bound() to throw a warning when this happens. Since DL_FLAG_SYNC_STATE_ONLY device links are mainly used for creating proxy device links for child device dependencies and aren't useful once the consumer device probes successfully, this patch just deletes DL_FLAG_SYNC_STATE_ONLY device links once its consumer device probes. This way, we avoid the warning, free up some memory and avoid complicating the device links "status" state management code. 2. Creating a DL_FLAG_STATELESS device link between two devices that already have a DL_FLAG_SYNC_STATE_ONLY device link will result in the DL_FLAG_STATELESS flag not getting set correctly. This patch also fixes this. Lastly, this patch also fixes minor whitespace issues. Cc: [email protected] Fixes: 05ef983 ("driver core: Add device link support for SYNC_STATE_ONLY flag") Signed-off-by: Saravana Kannan <[email protected]> Reviewed-by: Rafael J. Wysocki <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 2ef96a5 commit 21c27f0

File tree

1 file changed

+39
-22
lines changed

1 file changed

+39
-22
lines changed

drivers/base/core.c

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -360,13 +360,12 @@ struct device_link *device_link_add(struct device *consumer,
360360

361361
if (flags & DL_FLAG_STATELESS) {
362362
kref_get(&link->kref);
363+
link->flags |= DL_FLAG_STATELESS;
363364
if (link->flags & DL_FLAG_SYNC_STATE_ONLY &&
364-
!(link->flags & DL_FLAG_STATELESS)) {
365-
link->flags |= DL_FLAG_STATELESS;
365+
!(link->flags & DL_FLAG_STATELESS))
366366
goto reorder;
367-
} else {
367+
else
368368
goto out;
369-
}
370369
}
371370

372371
/*
@@ -433,12 +432,16 @@ struct device_link *device_link_add(struct device *consumer,
433432
flags & DL_FLAG_PM_RUNTIME)
434433
pm_runtime_resume(supplier);
435434

435+
list_add_tail_rcu(&link->s_node, &supplier->links.consumers);
436+
list_add_tail_rcu(&link->c_node, &consumer->links.suppliers);
437+
436438
if (flags & DL_FLAG_SYNC_STATE_ONLY) {
437439
dev_dbg(consumer,
438440
"Linked as a sync state only consumer to %s\n",
439441
dev_name(supplier));
440442
goto out;
441443
}
444+
442445
reorder:
443446
/*
444447
* Move the consumer and all of the devices depending on it to the end
@@ -449,12 +452,9 @@ struct device_link *device_link_add(struct device *consumer,
449452
*/
450453
device_reorder_to_tail(consumer, NULL);
451454

452-
list_add_tail_rcu(&link->s_node, &supplier->links.consumers);
453-
list_add_tail_rcu(&link->c_node, &consumer->links.suppliers);
454-
455455
dev_dbg(consumer, "Linked as a consumer to %s\n", dev_name(supplier));
456456

457-
out:
457+
out:
458458
device_pm_unlock();
459459
device_links_write_unlock();
460460

@@ -829,6 +829,13 @@ static void __device_links_supplier_defer_sync(struct device *sup)
829829
list_add_tail(&sup->links.defer_sync, &deferred_sync);
830830
}
831831

832+
static void device_link_drop_managed(struct device_link *link)
833+
{
834+
link->flags &= ~DL_FLAG_MANAGED;
835+
WRITE_ONCE(link->status, DL_STATE_NONE);
836+
kref_put(&link->kref, __device_link_del);
837+
}
838+
832839
/**
833840
* device_links_driver_bound - Update device links after probing its driver.
834841
* @dev: Device to update the links for.
@@ -842,7 +849,7 @@ static void __device_links_supplier_defer_sync(struct device *sup)
842849
*/
843850
void device_links_driver_bound(struct device *dev)
844851
{
845-
struct device_link *link;
852+
struct device_link *link, *ln;
846853
LIST_HEAD(sync_list);
847854

848855
/*
@@ -882,18 +889,35 @@ void device_links_driver_bound(struct device *dev)
882889
else
883890
__device_links_queue_sync_state(dev, &sync_list);
884891

885-
list_for_each_entry(link, &dev->links.suppliers, c_node) {
892+
list_for_each_entry_safe(link, ln, &dev->links.suppliers, c_node) {
893+
struct device *supplier;
894+
886895
if (!(link->flags & DL_FLAG_MANAGED))
887896
continue;
888897

889-
WARN_ON(link->status != DL_STATE_CONSUMER_PROBE);
890-
WRITE_ONCE(link->status, DL_STATE_ACTIVE);
898+
supplier = link->supplier;
899+
if (link->flags & DL_FLAG_SYNC_STATE_ONLY) {
900+
/*
901+
* When DL_FLAG_SYNC_STATE_ONLY is set, it means no
902+
* other DL_MANAGED_LINK_FLAGS have been set. So, it's
903+
* save to drop the managed link completely.
904+
*/
905+
device_link_drop_managed(link);
906+
} else {
907+
WARN_ON(link->status != DL_STATE_CONSUMER_PROBE);
908+
WRITE_ONCE(link->status, DL_STATE_ACTIVE);
909+
}
891910

911+
/*
912+
* This needs to be done even for the deleted
913+
* DL_FLAG_SYNC_STATE_ONLY device link in case it was the last
914+
* device link that was preventing the supplier from getting a
915+
* sync_state() call.
916+
*/
892917
if (defer_sync_state_count)
893-
__device_links_supplier_defer_sync(link->supplier);
918+
__device_links_supplier_defer_sync(supplier);
894919
else
895-
__device_links_queue_sync_state(link->supplier,
896-
&sync_list);
920+
__device_links_queue_sync_state(supplier, &sync_list);
897921
}
898922

899923
dev->links.status = DL_DEV_DRIVER_BOUND;
@@ -903,13 +927,6 @@ void device_links_driver_bound(struct device *dev)
903927
device_links_flush_sync_list(&sync_list, dev);
904928
}
905929

906-
static void device_link_drop_managed(struct device_link *link)
907-
{
908-
link->flags &= ~DL_FLAG_MANAGED;
909-
WRITE_ONCE(link->status, DL_STATE_NONE);
910-
kref_put(&link->kref, __device_link_del);
911-
}
912-
913930
/**
914931
* __device_links_no_driver - Update links of a device without a driver.
915932
* @dev: Device without a drvier.

0 commit comments

Comments
 (0)