Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 449c9c02537a1 ("PM: hibernate: Restrict GFP mask in hibernation_snapshot()")
Fixes: 469d80a3712c ("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

+17 -9
-4
kernel/power/hibernate.c
··· 706 706 707 707 #ifdef CONFIG_SUSPEND 708 708 if (hibernation_mode == HIBERNATION_SUSPEND) { 709 - pm_restore_gfp_mask(); 710 709 error = suspend_devices_and_enter(mem_sleep_current); 711 710 if (!error) 712 711 goto exit; ··· 745 746 cpu_relax(); 746 747 747 748 exit: 748 - /* Match the pm_restore_gfp_mask() call in hibernate(). */ 749 - pm_restrict_gfp_mask(); 750 - 751 749 /* Restore swap signature. */ 752 750 error = swsusp_unmark(); 753 751 if (error)
+17 -5
kernel/power/main.c
··· 31 31 * held, unless the suspend/hibernate code is guaranteed not to run in parallel 32 32 * with that modification). 33 33 */ 34 + static unsigned int saved_gfp_count; 34 35 static gfp_t saved_gfp_mask; 35 36 36 37 void pm_restore_gfp_mask(void) 37 38 { 38 39 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"); 43 48 } 44 49 45 50 void pm_restrict_gfp_mask(void) 46 51 { 47 52 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 + 49 59 saved_gfp_mask = gfp_allowed_mask; 50 60 gfp_allowed_mask &= ~(__GFP_IO | __GFP_FS); 61 + 62 + pm_pr_dbg("GFP mask restricted\n"); 51 63 } 52 64 53 65 unsigned int lock_system_sleep(void)