Skip to content

Commit 55f2503

Browse files
liupingfanrafaeljw
authored andcommitted
PM / reboot: Eliminate race between reboot and suspend
At present, "systemctl suspend" and "shutdown" can run in parrallel. A system can suspend after devices_shutdown(), and resume. Then the shutdown task goes on to power off. This causes many devices are not really shut off. Hence replacing reboot_mutex with system_transition_mutex (renamed from pm_mutex) to achieve the exclusion. The renaming of pm_mutex as system_transition_mutex can be better to reflect the purpose of the mutex. Signed-off-by: Pingfan Liu <[email protected]> Acked-by: Pavel Machek <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 82837ad commit 55f2503

File tree

10 files changed

+40
-36
lines changed

10 files changed

+40
-36
lines changed

Documentation/power/freezing-of-tasks.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -204,26 +204,26 @@ VI. Are there any precautions to be taken to prevent freezing failures?
204204

205205
Yes, there are.
206206

207-
First of all, grabbing the 'pm_mutex' lock to mutually exclude a piece of code
207+
First of all, grabbing the 'system_transition_mutex' lock to mutually exclude a piece of code
208208
from system-wide sleep such as suspend/hibernation is not encouraged.
209209
If possible, that piece of code must instead hook onto the suspend/hibernation
210210
notifiers to achieve mutual exclusion. Look at the CPU-Hotplug code
211211
(kernel/cpu.c) for an example.
212212

213-
However, if that is not feasible, and grabbing 'pm_mutex' is deemed necessary,
214-
it is strongly discouraged to directly call mutex_[un]lock(&pm_mutex) since
213+
However, if that is not feasible, and grabbing 'system_transition_mutex' is deemed necessary,
214+
it is strongly discouraged to directly call mutex_[un]lock(&system_transition_mutex) since
215215
that could lead to freezing failures, because if the suspend/hibernate code
216-
successfully acquired the 'pm_mutex' lock, and hence that other entity failed
216+
successfully acquired the 'system_transition_mutex' lock, and hence that other entity failed
217217
to acquire the lock, then that task would get blocked in TASK_UNINTERRUPTIBLE
218218
state. As a consequence, the freezer would not be able to freeze that task,
219219
leading to freezing failure.
220220

221221
However, the [un]lock_system_sleep() APIs are safe to use in this scenario,
222222
since they ask the freezer to skip freezing this task, since it is anyway
223-
"frozen enough" as it is blocked on 'pm_mutex', which will be released
223+
"frozen enough" as it is blocked on 'system_transition_mutex', which will be released
224224
only after the entire suspend/hibernation sequence is complete.
225225
So, to summarize, use [un]lock_system_sleep() instead of directly using
226-
mutex_[un]lock(&pm_mutex). That would prevent freezing failures.
226+
mutex_[un]lock(&system_transition_mutex). That would prevent freezing failures.
227227

228228
V. Miscellaneous
229229
/sys/power/pm_freeze_timeout controls how long it will cost at most to freeze

Documentation/power/suspend-and-cpuhotplug.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ More details follow:
3232
sysfs file
3333
|
3434
v
35-
Acquire pm_mutex lock
35+
Acquire system_transition_mutex lock
3636
|
3737
v
3838
Send PM_SUSPEND_PREPARE
@@ -96,10 +96,10 @@ execution during resume):
9696

9797
* thaw tasks
9898
* send PM_POST_SUSPEND notifications
99-
* Release pm_mutex lock.
99+
* Release system_transition_mutex lock.
100100

101101

102-
It is to be noted here that the pm_mutex lock is acquired at the very
102+
It is to be noted here that the system_transition_mutex lock is acquired at the very
103103
beginning, when we are just starting out to suspend, and then released only
104104
after the entire cycle is complete (i.e., suspend + resume).
105105

include/linux/suspend.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ static inline bool hibernation_available(void) { return false; }
414414
#define PM_RESTORE_PREPARE 0x0005 /* Going to restore a saved image */
415415
#define PM_POST_RESTORE 0x0006 /* Restore failed */
416416

417-
extern struct mutex pm_mutex;
417+
extern struct mutex system_transition_mutex;
418418

419419
#ifdef CONFIG_PM_SLEEP
420420
void save_processor_state(void);

