linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1] PM: Support aborting suspend during filesystem sync
@ 2025-08-12 23:21 Samuel Wu
  2025-08-13  5:53 ` Greg Kroah-Hartman
  2025-08-13 19:21 ` kernel test robot
  0 siblings, 2 replies; 4+ messages in thread
From: Samuel Wu @ 2025-08-12 23:21 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
	Danilo Krummrich, Viresh Kumar, Ingo Molnar, Peter Zijlstra,
	Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
	Ben Segall, Mel Gorman, Valentin Schneider, Lukasz Luba
  Cc: Samuel Wu, Saravana Kannan, kernel-team, Rafael J. Wysocki,
	linux-pm, linux-kernel

At the start of suspend, filesystems will sync to save the current state
of the device. However, the long tail of the filesystem sync can take
upwards of 25 seconds. If during this filesystem sync there is some
wakeup or abort signal, it will not be processed until the sync is
complete; from a user's perspective, this looks like the device is
unresponsive to any form of input.

This patch adds functionality to handle a suspend abort signal when in
the filesystem sync phase of suspend. This topic was first discussed by
Saravana Kannan at LPC 2024 [1], where the general consensus was to
allow filesystem sync on a parallel thread.

[1]: https://lpc.events/event/18/contributions/1845/

Suggested-by: Saravana Kannan <saravanak@google.com>
Signed-off-by: Samuel Wu <wusamuel@google.com>
---
 drivers/base/power/wakeup.c |  8 ++++
 include/linux/suspend.h     |  3 ++
 kernel/power/process.c      |  1 -
 kernel/power/suspend.c      | 80 ++++++++++++++++++++++++++++++++++++-
 4 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index d1283ff1080b..304368c3a55f 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -570,6 +570,13 @@ static void wakeup_source_activate(struct wakeup_source *ws)
 
 	/* Increment the counter of events in progress. */
 	cec = atomic_inc_return(&combined_event_count);
+	/*
+	 * To maintain the same behavior as pm_wakeup_pending(),
+	 * aborting suspend will only happen if events_check_enabled. Similarly,
+	 * the abort during fs_sync needs the same check.
+	 */
+	if (events_check_enabled)
+		suspend_abort_fs_sync();
 
 	trace_wakeup_source_activate(ws->name, cec);
 }
@@ -899,6 +906,7 @@ EXPORT_SYMBOL_GPL(pm_wakeup_pending);
 void pm_system_wakeup(void)
 {
 	atomic_inc(&pm_abort_suspend);
+	suspend_abort_fs_sync();
 	s2idle_wake();
 }
 EXPORT_SYMBOL_GPL(pm_system_wakeup);
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 317ae31e89b3..21b1ea275c79 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -276,6 +276,8 @@ extern void arch_suspend_enable_irqs(void);
 
 extern int pm_suspend(suspend_state_t state);
 extern bool sync_on_suspend_enabled;
+
+extern void suspend_abort_fs_sync(void);
 #else /* !CONFIG_SUSPEND */
 #define suspend_valid_only_mem	NULL
 
@@ -296,6 +298,7 @@ static inline bool idle_should_enter_s2idle(void) { return false; }
 static inline void __init pm_states_init(void) {}
 static inline void s2idle_set_ops(const struct platform_s2idle_ops *ops) {}
 static inline void s2idle_wake(void) {}
+static inline void suspend_abort_fs_sync(void) {}
 #endif /* !CONFIG_SUSPEND */
 
 static inline bool pm_suspend_in_progress(void)
diff --git a/kernel/power/process.c b/kernel/power/process.c
index dc0dfc349f22..8ff68ebaa1e0 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -132,7 +132,6 @@ int freeze_processes(void)
 	if (!pm_freezing)
 		static_branch_inc(&freezer_active);
 
-	pm_wakeup_clear(0);
 	pm_freezing = true;
 	error = try_to_freeze_tasks(true);
 	if (!error)
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index b4ca17c2fecf..3bdb8aca00cc 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -31,6 +31,7 @@
 #include <linux/compiler.h>
 #include <linux/moduleparam.h>
 #include <linux/fs.h>
+#include <linux/workqueue.h>
 
 #include "power.h"
 
@@ -74,6 +75,16 @@ bool pm_suspend_default_s2idle(void)
 }
 EXPORT_SYMBOL_GPL(pm_suspend_default_s2idle);
 
