Skip to content

Commit 05b158d

Browse files
committed
Merge patch series "power: wire-up filesystem freeze/thaw with suspend/resume"
Christian Brauner <[email protected]> says: 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. Othwerwise it risks thawing filesystems it didn't own. This could be done differently be e.g., keeping the filesystems that were actually frozen on a list and then unfreezing them from that list. This is disgustingly unclean though and reeks of an ugly hack. If the filesystem is already frozen by the time we've frozen all userspace processes we don't care to freeze it again. That's userspace's job once the process resumes. We only actually freeze filesystems if we absolutely have to and we ignore other failures to 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. * patches from https://lore.kernel.org/r/[email protected]: kernfs: add warning about implementing freeze/thaw power: freeze filesystems during suspend/resume Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Christian Brauner <[email protected]>
2 parents 0de4c40 + ef2ed04 commit 05b158d

File tree

5 files changed

+72
-1
lines changed

5 files changed

+72
-1
lines changed

fs/kernfs/mount.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,21 @@ const struct super_operations kernfs_sops = {
6262

6363
.show_options = kernfs_sop_show_options,
6464
.show_path = kernfs_sop_show_path,
65+
66+
/*
67+
* sysfs is built on top of kernfs and sysfs provides the power
68+
* management infrastructure to support suspend/hibernate by
69+
* writing to various files in /sys/power/. As filesystems may
70+
* be automatically frozen during suspend/hibernate implementing
71+
* freeze/thaw support for kernfs generically will cause
72+
* deadlocks as the suspending/hibernation initiating task will
73+
* hold a VFS lock that it will then wait upon to be released.
74+
* If freeze/thaw for kernfs is needed talk to the VFS.
75+
*/
76+
.freeze_fs = NULL,
77+
.unfreeze_fs = NULL,
78+
.freeze_super = NULL,
79+
.thaw_super = NULL,
6580
};
6681

6782
static int kernfs_encode_fh(struct inode *inode, __u32 *fh, int *max_len,

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)