kernel/freezer.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
atomic_t system_freezing_cnt = ATOMIC_INIT(0);
1616
EXPORT_SYMBOL(system_freezing_cnt);
1717

18-
/* indicate whether PM freezing is in effect, protected by pm_mutex */
18+
/* indicate whether PM freezing is in effect, protected by
19+
* system_transition_mutex
20+
*/
1921
bool pm_freezing;
2022
bool pm_nosig_freezing;
2123

kernel/power/hibernate.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ static int create_image(int platform_mode)
338338
* hibernation_snapshot - Quiesce devices and create a hibernation image.
339339
* @platform_mode: If set, use platform driver to prepare for the transition.
340340
*
341-
* This routine must be called with pm_mutex held.
341+
* This routine must be called with system_transition_mutex held.
342342
*/
343343
int hibernation_snapshot(int platform_mode)
344344
{
@@ -500,8 +500,9 @@ static int resume_target_kernel(bool platform_mode)
500500
* hibernation_restore - Quiesce devices and restore from a hibernation image.
501501
* @platform_mode: If set, use platform driver to prepare for the transition.
502502
*
503-
* This routine must be called with pm_mutex held. If it is successful, control
504-
* reappears in the restored target kernel in hibernation_snapshot().
503+
* This routine must be called with system_transition_mutex held. If it is
504+
* successful, control reappears in the restored target kernel in
505+
* hibernation_snapshot().
505506
*/
506507
int hibernation_restore(int platform_mode)
507508
{
@@ -806,13 +807,13 @@ static int software_resume(void)
806807
* name_to_dev_t() below takes a sysfs buffer mutex when sysfs
807808
* is configured into the kernel. Since the regular hibernate
808809
* trigger path is via sysfs which takes a buffer mutex before
809-
* calling hibernate functions (which take pm_mutex) this can
810-
* cause lockdep to complain about a possible ABBA deadlock
810+
* calling hibernate functions (which take system_transition_mutex)
811+
* this can cause lockdep to complain about a possible ABBA deadlock
811812
* which cannot happen since we're in the boot code here and
812813
* sysfs can't be invoked yet. Therefore, we use a subclass
813814
* here to avoid lockdep complaining.
814815
*/
815-
mutex_lock_nested(&pm_mutex, SINGLE_DEPTH_NESTING);
816+
mutex_lock_nested(&system_transition_mutex, SINGLE_DEPTH_NESTING);
816817

817818
if (swsusp_resume_device)
818819
goto Check_image;
@@ -900,7 +901,7 @@ static int software_resume(void)
900901
atomic_inc(&snapshot_device_available);
901902
/* For success case, the suspend path will release the lock */
902903
Unlock:
903-
mutex_unlock(&pm_mutex);
904+
mutex_unlock(&system_transition_mutex);
904905
pm_pr_dbg("Hibernation image not present or could not be loaded.\n");
905906
return error;
906907
Close_Finish:

kernel/power/main.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,16 @@
1515
#include <linux/workqueue.h>
1616
#include <linux/debugfs.h>
1717
#include <linux/seq_file.h>
18+
#include <linux/suspend.h>
1819

1920
#include "power.h"
2021

21-
DEFINE_MUTEX(pm_mutex);
22-
2322
#ifdef CONFIG_PM_SLEEP
2423

2524
void lock_system_sleep(void)
2625
{
2726
current->flags |= PF_FREEZER_SKIP;
28-
mutex_lock(&pm_mutex);
27+
mutex_lock(&system_transition_mutex);
2928
}
3029
EXPORT_SYMBOL_GPL(lock_system_sleep);
3130

@@ -37,8 +36,9 @@ void unlock_system_sleep(void)
3736
*
3837
* Reason:
3938
* Fundamentally, we just don't need it, because freezing condition
40-
* doesn't come into effect until we release the pm_mutex lock,
41-
* since the freezer always works with pm_mutex held.
39+
* doesn't come into effect until we release the
40+
* system_transition_mutex lock, since the freezer always works with
41+
* system_transition_mutex held.
4242
*
4343
* More importantly, in the case of hibernation,
4444
* unlock_system_sleep() gets called in snapshot_read() and
@@ -47,7 +47,7 @@ void unlock_system_sleep(void)
4747
* enter the refrigerator, thus causing hibernation to lockup.
4848
*/
4949
current->flags &= ~PF_FREEZER_SKIP;
50-
mutex_unlock(&pm_mutex);
50+
mutex_unlock(&system_transition_mutex);
5151
}
5252
EXPORT_SYMBOL_GPL(unlock_system_sleep);
5353

kernel/power/suspend.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ static int enter_state(suspend_state_t state)
556556
} else if (!valid_state(state)) {
557557
return -EINVAL;
558558
}
559-
if (!mutex_trylock(&pm_mutex))
559+
if (!mutex_trylock(&system_transition_mutex))
560560
return -EBUSY;
561561

