summaryrefslogtreecommitdiffstats
path: root/hibernate-freeze-filesystems.patch
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@redhat.com>2012-02-17 12:42:55 -0500
committerJosh Boyer <jwboyer@redhat.com>2012-02-17 13:42:40 -0500
commitfcbaf26ab3324e948e5ba3835f367ab6d5985b5d (patch)
treef6613875a4cdf49965770e61d895fdd3bee21759 /hibernate-freeze-filesystems.patch
parent49739536e3e3734a4f5fc3b5a697c5d9f996bb4d (diff)
downloadkernel-fcbaf26ab3324e948e5ba3835f367ab6d5985b5d.tar.gz
kernel-fcbaf26ab3324e948e5ba3835f367ab6d5985b5d.tar.xz
kernel-fcbaf26ab3324e948e5ba3835f367ab6d5985b5d.zip
Freeze all filesystems during system suspend/hibernate.
Rebased http://marc.info/?l=linux-kernel&m=132775832509351&w=4 to 3.3-rc3
Diffstat (limited to 'hibernate-freeze-filesystems.patch')
-rw-r--r--hibernate-freeze-filesystems.patch287
1 files changed, 287 insertions, 0 deletions
diff --git a/hibernate-freeze-filesystems.patch b/hibernate-freeze-filesystems.patch
new file mode 100644
index 000000000..841cab643
--- /dev/null
+++ b/hibernate-freeze-filesystems.patch
@@ -0,0 +1,287 @@
+commit b94887bbc0621e1e8402e7f0ec4bc3adf46c9a6e
+Author: Rafael J. Wysocki <rjw@sisk.pl>
+Date: Fri Feb 17 12:42:08 2012 -0500
+
+ Freeze all filesystems during system suspend and (kernel-driven)
+ hibernation by calling freeze_supers() for all superblocks and thaw
+ them during the subsequent resume with the help of thaw_supers().
+
+ This makes filesystems stay in a consistent state in case something
+ goes wrong between system suspend (or hibernation) and the subsequent
+ resume (e.g. journal replays won't be necessary in those cases). In
+ particular, this should help to solve a long-standing issue that, in
+ some cases, during resume from hibernation the boot loader causes the
+ journal to be replied for the filesystem containing the kernel image
+ and/or initrd causing it to become inconsistent with the information
+ stored in the hibernation image.
+
+ The user-space-driven hibernation (s2disk) is not covered by this
+ change, because the freezing of filesystems prevents s2disk from
+ accessing device special files it needs to do its job.
+
+ This change is based on earlier work by Nigel Cunningham.
+
+ Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
+
+ Rebased to 3.3-rc3 by Josh Boyer <jwboyer@redhat.com>
+
+diff --git a/fs/super.c b/fs/super.c
+index 6015c02..c8057fa 100644
+--- a/fs/super.c
++++ b/fs/super.c
+@@ -594,6 +594,79 @@ void iterate_supers_type(struct file_system_type *type,
+ EXPORT_SYMBOL(iterate_supers_type);
+
+ /**
++ * thaw_supers - call thaw_super() for all superblocks
++ */
++void thaw_supers(void)
++{
++ struct super_block *sb, *p = NULL;
++
++ spin_lock(&sb_lock);
++ list_for_each_entry(sb, &super_blocks, s_list) {
++ if (hlist_unhashed(&sb->s_instances))
++ continue;
++ sb->s_count++;
++ spin_unlock(&sb_lock);
++
++ if (sb->s_flags & MS_FROZEN) {
++ thaw_super(sb);
++ sb->s_flags &= ~MS_FROZEN;
++ }
++
++ spin_lock(&sb_lock);
++ if (p)
++ __put_super(p);
++ p = sb;
++ }
++ if (p)
++ __put_super(p);
++ spin_unlock(&sb_lock);
++}
++
++/**
++ * freeze_supers - call freeze_super() for all superblocks
++ */
++int freeze_supers(void)
++{
++ struct super_block *sb, *p = NULL;
++ int error = 0;
++
++ spin_lock(&sb_lock);
++ /*
++ * Freeze in reverse order so filesystems depending on others are
++ * frozen in the right order (eg. loopback on ext3).
++ */
++ list_for_each_entry_reverse(sb, &super_blocks, s_list) {
++ if (hlist_unhashed(&sb->s_instances))
++ continue;
++ sb->s_count++;
++ spin_unlock(&sb_lock);
++
++ if (sb->s_root && sb->s_frozen != SB_FREEZE_TRANS
++ && !(sb->s_flags & MS_RDONLY)) {
++ error = freeze_super(sb);
++ if (!error)
++ sb->s_flags |= MS_FROZEN;
++ }
++
++ spin_lock(&sb_lock);
++ if (error)
++ break;
++ if (p)
++ __put_super(p);
++ p = sb;
++ }
++ if (p)
++ __put_super(p);
++ spin_unlock(&sb_lock);
++
++ if (error)
++ thaw_supers();
++
++ return error;
++}
++
++
++/**
+ * get_super - get the superblock of a device
+ * @bdev: device to get the superblock for
+ *
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index 386da09..a164f4a 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -210,6 +210,7 @@ struct inodes_stat_t {
+ #define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */
+ #define MS_I_VERSION (1<<23) /* Update inode I_version field */
+ #define MS_STRICTATIME (1<<24) /* Always perform atime updates */
++#define MS_FROZEN (1<<25) /* Frozen filesystem */
+ #define MS_NOSEC (1<<28)
+ #define MS_BORN (1<<29)
+ #define MS_ACTIVE (1<<30)
+@@ -2501,6 +2502,8 @@ extern void drop_super(struct super_block *sb);
+ extern void iterate_supers(void (*)(struct super_block *, void *), void *);
+ extern void iterate_supers_type(struct file_system_type *,
+ void (*)(struct super_block *, void *), void *);
++extern int freeze_supers(void);
++extern void thaw_supers(void);
+
+ extern int dcache_dir_open(struct inode *, struct file *);
+ extern int dcache_dir_close(struct inode *, struct file *);
+diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
+index 6d6d288..492fc62 100644
+--- a/kernel/power/hibernate.c
++++ b/kernel/power/hibernate.c
+@@ -626,12 +626,17 @@ int hibernate(void)
+ if (error)
+ goto Finish;
+
+- error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
++ error = freeze_supers();
+ if (error)
+ goto Thaw;
++
++ error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
++ if (error)
++ goto Thaw_fs;
++
+ if (freezer_test_done) {
+ freezer_test_done = false;
+- goto Thaw;
++ goto Thaw_fs;
+ }
+
+ if (in_suspend) {
+@@ -655,6 +660,8 @@ int hibernate(void)
+ pr_debug("PM: Image restored successfully.\n");
+ }
+
++ Thaw_fs:
++ thaw_supers();
+ Thaw:
+ thaw_processes();
+ Finish:
+diff --git a/kernel/power/power.h b/kernel/power/power.h
+index 21724ee..40d6f64 100644
+--- a/kernel/power/power.h
++++ b/kernel/power/power.h
+@@ -1,3 +1,4 @@
++#include <linux/fs.h>
+ #include <linux/suspend.h>
+ #include <linux/suspend_ioctls.h>
+ #include <linux/utsname.h>
+@@ -227,45 +228,3 @@ enum {
+ #define TEST_MAX (__TEST_AFTER_LAST - 1)
+
+ extern int pm_test_level;
+-
+-#ifdef CONFIG_SUSPEND_FREEZER
+-static inline int suspend_freeze_processes(void)
+-{
+- int error;
+-
+- error = freeze_processes();
+-
+- /*
+- * freeze_processes() automatically thaws every task if freezing
+- * fails. So we need not do anything extra upon error.
+- */
+- if (error)
+- goto Finish;
+-
+- error = freeze_kernel_threads();
+-
+- /*
+- * freeze_kernel_threads() thaws only kernel threads upon freezing
+- * failure. So we have to thaw the userspace tasks ourselves.
+- */
+- if (error)
+- thaw_processes();
+-
+- Finish:
+- return error;
+-}
+-
+-static inline void suspend_thaw_processes(void)
+-{
+- thaw_processes();
+-}
+-#else
+-static inline int suspend_freeze_processes(void)
+-{
+- return 0;
+-}
+-
+-static inline void suspend_thaw_processes(void)
+-{
+-}
+-#endif
+diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
+index 4fd51be..5f51fc7 100644
+--- a/kernel/power/suspend.c
++++ b/kernel/power/suspend.c
+@@ -29,6 +29,62 @@
+
+ #include "power.h"
+
++#ifdef CONFIG_SUSPEND_FREEZER
++
++static inline int suspend_freeze_processes(void)
++{
++ int error;
++
++ error = freeze_processes();
++
++ /*
++ * freeze_processes() automatically thaws every task if freezing
++ * fails. So we need not do anything extra upon error.
++ */
++
++ if (error)
++ goto Finish;
++
++ error = freeze_supers();
++ if (error) {
++ thaw_processes();
++ goto Finish;
++ }
++
++ error = freeze_kernel_threads();
++
++ /*
++ * freeze_kernel_threads() thaws only kernel threads upon freezing
++ * failure. So we have to thaw the userspace tasks ourselves.
++ */
++ if (error) {
++ thaw_supers();
++ thaw_processes();
++ }
++
++Finish:
++ return error;
++}
++
++static inline void suspend_thaw_processes(void)
++{
++ thaw_supers();
++ thaw_processes();
++}
++
++#else /* !CONFIG_SUSPEND_FREEZER */
++
++static inline int suspend_freeze_processes(void)
++{
++ return 0;
++}
++
++static inline void suspend_thaw_processes(void)
++{
++}
++
++#endif /* !CONFIG_SUSPEND_FREEZER */
++
+ const char *const pm_states[PM_SUSPEND_MAX] = {
+ [PM_SUSPEND_STANDBY] = "standby",
+ [PM_SUSPEND_MEM] = "mem",