Commit 6b57b15a authored by Saravana Kannan's avatar Saravana Kannan Committed by Greg Kroah-Hartman

driver core: Fix device_pm_lock() locking for device links

This commit fixes two issues:

1. The lockdep warning reported by Dong Aisheng <dongas86@gmail.com> [1].

It is a warning about a cycle (dpm_list_mtx --> kn->active#3 --> fw_lock)
that was introduced when device-link devices were added to expose device
link information in sysfs.

The patch that "introduced" this cycle can't be reverted because it's fixes
a real SRCU issue and also ensures that the device-link device is deleted
as soon as the device-link is deleted. This is important to avoid sysfs
name collisions if the device-link is create again immediately (this can
happen a lot with deferred probing).

2. Inconsistency in grabbing device_pm_lock() during device link deletion

Some device link deletion code paths grab device_pm_lock(), while others
don't.  The device_pm_lock() is grabbed during device_link_add() because it
checks if the supplier is in the dpm_list and also reorders the dpm_list.
However, when a device link is deleted, it does not do either of those and
therefore device_pm_lock() is not necessary. Dropping the device_pm_lock()
in all the device link deletion paths removes the inconsistency in locking.

Thanks to Stephen Boyd for helping me understand the lockdep splat.

Fixes: 843e600b ("driver core: Fix sleeping in invalid context during device link deletion")
[1] - https://lore.kernel.org/lkml/CAA+hA=S4eAreb7vo69LAXSk2t5=DEKNxHaiY1wSpk4xTp9urLg@mail.gmail.com/Reported-by: default avatarDong Aisheng <dongas86@gmail.com>
Signed-off-by: default avatarSaravana Kannan <saravanak@google.com>
Tested-by: default avatarPeng Fan <peng.fan@nxp.com>
Link: https://lore.kernel.org/r/20200901184445.1736658-1-saravanak@google.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 51de18bf
...@@ -807,9 +807,7 @@ static void device_link_put_kref(struct device_link *link) ...@@ -807,9 +807,7 @@ static void device_link_put_kref(struct device_link *link)
void device_link_del(struct device_link *link) void device_link_del(struct device_link *link)
{ {
device_links_write_lock(); device_links_write_lock();
device_pm_lock();
device_link_put_kref(link); device_link_put_kref(link);
device_pm_unlock();
device_links_write_unlock(); device_links_write_unlock();
} }
EXPORT_SYMBOL_GPL(device_link_del); EXPORT_SYMBOL_GPL(device_link_del);
...@@ -830,7 +828,6 @@ void device_link_remove(void *consumer, struct device *supplier) ...@@ -830,7 +828,6 @@ void device_link_remove(void *consumer, struct device *supplier)
return; return;
device_links_write_lock(); device_links_write_lock();
device_pm_lock();
list_for_each_entry(link, &supplier->links.consumers, s_node) { list_for_each_entry(link, &supplier->links.consumers, s_node) {
if (link->consumer == consumer) { if (link->consumer == consumer) {
...@@ -839,7 +836,6 @@ void device_link_remove(void *consumer, struct device *supplier) ...@@ -839,7 +836,6 @@ void device_link_remove(void *consumer, struct device *supplier)
} }
} }
device_pm_unlock();
device_links_write_unlock(); device_links_write_unlock();
} }
EXPORT_SYMBOL_GPL(device_link_remove); EXPORT_SYMBOL_GPL(device_link_remove);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment