Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5db25c9e authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Greg Kroah-Hartman
Browse files

driver core: Do not resume suppliers under device_links_write_lock()



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: 21d5c57b ("PM / runtime: Use device links")
Fixes: baa8809f ("PM / runtime: Optimize the use of device links")
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f265df55
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -201,12 +201,21 @@ 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_CONSUMER | DL_FLAG_AUTOREMOVE_SUPPLIER)))
		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();

@@ -250,13 +259,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);
		/*
@@ -328,6 +332,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);