History

PM: suspend: Add sysfs attribute to control the "sync on suspend" behavior

The sysfs attribute `/sys/power/sync_on_suspend` controls, whether or not filesystems are synced by the kernel before system suspend. Congruously, the behaviour of build-time switch CONFIG_SUSPEND_SKIP_SYNC is slightly changed: It now defines the run-tim default for the new sysfs attribute `/sys/power/sync_on_suspend`. The run-time attribute is added because the existing corresponding build-time Kconfig flag for (`CONFIG_SUSPEND_SKIP_SYNC`) is not flexible enough. E.g. Linux distributions that provide pre-compiled kernels usually want to stick with the default (sync filesystems before suspend) but under special conditions this needs to be changed. One example for such a special condition is user-space handling of suspending block devices (e.g. using `cryptsetup luksSuspend` or `dmsetup suspend`) before system suspend. The Kernel trying to sync filesystems after the underlying block device already got suspended obviously leads to dead-locks. Be aware that you have to take care of the filesystem sync yourself before suspending the system in those scenarios.

Jonas Meurer committed 6 years ago

Commit c052bf81 parent 5c0e9de5 files · +53 −2Browse files

Unified · Split

5 files
  1. Documentation/ABI/testing/sysfs-power +13 −0
  2. include/linux/suspend.h +2 −0
  3. kernel/power/Kconfig +4 −1
  4. kernel/power/main.c +33 −0
  5. kernel/power/suspend.c +1 −1
Documentation/ABI/testing/sysfs-power+13−0
@@ -407,3 +407,16 @@ Contact: Kalesh Singh <kaleshsingh96@gmail.com> · 406 unmodified lines
407Description:407Description:
408 The /sys/power/suspend_stats/last_failed_step file contains408 The /sys/power/suspend_stats/last_failed_step file contains
409 the last failed step in the suspend/resume path.409 the last failed step in the suspend/resume path.
410
411What: /sys/power/sync_on_suspend
412Date: October 2019
413Contact: Jonas Meurer <jonas@freesources.org>
414Description:
415 This file controls whether or not the kernel will sync()
416 filesystems during system suspend (after freezing user space
417 and before suspending devices).
418
419 Writing a "1" to this file enables the sync() and writing a "0"
420 disables it. Reads from the file return the current value.
421 The default is "1" if the build-time "SUSPEND_SKIP_SYNC" config
422 flag is unset, or "0" otherwise.
include/linux/suspend.h+2−0
@@ -329,6 +329,7 @@ extern void arch_suspend_disable_irqs(void); · 328 unmodified lines
329extern void arch_suspend_enable_irqs(void);329extern void arch_suspend_enable_irqs(void);
330 330
331extern int pm_suspend(suspend_state_t state);331extern int pm_suspend(suspend_state_t state);
332extern bool sync_on_suspend_enabled;
332#else /* !CONFIG_SUSPEND */333#else /* !CONFIG_SUSPEND */
333#define suspend_valid_only_mem NULL334#define suspend_valid_only_mem NULL
334 335
@@ -342,6 +343,7 @@ static inline bool pm_suspend_default_s2idle(void) { return false; } · 7 unmodified lines
342 343
343static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {}344static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {}
344static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }345static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }
346static inline bool sync_on_suspend_enabled(void) { return true; }
345static inline bool idle_should_enter_s2idle(void) { return false; }347static inline bool idle_should_enter_s2idle(void) { return false; }
346static inline void __init pm_states_init(void) {}348static inline void __init pm_states_init(void) {}
347static inline void s2idle_set_ops(const struct platform_s2idle_ops *ops) {}349static inline void s2idle_set_ops(const struct platform_s2idle_ops *ops) {}
kernel/power/Kconfig+4−1
@@ -27,7 +27,10 @@ config SUSPEND_SKIP_SYNC · 26 unmodified lines
27 Skip the kernel sys_sync() before freezing user processes.27 Skip the kernel sys_sync() before freezing user processes.
28 Some systems prefer not to pay this cost on every invocation28 Some systems prefer not to pay this cost on every invocation
29 of suspend, or they are content with invoking sync() from29 of suspend, or they are content with invoking sync() from
30 user-space before invoking suspend. Say Y if that's your case.30 user-space before invoking suspend. There's a run-time switch
31 at '/sys/power/sync_on_suspend' to configure this behaviour.
32 This setting changes the default for the run-tim switch. Say Y
33 to change the default to disable the kernel sys_sync().
31 34
32config HIBERNATE_CALLBACKS35config HIBERNATE_CALLBACKS
33 bool36 bool
kernel/power/main.c+33−0
@@ -190,6 +190,38 @@ static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr · 189 unmodified lines
190}190}
191 191
192power_attr(mem_sleep);192power_attr(mem_sleep);
193
194/*
195 * sync_on_suspend: invoke ksys_sync_helper() before suspend.
196 *
197 * show() returns whether ksys_sync_helper() is invoked before suspend.
198 * store() accepts 0 or 1. 0 disables ksys_sync_helper() and 1 enables it.
199 */
200bool sync_on_suspend_enabled = !IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC);
201
202static ssize_t sync_on_suspend_show(struct kobject *kobj,
203 struct kobj_attribute *attr, char *buf)
204{
205 return sprintf(buf, "%d\n", sync_on_suspend_enabled);
206}
207
208static ssize_t sync_on_suspend_store(struct kobject *kobj,
209 struct kobj_attribute *attr,
210 const char *buf, size_t n)
211{
212 unsigned long val;
213
214 if (kstrtoul(buf, 10, &val))
215 return -EINVAL;
216
217 if (val > 1)
218 return -EINVAL;
219
220 sync_on_suspend_enabled = !!val;
221 return n;
222}
223
224power_attr(sync_on_suspend);
193#endif /* CONFIG_SUSPEND */225#endif /* CONFIG_SUSPEND */
194 226
195#ifdef CONFIG_PM_SLEEP_DEBUG227#ifdef CONFIG_PM_SLEEP_DEBUG
@@ -855,6 +887,7 @@ static struct attribute * g[] = { · 659 unmodified lines
855 &wakeup_count_attr.attr,887 &wakeup_count_attr.attr,
856#ifdef CONFIG_SUSPEND888#ifdef CONFIG_SUSPEND
857 &mem_sleep_attr.attr,889 &mem_sleep_attr.attr,
890 &sync_on_suspend_attr.attr,
858#endif891#endif
859#ifdef CONFIG_PM_AUTOSLEEP892#ifdef CONFIG_PM_AUTOSLEEP
860 &autosleep_attr.attr,893 &autosleep_attr.attr,
kernel/power/suspend.c+1−1
@@ -564,7 +564,7 @@ static int enter_state(suspend_state_t state) · 563 unmodified lines
564 if (state == PM_SUSPEND_TO_IDLE)564 if (state == PM_SUSPEND_TO_IDLE)
565 s2idle_begin();565 s2idle_begin();
566 566
567 if (!IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC)) {567 if (sync_on_suspend_enabled) {
568 trace_suspend_resume(TPS("sync_filesystems"), 0, true);568 trace_suspend_resume(TPS("sync_filesystems"), 0, true);
569 ksys_sync_helper();569 ksys_sync_helper();
570 trace_suspend_resume(TPS("sync_filesystems"), 0, false);570 trace_suspend_resume(TPS("sync_filesystems"), 0, false);