+static bool suspend_fs_sync_queued;
+DEFINE_SPINLOCK(suspend_fs_sync_lock);
+DECLARE_COMPLETION(suspend_fs_sync_complete);
+void suspend_abort_fs_sync(void)
+{
+	spin_lock(&suspend_fs_sync_lock);
+	complete(&suspend_fs_sync_complete);
+	spin_unlock(&suspend_fs_sync_lock);
+}
+
 void s2idle_set_ops(const struct platform_s2idle_ops *ops)
 {
 	unsigned int sleep_flags;
@@ -403,6 +414,71 @@ void __weak arch_suspend_enable_irqs(void)
 	local_irq_enable();
 }
 
+static void sync_filesystems_fn(struct work_struct *work)
+{
+	ksys_sync_helper();
+
+	spin_lock(&suspend_fs_sync_lock);
+	suspend_fs_sync_queued = false;
+	complete(&suspend_fs_sync_complete);
+	spin_unlock(&suspend_fs_sync_lock);
+}
+static DECLARE_WORK(sync_filesystems, sync_filesystems_fn);
+
+/**
+ * suspend_fs_sync_with_abort- Start filesystem sync and handle potential aborts
+ *
+ * Starts filesystem sync in a workqueue, while the main thread uses a
+ * completion to wait for either the filesystem sync to finish or for a wakeup
+ * event. In the case of filesystem sync finishing and triggering the
+ * completion, the suspend path continues as normal. If the complete is due to a
+ * wakeup or abort signal, the code jumps to the suspend abort path while the
+ * filesystem sync finishes in the background.
+ *
+ * An aborted suspend that is followed by another suspend is a potential
+ * scenario that complicates the sequence. This patch handles this by
+ * serializing any filesystem sync; a subsequent suspend's filesystem sync
+ * operation will only start when the previous suspend's filesystem sync has
+ * finished. Even while waiting for the previous suspend's filesystem sync to
+ * finish, the subsequent suspend will still break early if a wakeup completion
+ * is triggered, solving the original issue of filesystem sync blocking abort.
+ */
+static int suspend_fs_sync_with_abort(void)
+{
+	bool need_suspend_fs_sync_requeue;
+
+	pm_wakeup_clear(0);
+Start_fs_sync:
+	spin_lock(&suspend_fs_sync_lock);
+	reinit_completion(&suspend_fs_sync_complete);
+	/*
+	 * Handle the case where a suspend immediately follows a previous
+	 * suspend that was aborted during fs_sync. In this case, serialize
+	 * fs_sync by only starting fs_sync of the subsequent suspend when the
+	 * fs_sync of the previous suspend has finished.
+	 */
+	if (suspend_fs_sync_queued) {
+		need_suspend_fs_sync_requeue = true;
+	} else {
+		need_suspend_fs_sync_requeue = false;
+		suspend_fs_sync_queued = true;
+		schedule_work(&sync_filesystems);
+	}
+	spin_unlock(&suspend_fs_sync_lock);
+
+	/*
+	 * Completion is triggered by fs_sync finishing or a suspend abort
+	 * signal, whichever comes first
+	 */
+	wait_for_completion(&suspend_fs_sync_complete);
+	if (pm_wakeup_pending())
+		return -EBUSY;
+	if (need_suspend_fs_sync_requeue)
+		goto Start_fs_sync;
+
+	return 0;
+}
+
 /**
  * suspend_enter - Make the system enter the given sleep state.
  * @state: System sleep state to enter.
@@ -590,8 +666,10 @@ static int enter_state(suspend_state_t state)
 
 	if (sync_on_suspend_enabled) {
 		trace_suspend_resume(TPS("sync_filesystems"), 0, true);
-		ksys_sync_helper();
+		error = suspend_fs_sync_with_abort();
 		trace_suspend_resume(TPS("sync_filesystems"), 0, false);
+		if (error)
+			goto Unlock;
 	}
 
 	pm_pr_dbg("Preparing system for sleep (%s)\n", mem_sleep_labels[state]);
-- 
2.51.0.rc0.215.g125493bb4a-goog


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v1] PM: Support aborting suspend during filesystem sync
  2025-08-12 23:21 [PATCH v1] PM: Support aborting suspend during filesystem sync Samuel Wu
@ 2025-08-13  5:53 ` Greg Kroah-Hartman
  2025-08-15  0:49   ` Samuel Wu
  2025-08-13 19:21 ` kernel test robot
  1 sibling, 1 reply; 4+ messages in thread
From: Greg Kroah-Hartman @ 2025-08-13  5:53 UTC (permalink / raw)
  To: Samuel Wu
  Cc: Rafael J. Wysocki, Len Brown, Pavel Machek, Danilo Krummrich,
	Viresh Kumar, Ingo Molnar, Peter Zijlstra, Juri Lelli,
	Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
	Mel Gorman, Valentin Schneider, Lukasz Luba, Saravana Kannan,
	kernel-team, Rafael J. Wysocki, linux-pm, linux-kernel

On Tue, Aug 12, 2025 at 04:21:23PM -0700, Samuel Wu wrote:
> +static bool suspend_fs_sync_queued;
> +DEFINE_SPINLOCK(suspend_fs_sync_lock);
> +DECLARE_COMPLETION(suspend_fs_sync_complete);
> +void suspend_abort_fs_sync(void)
> +{
> +	spin_lock(&suspend_fs_sync_lock);
> +	complete(&suspend_fs_sync_complete);
> +	spin_unlock(&suspend_fs_sync_lock);
> +}

Why no documentation for this public function that you added, but yet
you added documentation for a static function that no one can call?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v1] PM: Support aborting suspend during filesystem sync
  2025-08-12 23:21 [PATCH v1] PM: Support aborting suspend during filesystem sync Samuel Wu
  2025-08-13  5:53 ` Greg Kroah-Hartman
@ 2025-08-13 19:21 ` kernel test robot
  1 sibling, 0 replies; 4+ messages in thread
From: kernel test robot @ 2025-08-13 19:21 UTC (permalink / raw)
  To: Samuel Wu, Rafael J. Wysocki, Len Brown, Pavel Machek,
	Greg Kroah-Hartman, Danilo Krummrich, Viresh Kumar, Ingo Molnar,
	Peter Zijlstra, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
	Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
	Lukasz Luba
  Cc: oe-kbuild-all, Samuel Wu, Saravana Kannan, kernel-team, linux-pm,
	linux-kernel

Hi Samuel,

kernel test robot noticed the following build warnings:

[auto build test WARNING on rafael-pm/linux-next]
[also build test WARNING on rafael-pm/bleeding-edge linus/master v6.17-rc1 next-20250813]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Samuel-Wu/PM-Support-aborting-suspend-during-filesystem-sync/20250813-072435
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
patch link:    https://lore.kernel.org/r/20250812232126.1814253-1-wusamuel%40google.com
patch subject: [PATCH v1] PM: Support aborting suspend during filesystem sync
config: arm64-randconfig-r132-20250813 (https://download.01.org/0day-ci/archive/20250814/202508140303.9c38ncEh-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 12.5.0
reproduce: (https://download.01.org/0day-ci/archive/20250814/202508140303.9c38ncEh-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202508140303.9c38ncEh-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> kernel/power/suspend.c:79:1: sparse: sparse: symbol 'suspend_fs_sync_lock' was not declared. Should it be static?
>> kernel/power/suspend.c:80:1: sparse: sparse: symbol 'suspend_fs_sync_complete' was not declared. Should it be static?
   kernel/power/suspend.c:104:54: sparse: sparse: incorrect type in argument 2 (different base types) @@     expected int val @@     got restricted suspend_state_t [usertype] @@
   kernel/power/suspend.c:104:54: sparse:     expected int val
   kernel/power/suspend.c:104:54: sparse:     got restricted suspend_state_t [usertype]
   kernel/power/suspend.c:141:54: sparse: sparse: incorrect type in argument 2 (different base types) @@     expected int val @@     got restricted suspend_state_t [usertype] @@
   kernel/power/suspend.c:141:54: sparse:     expected int val
   kernel/power/suspend.c:141:54: sparse:     got restricted suspend_state_t [usertype]
   kernel/power/suspend.c:202:19: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:202:47: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:203:19: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:203:51: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:208:26: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:208:65: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:215:42: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:215:51: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:216:38: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:217:51: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:215:72: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:240:34: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:240:73: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:241:27: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:241:59: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:246:34: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:246:69: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:247:21: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:247:42: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:537:33: sparse: sparse: incorrect type in argument 2 (different base types) @@     expected int val @@     got restricted suspend_state_t [usertype] state @@
   kernel/power/suspend.c:537:33: sparse:     expected int val
   kernel/power/suspend.c:537:33: sparse:     got restricted suspend_state_t [usertype] state
   kernel/power/suspend.c:540:33: sparse: sparse: incorrect type in argument 2 (different base types) @@     expected int val @@     got restricted suspend_state_t [usertype] state @@
   kernel/power/suspend.c:540:33: sparse:     expected int val
   kernel/power/suspend.c:540:33: sparse:     got restricted suspend_state_t [usertype] state
   kernel/power/suspend.c:610:57: sparse: sparse: incorrect type in argument 2 (different base types) @@     expected int val @@     got restricted suspend_state_t [usertype] state @@
   kernel/power/suspend.c:610:57: sparse:     expected int val
   kernel/power/suspend.c:610:57: sparse:     got restricted suspend_state_t [usertype] state
   kernel/power/suspend.c:612:57: sparse: sparse: incorrect type in argument 2 (different base types) @@     expected int val @@     got restricted suspend_state_t [usertype] state @@
   kernel/power/suspend.c:612:57: sparse:     expected int val
   kernel/power/suspend.c:612:57: sparse:     got restricted suspend_state_t [usertype] state
   kernel/power/suspend.c:650:52: sparse: sparse: incorrect type in argument 2 (different base types) @@     expected int val @@     got restricted suspend_state_t [usertype] state @@
   kernel/power/suspend.c:650:52: sparse:     expected int val
   kernel/power/suspend.c:650:52: sparse:     got restricted suspend_state_t [usertype] state
   kernel/power/suspend.c:675:9: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:675:9: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:684:52: sparse: sparse: incorrect type in argument 2 (different base types) @@     expected int val @@     got restricted suspend_state_t [usertype] state @@
   kernel/power/suspend.c:684:52: sparse:     expected int val
   kernel/power/suspend.c:684:52: sparse:     got restricted suspend_state_t [usertype] state
   kernel/power/suspend.c:685:9: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:685:9: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:708:13: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:708:22: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:708:39: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:708:48: sparse: sparse: restricted suspend_state_t degrades to integer
   kernel/power/suspend.c:711:9: sparse: sparse: restricted suspend_state_t degrades to integer

vim +/suspend_fs_sync_lock +79 kernel/power/suspend.c

    77	
    78	static bool suspend_fs_sync_queued;
  > 79	DEFINE_SPINLOCK(suspend_fs_sync_lock);
  > 80	DECLARE_COMPLETION(suspend_fs_sync_complete);
    81	void suspend_abort_fs_sync(void)
    82	{
    83		spin_lock(&suspend_fs_sync_lock);
    84		complete(&suspend_fs_sync_complete);
    85		spin_unlock(&suspend_fs_sync_lock);
    86	}
    87	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v1] PM: Support aborting suspend during filesystem sync
  2025-08-13  5:53 ` Greg Kroah-Hartman
@ 2025-08-15  0:49   ` Samuel Wu
  0 siblings, 0 replies; 4+ messages in thread
From: Samuel Wu @ 2025-08-15  0:49 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Rafael J. Wysocki, Len Brown, Pavel Machek, Danilo Krummrich,
	Viresh Kumar, Ingo Molnar, Peter Zijlstra, Juri Lelli,
	Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
	Mel Gorman, Valentin Schneider, Lukasz Luba, Saravana Kannan,
	kernel-team, Rafael J. Wysocki, linux-pm, linux-kernel

On Tue, Aug 12, 2025 at 10:53 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> On Tue, Aug 12, 2025 at 04:21:23PM -0700, Samuel Wu wrote:
> > +static bool suspend_fs_sync_queued;
> > +DEFINE_SPINLOCK(suspend_fs_sync_lock);
> > +DECLARE_COMPLETION(suspend_fs_sync_complete);
> > +void suspend_abort_fs_sync(void)
> > +{
> > +     spin_lock(&suspend_fs_sync_lock);
> > +     complete(&suspend_fs_sync_complete);
> > +     spin_unlock(&suspend_fs_sync_lock);
> > +}
>
> Why no documentation for this public function that you added, but yet
> you added documentation for a static function that no one can call?
>
> thanks,
>
> greg k-h

Thanks for catching this; updated in V2 of patch.

-- Samuel Wu

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-08-15  0:49 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-12 23:21 [PATCH v1] PM: Support aborting suspend during filesystem sync Samuel Wu
2025-08-13  5:53 ` Greg Kroah-Hartman
2025-08-15  0:49   ` Samuel Wu
2025-08-13 19:21 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).