lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20251229065251.3315787-1-tuhaowen@uniontech.com>
Date: Mon, 29 Dec 2025 14:52:51 +0800
From: tuhaowen <tuhaowen@...ontech.com>
To: rafael@...nel.org
Cc: pavel@...nel.org,
	lenb@...nel.org,
	linux-pm@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	tuhaowen@...ontech.com
Subject: [PATCH v1] PM: sleep: Add configurable timeout and mode control for filesystem sync

When users trigger system suspend on desktop systems, filesystem sync
can take 10-25 seconds or even longer if there are slow/faulty storage
devices (e.g., a failing hard drive or disconnected USB drive). During
this time, the screen goes black and the system appears completely
frozen with no visual feedback. Users cannot distinguish whether the
system is "syncing filesystems" or has "crashed/hung", leading them
to perform a hard reset, potentially causing data loss.

While the existing wakeup event mechanism allows aborting sync via key
presses (designed for mobile devices), desktop/laptop users often don't
realize they can press keys during the black screen. Instead, they tend
to force power off by holding the power button, assuming the system has
hung. This is especially problematic with faulty storage devices that
cause indefinite sync hangs.

This patch adds a timeout mechanism to automatically abort filesystem
sync after a configurable duration, preventing indefinite hangs without
requiring user intervention:

1. /sys/power/fs_sync_mode (0 or 1, default: 0)
   - Mode 0: Check wakeup events, allow user to abort sync
   - Mode 1: Only use timeout, ignore wakeup events

2. /sys/power/fs_sync_timeout (0-300 seconds, default: 0)
   - Set maximum wait time for filesystem sync

The fix adds timeout mechanism to pm_sleep_fs_sync(). When timeout
expires or user presses a key (mode 0), the sync is aborted and
suspend proceeds, preventing indefinite hangs. The default behavior
(mode 0, timeout 0) maintains backward compatibility.

Link: https://lore.kernel.org/all/CAJZ5v0g_HXQjWfp=L0KetRCHMTD=QsP3wJKNZnadJic2yccCUQ@mail.gmail.com/

Signed-off-by: tuhaowen <tuhaowen@...ontech.com>
---
 kernel/power/main.c | 94 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 91 insertions(+), 3 deletions(-)

diff --git a/kernel/power/main.c b/kernel/power/main.c
index 03b2c5495c77..bb7dd73e18fc 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -102,6 +102,12 @@ static atomic_t pm_fs_sync_count = ATOMIC_INIT(0);
 static struct workqueue_struct *pm_fs_sync_wq;
 static DECLARE_WAIT_QUEUE_HEAD(pm_fs_sync_wait);
 
+/* Timeout for file system sync during suspend/hibernate (in seconds) */
+static unsigned int fs_sync_timeout_secs;
+
+/* File system sync mode: 0 = interrupt mode, 1 = timeout mode */
+static unsigned int fs_sync_mode;
+
 static bool pm_fs_sync_completed(void)
 {
 	return atomic_read(&pm_fs_sync_count) == 0;
@@ -119,11 +125,15 @@ static DECLARE_WORK(pm_fs_sync_work, pm_fs_sync_work_fn);
 /**
  * pm_sleep_fs_sync() - Sync file systems in an interruptible way
  *
- * Return: 0 on successful file system sync, or -EBUSY if the file system sync
- * was aborted.
+ * Return: 0 on successful file system sync,
+ *         -EBUSY if the file system sync was aborted by wakeup event,
+ *         -ETIME if the file system sync timed out.
  */
 int pm_sleep_fs_sync(void)
 {
+	unsigned long timeout_jiffies = 0;
+	unsigned long start_time;
+
 	pm_wakeup_clear(0);
 
 	/*
@@ -137,16 +147,90 @@ int pm_sleep_fs_sync(void)
 		queue_work(pm_fs_sync_wq, &pm_fs_sync_work);
 	}
 
+	/* Setup timeout only in timeout mode (mode 1) */
+	if (fs_sync_mode && fs_sync_timeout_secs > 0) {
+		timeout_jiffies = msecs_to_jiffies(fs_sync_timeout_secs * 1000);
+		start_time = jiffies;
+	}
+
 	while (!pm_fs_sync_completed()) {
-		if (pm_wakeup_pending())
+		if (!fs_sync_mode && pm_wakeup_pending())
 			return -EBUSY;
 
+		if (fs_sync_mode && timeout_jiffies > 0 &&
+		    time_after(jiffies, start_time + timeout_jiffies)) {
+			pr_warn("PM: File system sync timed out after %u seconds, proceeding with suspend\n",
+				fs_sync_timeout_secs);
+			return -ETIME;
+		}
+
 		wait_event_timeout(pm_fs_sync_wait, pm_fs_sync_completed(),
 				   PM_FS_SYNC_WAKEUP_RESOLUTION);
 	}
 
 	return 0;
 }
+
+/*
+ * fs_sync_timeout: Control file system sync timeout during suspend/hibernate.
+ *
+ * show() returns the timeout value in seconds.
+ * store() accepts a value in seconds. 0 means no timeout (only interrupted by wakeup events).
+ * Non-zero values will cause the sync to be interrupted after the specified time.
+ */
+static ssize_t fs_sync_timeout_show(struct kobject *kobj,
+				    struct kobj_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "%u\n", fs_sync_timeout_secs);
+}
+
+static ssize_t fs_sync_timeout_store(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	/* Allow values from 0 to 300 seconds (5 minutes) */
+	if (val > 300)
+		return -EINVAL;
+
+	fs_sync_timeout_secs = val;
+	return n;
+}
+
+power_attr(fs_sync_timeout);
+
+/*
+ * fs_sync_mode: Control file system sync behavior mode
+ *
+ * 0 = interrupt mode (default): check wakeup events during sync, can abort suspend/hibernate
+ * 1 = timeout mode: ignore wakeup events during sync, only use timeout
+ */
+static ssize_t fs_sync_mode_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "%u\n", fs_sync_mode);
+}
+
+static ssize_t fs_sync_mode_store(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	if (val > 1)
+		return -EINVAL;
+
+	fs_sync_mode = val;
+	return n;
+}
+power_attr(fs_sync_mode);
 #endif /* CONFIG_SUSPEND || CONFIG_HIBERNATION */
 
 /* Routines for PM-transition notifications */
@@ -1085,6 +1169,10 @@ static struct attribute * g[] = {
 	&mem_sleep_attr.attr,
 	&sync_on_suspend_attr.attr,
 #endif
+#if defined(CONFIG_SUSPEND) || defined(CONFIG_HIBERNATION)
+	&fs_sync_timeout_attr.attr,
+	&fs_sync_mode_attr.attr,
+#endif
 #ifdef CONFIG_PM_AUTOSLEEP
 	&autosleep_attr.attr,
 #endif
-- 
2.20.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