summaryrefslogtreecommitdiffstats
path: root/kernel/power/main.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2009-05-24 21:15:07 +0200
committerRafael J. Wysocki <rjw@sisk.pl>2009-05-24 21:15:07 +0200
commit32bdfac5462d777f35b00838893c4f87baf23efe (patch)
tree92e4ef3af7b68007e8004eaca978865a29e543b0 /kernel/power/main.c
parent59a3759d0fe8d969888c741bb33f4946e4d3750d (diff)
downloadop-kernel-dev-32bdfac5462d777f35b00838893c4f87baf23efe.zip
op-kernel-dev-32bdfac5462d777f35b00838893c4f87baf23efe.tar.gz
PM: Do not hold dpm_list_mtx while disabling/enabling nonboot CPUs
We shouldn't hold dpm_list_mtx while executing [disable|enable]_nonboot_cpus(), because theoretically this may lead to a deadlock as shown by the following example (provided by Johannes Berg): CPU 3 CPU 2 CPU 1 suspend/hibernate something: rtnl_lock() device_pm_lock() -> mutex_lock(&dpm_list_mtx) mutex_lock(&dpm_list_mtx) linkwatch_work -> rtnl_lock() disable_nonboot_cpus() -> flush CPU 3 workqueue Fortunately, device drivers are supposed to stop any activities that might lead to the registration of new device objects way before disable_nonboot_cpus() is called, so it shouldn't be necessary to hold dpm_list_mtx over the entire late part of device suspend and early part of device resume. Thus, during the late suspend and the early resume of devices acquire dpm_list_mtx only when dpm_list is going to be traversed and release it right after that. This patch is reported to fix the regressions tracked as http://bugzilla.kernel.org/show_bug.cgi?id=13245. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Miles Lane <miles.lane@gmail.com> Tested-by: Ming Lei <tom.leiming@gmail.com>
Diffstat (limited to 'kernel/power/main.c')
-rw-r--r--kernel/power/main.c7
1 files changed, 1 insertions, 6 deletions
diff --git a/kernel/power/main.c b/kernel/power/main.c
index f99ed6a..8680282 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -289,12 +289,10 @@ static int suspend_enter(suspend_state_t state)
{
int error;
- device_pm_lock();
-
if (suspend_ops->prepare) {
error = suspend_ops->prepare();
if (error)
- goto Done;
+ return error;
}
error = device_power_down(PMSG_SUSPEND);
@@ -343,9 +341,6 @@ static int suspend_enter(suspend_state_t state)
if (suspend_ops->finish)
suspend_ops->finish();
- Done:
- device_pm_unlock();
-
return error;
}
OpenPOWER on IntegriCloud