driver core: Do not resume suppliers under device_links_write_lock()
[ Upstream commit 5db25c9eb893df8f6b93c1d97b8006d768e1b6f5 ] It is incorrect to call pm_runtime_get_sync() under device_links_write_lock(), because it may end up trying to take device_links_read_lock() while resuming the target device and that will deadlock in the non-SRCU case, so avoid that by resuming the supplier device in device_link_add() before calling device_links_write_lock(). Fixes: 21d5c57b3726 ("PM / runtime: Use device links") Fixes: baa8809f6097 ("PM / runtime: Optimize the use of device links") Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
d7a7f04e10
commit
d7ee5bfb55
@ -180,11 +180,20 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
struct device *supplier, u32 flags)
|
||||
{
|
||||
struct device_link *link;
|
||||
bool rpm_put_supplier = false;
|
||||
|
||||
if (!consumer || !supplier ||
|
||||
((flags & DL_FLAG_STATELESS) && (flags & DL_FLAG_AUTOREMOVE)))
|
||||
return NULL;
|
||||
|
||||
if (flags & DL_FLAG_PM_RUNTIME && flags & DL_FLAG_RPM_ACTIVE) {
|
||||
if (pm_runtime_get_sync(supplier) < 0) {
|
||||
pm_runtime_put_noidle(supplier);
|
||||
return NULL;
|
||||
}
|
||||
rpm_put_supplier = true;
|
||||
}
|
||||
|
||||
device_links_write_lock();
|
||||
device_pm_lock();
|
||||
|
||||
@ -209,13 +218,8 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
|
||||
if (flags & DL_FLAG_PM_RUNTIME) {
|
||||
if (flags & DL_FLAG_RPM_ACTIVE) {
|
||||
if (pm_runtime_get_sync(supplier) < 0) {
|
||||
pm_runtime_put_noidle(supplier);
|
||||
kfree(link);
|
||||
link = NULL;
|
||||
goto out;
|
||||
}
|
||||
link->rpm_active = true;
|
||||
rpm_put_supplier = false;
|
||||
}
|
||||
pm_runtime_new_link(consumer);
|
||||
/*
|
||||
@ -286,6 +290,10 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
out:
|
||||
device_pm_unlock();
|
||||
device_links_write_unlock();
|
||||
|
||||
if (rpm_put_supplier)
|
||||
pm_runtime_put(supplier);
|
||||
|
||||
return link;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_link_add);
|
||||
|
Loading…
x
Reference in New Issue
Block a user