lkundrak / rpms / kernel

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