562562
if (state == PM_SUSPEND_TO_IDLE)
@@ -590,7 +590,7 @@ static int enter_state(suspend_state_t state)
590590
pm_pr_dbg("Finishing wakeup.\n");
591591
suspend_finish();
592592
Unlock:
593-
mutex_unlock(&pm_mutex);
593+
mutex_unlock(&system_transition_mutex);
594594
return error;
595595
}
596596

kernel/power/user.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
216216
if (!capable(CAP_SYS_ADMIN))
217217
return -EPERM;
218218

219-
if (!mutex_trylock(&pm_mutex))
219+
if (!mutex_trylock(&system_transition_mutex))
220220
return -EBUSY;
221221

222222
lock_device_hotplug();
@@ -394,7 +394,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
394394
}
395395

396396
unlock_device_hotplug();
397-
mutex_unlock(&pm_mutex);
397+
mutex_unlock(&system_transition_mutex);
398398

399399
return error;
400400
}

kernel/reboot.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ void kernel_power_off(void)
294294
}
295295
EXPORT_SYMBOL_GPL(kernel_power_off);
296296

297-
static DEFINE_MUTEX(reboot_mutex);
297+
DEFINE_MUTEX(system_transition_mutex);
298298

299299
/*
300300
* Reboot system call: for obvious reasons only root may call it,
@@ -338,7 +338,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
338338
if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
339339
cmd = LINUX_REBOOT_CMD_HALT;
340340

341-
mutex_lock(&reboot_mutex);
341+
mutex_lock(&system_transition_mutex);
342342
switch (cmd) {
343343
case LINUX_REBOOT_CMD_RESTART:
344344
kernel_restart(NULL);
@@ -389,7 +389,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
389389
ret = -EINVAL;
390390
break;
391391
}
392-
mutex_unlock(&reboot_mutex);
392+
mutex_unlock(&system_transition_mutex);
393393
return ret;
394394
}
395395

mm/page_alloc.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,17 @@ static inline void set_pcppage_migratetype(struct page *page, int migratetype)
155155
* The following functions are used by the suspend/hibernate code to temporarily
156156
* change gfp_allowed_mask in order to avoid using I/O during memory allocations
157157
* while devices are suspended. To avoid races with the suspend/hibernate code,
158-
* they should always be called with pm_mutex held (gfp_allowed_mask also should
159-
* only be modified with pm_mutex held, unless the suspend/hibernate code is
160-
* guaranteed not to run in parallel with that modification).
158+
* they should always be called with system_transition_mutex held
159+
* (gfp_allowed_mask also should only be modified with system_transition_mutex
160+
* held, unless the suspend/hibernate code is guaranteed not to run in parallel
161+
* with that modification).
161162
*/
162163

163164
static gfp_t saved_gfp_mask;
164165

165166
void pm_restore_gfp_mask(void)
166167
{
167-
WARN_ON(!mutex_is_locked(&pm_mutex));
168+
WARN_ON(!mutex_is_locked(&system_transition_mutex));
168169
if (saved_gfp_mask) {
169170
gfp_allowed_mask = saved_gfp_mask;
170171
saved_gfp_mask = 0;
@@ -173,7 +174,7 @@ void pm_restore_gfp_mask(void)
173174

174175
void pm_restrict_gfp_mask(void)
175176
{
176-
WARN_ON(!mutex_is_locked(&pm_mutex));
177+
WARN_ON(!mutex_is_locked(&system_transition_mutex));
177178
WARN_ON(saved_gfp_mask);
178179
saved_gfp_mask = gfp_allowed_mask;
179180
gfp_allowed_mask &= ~(__GFP_IO | __GFP_FS);

0 commit comments

Comments
 (0)