PM: runtime: Fix race getting/putting suppliers at probe
Subsystems (5)
cover PM: runtime: Fix race getting/putting suppliers at probe
Hi
SCSI UFS is starting to use device links for power management but has run into issues. Here are 2 patches that seem to help.
Adrian Hunter (2):
PM: runtime: Fix ordering in pm_runtime_get_suppliers()
PM: runtime: Fix race getting/putting suppliers at probe
drivers/base/power/runtime.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
Regards
Adrian
PATCH 1/2 PM: runtime: Fix ordering in pm_runtime_get_suppliers()
rpm_active indicates how many times the supplier usage_count has been incremented. Consequently it must be updated after pm_runtime_get_sync() of the supplier, not before.
--- drivers/base/power/runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/base/power/runtime.c +1 -1
@@ -1690,8 +1690,8 @@ void pm_runtime_get_suppliers(struct device *dev) device_links_read_lock_held())if (link->flags &DL_FLAG_PM_RUNTIME ) { link->supplier_preactivated = true; -refcount_inc (&link->rpm_active);pm_runtime_get_sync (link->supplier); +refcount_inc (&link->rpm_active); }device_links_read_unlock (idx);
Signature · 1 line
2.17.1
PATCH 2/2 PM: runtime: Fix race getting/putting suppliers at probe
In reply to Adrian Hunterpm_runtime_put_suppliers() must not decrement rpm_active unless the consumer is suspended. That is because, otherwise, it could suspend suppliers for an active consumer.
That can happen as follows:
static int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
if (!device_is_registered(dev))
return -ENODEV;
dev->can_match = true;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
pm_runtime_get_suppliers(dev);
if (dev->parent)
pm_runtime_get_sync(dev->parent); At this point, dev can runtime suspend so rpm_put_suppliers() can run, rpm_active becomes 1 (the lowest value).
pm_runtime_barrier(dev); if (initcall_debug) ret = really_probe_debug(dev, drv); else ret = really_probe(dev, drv);
Probe callback can have runtime resumed dev, and then runtime put so dev is awaiting autosuspend, but rpm_active is 2.
pm_request_idle(dev); if (dev->parent) pm_runtime_put(dev->parent); pm_runtime_put_suppliers(dev);
Now pm_runtime_put_suppliers() will put the supplier i.e. rpm_active 2 -> 1, but consumer can still be active.
return ret;
}
Fix by checking the runtime status. For any status other than RPM_SUSPENDED, rpm_active can be considered to be "owned" by rpm_[get/put]_suppliers() and pm_runtime_put_suppliers() need do nothing.
--- drivers/base/power/runtime.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/base/power/runtime.c +7 -1
@@ -1704,6 +1704,8 @@ void pm_runtime_get_suppliers(struct device *dev)void pm_runtime_put_suppliers (struct device *dev) {struct device_link *link; +unsigned long flags; +bool put;int idx; idx =device_links_read_lock ();
@@ -1712,7 +1714,11 @@ void pm_runtime_put_suppliers(struct device *dev) device_links_read_lock_held())if (link->supplier_preactivated) { link->supplier_preactivated = false; -if (refcount_dec_not_one (&link->rpm_active)) +spin_lock_irqsave (&dev->power.lock, flags); + put =pm_runtime_status_suspended (dev) && +refcount_dec_not_one (&link->rpm_active); +spin_unlock_irqrestore (&dev->power.lock, flags); +if (put)pm_runtime_put (link->supplier); }
Signature · 1 line
2.17.1
Rafael J. Wysocki
maintainerQuoted 10 lines · Adrian Hunter
Hi
SCSI UFS is starting to use device links for power management but has run into issues. Here are 2 patches that seem to help.
Adrian Hunter (2):
PM: runtime: Fix ordering inpm_runtime_get_suppliers()
PM: runtime: Fix race getting/putting suppliers at probe
Both look good to me, so queuing them up for the next 5.12-rc, thanks!