Skip to content

Commit eacfbf7

Browse files
committed
power: freeze filesystems during suspend/resume
Now all the pieces are in place to actually allow the power subsystem to freeze/thaw filesystems during suspend/resume. Filesystems are only frozen and thawed if the power subsystem does actually own the freeze. We could bubble up errors and fail suspend/resume if the error isn't EBUSY (aka it's already frozen) but I don't think that this is worth it. Filesystem freezing during suspend/resume is best-effort. If the user has 500 ext4 filesystems mounted and 4 fail to freeze for whatever reason then we simply skip them. What we have now is already a big improvement and let's see how we fare with it before making our lives even harder (and uglier) than we have to. We add a new sysctl know /sys/power/freeze_filesystems that will allow userspace to freeze filesystems during suspend/hibernate. For now it defaults to off. The thaw logic doesn't require checking whether freezing is enabled because the power subsystem exclusively owns frozen filesystems for the duration of suspend/hibernate and is able to skip filesystems it doesn't need to freeze. Also it is technically possible that filesystem filesystem_freeze_enabled is true and power freezes the filesystems but before freezing all processes another process disables filesystem_freeze_enabled. If power were to place the filesystems_thaw() call under filesystems_freeze_enabled it would fail to thaw the fileystems it frozw. The exclusive holder mechanism makes it possible to iterate through the list without any concern making sure that no filesystems are left frozen. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 0de4c40 commit eacfbf7

File tree

4 files changed

+57
-1
lines changed

4 files changed

+57
-1
lines changed

kernel/power/hibernate.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,8 @@ int hibernate(void)
778778
goto Restore;
779779

780780
ksys_sync_helper();
781+
if (filesystem_freeze_enabled)
782+
filesystems_freeze();
781783

782784
error = freeze_processes();
783785
if (error)
@@ -846,6 +848,7 @@ int hibernate(void)
846848
/* Don't bother checking whether freezer_test_done is true */
847849
freezer_test_done = false;
848850
Exit:
851+
filesystems_thaw();
849852
pm_notifier_call_chain(PM_POST_HIBERNATION);
850853
Restore:
851854
pm_restore_console();
@@ -882,6 +885,9 @@ int hibernate_quiet_exec(int (*func)(void *data), void *data)
882885
if (error)
883886
goto restore;
884887

888+
if (filesystem_freeze_enabled)
889+
filesystems_freeze();
890+
885891
error = freeze_processes();
886892
if (error)
887893
goto exit;
@@ -941,6 +947,7 @@ int hibernate_quiet_exec(int (*func)(void *data), void *data)
941947
thaw_processes();
942948

943949
exit:
950+
filesystems_thaw();
944951
pm_notifier_call_chain(PM_POST_HIBERNATION);
945952

946953
restore:
@@ -1029,19 +1036,26 @@ static int software_resume(void)
10291036
if (error)
10301037
goto Restore;
10311038

1039+
if (filesystem_freeze_enabled)
1040+
filesystems_freeze();
1041+
10321042
pm_pr_dbg("Preparing processes for hibernation restore.\n");
10331043
error = freeze_processes();
1034-
if (error)
1044+
if (error) {
1045+
filesystems_thaw();
10351046
goto Close_Finish;
1047+
}
10361048

10371049
error = freeze_kernel_threads();
10381050
if (error) {
10391051
thaw_processes();
1052+
filesystems_thaw();
10401053
goto Close_Finish;
10411054
}
10421055

10431056
error = load_image_and_restore();
10441057
thaw_processes();
1058+
filesystems_thaw();
10451059
Finish:
10461060
pm_notifier_call_chain(PM_POST_RESTORE);
10471061
Restore:

kernel/power/main.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,34 @@ power_attr(pm_freeze_timeout);
962962

963963
#endif /* CONFIG_FREEZER*/
964964

965+
#if defined(CONFIG_SUSPEND) || defined(CONFIG_HIBERNATION)
966+
bool filesystem_freeze_enabled = false;
967+
968+
static ssize_t freeze_filesystems_show(struct kobject *kobj,
969+
struct kobj_attribute *attr, char *buf)
970+
{
971+
return sysfs_emit(buf, "%d\n", filesystem_freeze_enabled);
972+
}
973+
974+
static ssize_t freeze_filesystems_store(struct kobject *kobj,
975+
struct kobj_attribute *attr,
976+
const char *buf, size_t n)
977+
{
978+
unsigned long val;
979+
980+
if (kstrtoul(buf, 10, &val))
981+
return -EINVAL;
982+
983+
if (val > 1)
984+
return -EINVAL;
985+
986+
filesystem_freeze_enabled = !!val;
987+
return n;
988+
}
989+
990+
power_attr(freeze_filesystems);
991+
#endif /* CONFIG_SUSPEND || CONFIG_HIBERNATION */
992+
965993
static struct attribute * g[] = {
966994
&state_attr.attr,
967995
#ifdef CONFIG_PM_TRACE
@@ -991,6 +1019,9 @@ static struct attribute * g[] = {
9911019
#endif
9921020
#ifdef CONFIG_FREEZER
9931021
&pm_freeze_timeout_attr.attr,
1022+
#endif
1023+
#if defined(CONFIG_SUSPEND) || defined(CONFIG_HIBERNATION)
1024+
&freeze_filesystems_attr.attr,
9941025
#endif
9951026
NULL,
9961027
};

kernel/power/power.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ struct swsusp_info {
1818
unsigned long size;
1919
} __aligned(PAGE_SIZE);
2020

21+
#if defined(CONFIG_SUSPEND) || defined(CONFIG_HIBERNATION)
22+
extern bool filesystem_freeze_enabled;
23+
#endif
24+
2125
#ifdef CONFIG_HIBERNATION
2226
/* kernel/power/snapshot.c */
2327
extern void __init hibernate_reserved_size_init(void);

kernel/power/suspend.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <trace/events/power.h>
3131
#include <linux/compiler.h>
3232
#include <linux/moduleparam.h>
33+
#include <linux/fs.h>
3334

3435
#include "power.h"
3536

@@ -374,6 +375,8 @@ static int suspend_prepare(suspend_state_t state)
374375
if (error)
375376
goto Restore;
376377

378+
if (filesystem_freeze_enabled)
379+
filesystems_freeze();
377380
trace_suspend_resume(TPS("freeze_processes"), 0, true);
378381
error = suspend_freeze_processes();
379382
trace_suspend_resume(TPS("freeze_processes"), 0, false);
@@ -550,6 +553,7 @@ int suspend_devices_and_enter(suspend_state_t state)
550553
static void suspend_finish(void)
551554
{
552555
suspend_thaw_processes();
556+
filesystems_thaw();
553557
pm_notifier_call_chain(PM_POST_SUSPEND);
554558
pm_restore_console();
555559
}
@@ -588,6 +592,8 @@ static int enter_state(suspend_state_t state)
588592
ksys_sync_helper();
589593
trace_suspend_resume(TPS("sync_filesystems"), 0, false);
590594
}
595+
if (filesystem_freeze_enabled)
596+
filesystems_freeze();
591597

592598
pm_pr_dbg("Preparing system for sleep (%s)\n", mem_sleep_labels[state]);
593599
pm_suspend_clear_flags();
@@ -609,6 +615,7 @@ static int enter_state(suspend_state_t state)
609615
pm_pr_dbg("Finishing wakeup.\n");
610616
suspend_finish();
611617
Unlock:
618+
filesystems_thaw();
612619
mutex_unlock(&system_transition_mutex);
613620
return error;
614621
}

0 commit comments

Comments
 (0)