Skip to content

Commit 35e4a69

Browse files
committed
PM: sleep: Allow pm_restrict_gfp_mask() stacking
Allow pm_restrict_gfp_mask() to be called many times in a row to avoid issues with calling dpm_suspend_start() when the GFP mask has been already restricted. Only the first invocation of pm_restrict_gfp_mask() will actually restrict the GFP mask and the subsequent calls will warn if there is a mismatch between the expected allowed GFP mask and the actual one. Moreover, if pm_restrict_gfp_mask() is called many times in a row, pm_restore_gfp_mask() needs to be called matching number of times in a row to actually restore the GFP mask. Calling it when the GFP mask has not been restricted will cause it to warn. This is necessary for the GFP mask restriction starting in hibernation_snapshot() to continue throughout the entire hibernation flow until it completes or it is aborted (either by a wakeup event or by an error). Fixes: 449c9c0 ("PM: hibernate: Restrict GFP mask in hibernation_snapshot()") Fixes: 469d80a ("PM: hibernate: Fix hybrid-sleep") Reported-by: Askar Safin <safinaskar@gmail.com> Closes: https://lore.kernel.org/linux-pm/20251025050812.421905-1-safinaskar@gmail.com/ Link: https://lore.kernel.org/linux-pm/20251028111730.2261404-1-safinaskar@gmail.com/ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> Tested-by: Mario Limonciello (AMD) <superm1@kernel.org> Cc: 6.16+ <stable@vger.kernel.org> # 6.16+ Link: https://patch.msgid.link/5935682.DvuYhMxLoT@rafael.j.wysocki
1 parent 79816d4 commit 35e4a69

File tree

2 files changed

+17
-9
lines changed

2 files changed

+17
-9
lines changed

kernel/power/hibernate.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,6 @@ static void power_down(void)
706706

707707
#ifdef CONFIG_SUSPEND
708708
if (hibernation_mode == HIBERNATION_SUSPEND) {
709-
pm_restore_gfp_mask();
710709
error = suspend_devices_and_enter(mem_sleep_current);
711710
if (!error)
712711
goto exit;
@@ -746,9 +745,6 @@ static void power_down(void)
746745
cpu_relax();
747746

748747
exit:
749-
/* Match the pm_restore_gfp_mask() call in hibernate(). */
750-
pm_restrict_gfp_mask();
751-
752748
/* Restore swap signature. */
753749
error = swsusp_unmark();
754750
if (error)

kernel/power/main.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,35 @@
3131
* held, unless the suspend/hibernate code is guaranteed not to run in parallel
3232
* with that modification).
3333
*/
34+
static unsigned int saved_gfp_count;
3435
static gfp_t saved_gfp_mask;
3536

3637
void pm_restore_gfp_mask(void)
3738
{
3839
WARN_ON(!mutex_is_locked(&system_transition_mutex));
39-
if (saved_gfp_mask) {
40-
gfp_allowed_mask = saved_gfp_mask;
41-
saved_gfp_mask = 0;
42-
}
40+
41+
if (WARN_ON(!saved_gfp_count) || --saved_gfp_count)
42+
return;
43+
44+
gfp_allowed_mask = saved_gfp_mask;
45+
saved_gfp_mask = 0;
46+
47+
pm_pr_dbg("GFP mask restored\n");
4348
}
4449

4550
void pm_restrict_gfp_mask(void)
4651
{
4752
WARN_ON(!mutex_is_locked(&system_transition_mutex));
48-
WARN_ON(saved_gfp_mask);
53+
54+
if (saved_gfp_count++) {
55+
WARN_ON((saved_gfp_mask & ~(__GFP_IO | __GFP_FS)) != gfp_allowed_mask);
56+
return;
57+
}
58+
4959
saved_gfp_mask = gfp_allowed_mask;
5060
gfp_allowed_mask &= ~(__GFP_IO | __GFP_FS);
61+
62+
pm_pr_dbg("GFP mask restricted\n");
5163
}
5264

5365
unsigned int lock_system_sleep(void)

0 commit comments

Comments
 (0)