Преглед изворни кода

Merge branch 'pm-sleep'

* pm-sleep:
  PM / Sleep: Require CAP_BLOCK_SUSPEND to use wake_lock/wake_unlock
  PM / Sleep: Add missing static storage class specifiers in main.c
  PM / Sleep: Fix build warning in sysfs.c for CONFIG_PM_SLEEP unset
  PM / Hibernate: Print hibernation/thaw progress indicator one line at a time.
  PM / Sleep: Separate printing suspend times from initcall_debug
  PM / Sleep: add knob for printing device resume times
  ftrace: Disable function tracing during suspend/resume and hibernation, again
  PM / Hibernate: Enable suspend to both for in-kernel hibernation.
Rafael J. Wysocki пре 13 година
родитељ
комит
d52fdf1337

+ 13 - 0
Documentation/ABI/testing/sysfs-power

@@ -231,3 +231,16 @@ Description:
 		Reads from this file return a string consisting of the names of
 		Reads from this file return a string consisting of the names of
 		wakeup sources created with the help of /sys/power/wake_lock
 		wakeup sources created with the help of /sys/power/wake_lock
 		that are inactive at the moment, separated with spaces.
 		that are inactive at the moment, separated with spaces.
+
+What:		/sys/power/pm_print_times
+Date:		May 2012
+Contact:	Sameer Nanda <snanda@chromium.org>
+Description:
+		The /sys/power/pm_print_times file allows user space to
+		control whether the time taken by devices to suspend and
+		resume is printed.  These prints are useful for hunting down
+		devices that take too long to suspend or resume.
+
+		Writing a "1" enables this printing while writing a "0"
+		disables it.  The default value is "0".  Reading from this file
+		will display the current value.

+ 5 - 0
Documentation/power/swsusp.txt

@@ -33,6 +33,11 @@ echo shutdown > /sys/power/disk; echo disk > /sys/power/state
 
 
 echo platform > /sys/power/disk; echo disk > /sys/power/state
 echo platform > /sys/power/disk; echo disk > /sys/power/state
 
 
+. If you would like to write hibernation image to swap and then suspend
+to RAM (provided your platform supports it), you can try
+
+echo suspend > /sys/power/disk; echo disk > /sys/power/state
+
 . If you have SATA disks, you'll need recent kernels with SATA suspend
 . If you have SATA disks, you'll need recent kernels with SATA suspend
 support. For suspend and resume to work, make sure your disk drivers
 support. For suspend and resume to work, make sure your disk drivers
 are built into kernel -- not modules. [There's way to make
 are built into kernel -- not modules. [There's way to make

+ 6 - 6
drivers/base/power/main.c

@@ -45,10 +45,10 @@ typedef int (*pm_callback_t)(struct device *);
  */
  */
 
 
 LIST_HEAD(dpm_list);
 LIST_HEAD(dpm_list);
-LIST_HEAD(dpm_prepared_list);
-LIST_HEAD(dpm_suspended_list);
-LIST_HEAD(dpm_late_early_list);
-LIST_HEAD(dpm_noirq_list);
+static LIST_HEAD(dpm_prepared_list);
+static LIST_HEAD(dpm_suspended_list);
+static LIST_HEAD(dpm_late_early_list);
+static LIST_HEAD(dpm_noirq_list);
 
 
 struct suspend_stats suspend_stats;
 struct suspend_stats suspend_stats;
 static DEFINE_MUTEX(dpm_list_mtx);
 static DEFINE_MUTEX(dpm_list_mtx);
@@ -166,7 +166,7 @@ static ktime_t initcall_debug_start(struct device *dev)
 {
 {
 	ktime_t calltime = ktime_set(0, 0);
 	ktime_t calltime = ktime_set(0, 0);
 
 
-	if (initcall_debug) {
+	if (pm_print_times_enabled) {
 		pr_info("calling  %s+ @ %i, parent: %s\n",
 		pr_info("calling  %s+ @ %i, parent: %s\n",
 			dev_name(dev), task_pid_nr(current),
 			dev_name(dev), task_pid_nr(current),
 			dev->parent ? dev_name(dev->parent) : "none");
 			dev->parent ? dev_name(dev->parent) : "none");
@@ -181,7 +181,7 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime,
 {
 {
 	ktime_t delta, rettime;
 	ktime_t delta, rettime;
 
 
-	if (initcall_debug) {
+	if (pm_print_times_enabled) {
 		rettime = ktime_get();
 		rettime = ktime_get();
 		delta = ktime_sub(rettime, calltime);
 		delta = ktime_sub(rettime, calltime);
 		pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
 		pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),

+ 4 - 0
drivers/base/power/sysfs.c

@@ -474,6 +474,8 @@ static DEVICE_ATTR(runtime_enabled, 0444, rtpm_enabled_show, NULL);
 
 
 #endif
 #endif
 
 
+#ifdef CONFIG_PM_SLEEP
+
 static ssize_t async_show(struct device *dev, struct device_attribute *attr,
 static ssize_t async_show(struct device *dev, struct device_attribute *attr,
 			  char *buf)
 			  char *buf)
 {
 {
@@ -500,6 +502,8 @@ static ssize_t async_store(struct device *dev, struct device_attribute *attr,
 }
 }
 
 
 static DEVICE_ATTR(async, 0644, async_show, async_store);
 static DEVICE_ATTR(async, 0644, async_show, async_store);
+
+#endif
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
 
 
 static struct attribute *power_attrs[] = {
 static struct attribute *power_attrs[] = {

+ 6 - 0
include/linux/suspend.h

@@ -408,6 +408,12 @@ static inline void unlock_system_sleep(void) {}
 
 
 #endif /* !CONFIG_PM_SLEEP */
 #endif /* !CONFIG_PM_SLEEP */
 
 
+#ifdef CONFIG_PM_SLEEP_DEBUG
+extern bool pm_print_times_enabled;
+#else
+#define pm_print_times_enabled	(false)
+#endif
+
 #ifdef CONFIG_PM_AUTOSLEEP
 #ifdef CONFIG_PM_AUTOSLEEP
 
 
 /* kernel/power/autosleep.c */
 /* kernel/power/autosleep.c */

+ 2 - 2
kernel/power/Kconfig

@@ -175,7 +175,7 @@ config PM_TEST_SUSPEND
 	You probably want to have your system's RTC driver statically
 	You probably want to have your system's RTC driver statically
 	linked, ensuring that it's available when this test runs.
 	linked, ensuring that it's available when this test runs.
 
 
-config CAN_PM_TRACE
+config PM_SLEEP_DEBUG
 	def_bool y
 	def_bool y
 	depends on PM_DEBUG && PM_SLEEP
 	depends on PM_DEBUG && PM_SLEEP
 
 
@@ -196,7 +196,7 @@ config PM_TRACE
 
 
 config PM_TRACE_RTC
 config PM_TRACE_RTC
 	bool "Suspend/resume event tracing"
 	bool "Suspend/resume event tracing"
-	depends on CAN_PM_TRACE
+	depends on PM_SLEEP_DEBUG
 	depends on X86
 	depends on X86
 	select PM_TRACE
 	select PM_TRACE
 	---help---
 	---help---

+ 42 - 0
kernel/power/hibernate.c

@@ -5,6 +5,7 @@
  * Copyright (c) 2003 Open Source Development Lab
  * Copyright (c) 2003 Open Source Development Lab
  * Copyright (c) 2004 Pavel Machek <pavel@ucw.cz>
  * Copyright (c) 2004 Pavel Machek <pavel@ucw.cz>
  * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc.
  * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc.
+ * Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com>
  *
  *
  * This file is released under the GPLv2.
  * This file is released under the GPLv2.
  */
  */
@@ -46,6 +47,9 @@ enum {
 	HIBERNATION_PLATFORM,
 	HIBERNATION_PLATFORM,
 	HIBERNATION_SHUTDOWN,
 	HIBERNATION_SHUTDOWN,
 	HIBERNATION_REBOOT,
 	HIBERNATION_REBOOT,
+#ifdef CONFIG_SUSPEND
+	HIBERNATION_SUSPEND,
+#endif
 	/* keep last */
 	/* keep last */
 	__HIBERNATION_AFTER_LAST
 	__HIBERNATION_AFTER_LAST
 };
 };
@@ -354,6 +358,7 @@ int hibernation_snapshot(int platform_mode)
 	}
 	}
 
 
 	suspend_console();
 	suspend_console();
+	ftrace_stop();
 	pm_restrict_gfp_mask();
 	pm_restrict_gfp_mask();
 
 
 	error = dpm_suspend(PMSG_FREEZE);
 	error = dpm_suspend(PMSG_FREEZE);
@@ -379,6 +384,7 @@ int hibernation_snapshot(int platform_mode)
 	if (error || !in_suspend)
 	if (error || !in_suspend)
 		pm_restore_gfp_mask();
 		pm_restore_gfp_mask();
 
 
+	ftrace_start();
 	resume_console();
 	resume_console();
 	dpm_complete(msg);
 	dpm_complete(msg);
 
 
@@ -481,6 +487,7 @@ int hibernation_restore(int platform_mode)
 
 
 	pm_prepare_console();
 	pm_prepare_console();
 	suspend_console();
 	suspend_console();
+	ftrace_stop();
 	pm_restrict_gfp_mask();
 	pm_restrict_gfp_mask();
 	error = dpm_suspend_start(PMSG_QUIESCE);
 	error = dpm_suspend_start(PMSG_QUIESCE);
 	if (!error) {
 	if (!error) {
@@ -488,6 +495,7 @@ int hibernation_restore(int platform_mode)
 		dpm_resume_end(PMSG_RECOVER);
 		dpm_resume_end(PMSG_RECOVER);
 	}
 	}
 	pm_restore_gfp_mask();
 	pm_restore_gfp_mask();
+	ftrace_start();
 	resume_console();
 	resume_console();
 	pm_restore_console();
 	pm_restore_console();
 	return error;
 	return error;
@@ -514,6 +522,7 @@ int hibernation_platform_enter(void)
 
 
 	entering_platform_hibernation = true;
 	entering_platform_hibernation = true;
 	suspend_console();
 	suspend_console();
+	ftrace_stop();
 	error = dpm_suspend_start(PMSG_HIBERNATE);
 	error = dpm_suspend_start(PMSG_HIBERNATE);
 	if (error) {
 	if (error) {
 		if (hibernation_ops->recover)
 		if (hibernation_ops->recover)
@@ -557,6 +566,7 @@ int hibernation_platform_enter(void)
  Resume_devices:
  Resume_devices:
 	entering_platform_hibernation = false;
 	entering_platform_hibernation = false;
 	dpm_resume_end(PMSG_RESTORE);
 	dpm_resume_end(PMSG_RESTORE);
+	ftrace_start();
 	resume_console();
 	resume_console();
 
 
  Close:
  Close:
@@ -574,6 +584,10 @@ int hibernation_platform_enter(void)
  */
  */
 static void power_down(void)
 static void power_down(void)
 {
 {
+#ifdef CONFIG_SUSPEND
+	int error;
+#endif
+
 	switch (hibernation_mode) {
 	switch (hibernation_mode) {
 	case HIBERNATION_REBOOT:
 	case HIBERNATION_REBOOT:
 		kernel_restart(NULL);
 		kernel_restart(NULL);
@@ -583,6 +597,25 @@ static void power_down(void)
 	case HIBERNATION_SHUTDOWN:
 	case HIBERNATION_SHUTDOWN:
 		kernel_power_off();
 		kernel_power_off();
 		break;
 		break;
+#ifdef CONFIG_SUSPEND
+	case HIBERNATION_SUSPEND:
+		error = suspend_devices_and_enter(PM_SUSPEND_MEM);
+		if (error) {
+			if (hibernation_ops)
+				hibernation_mode = HIBERNATION_PLATFORM;
+			else
+				hibernation_mode = HIBERNATION_SHUTDOWN;
+			power_down();
+		}
+		/*
+		 * Restore swap signature.
+		 */
+		error = swsusp_unmark();
+		if (error)
+			printk(KERN_ERR "PM: Swap will be unusable! "
+			                "Try swapon -a.\n");
+		return;
+#endif
 	}
 	}
 	kernel_halt();
 	kernel_halt();
 	/*
 	/*
@@ -827,6 +860,9 @@ static const char * const hibernation_modes[] = {
 	[HIBERNATION_PLATFORM]	= "platform",
 	[HIBERNATION_PLATFORM]	= "platform",
 	[HIBERNATION_SHUTDOWN]	= "shutdown",
 	[HIBERNATION_SHUTDOWN]	= "shutdown",
 	[HIBERNATION_REBOOT]	= "reboot",
 	[HIBERNATION_REBOOT]	= "reboot",
+#ifdef CONFIG_SUSPEND
+	[HIBERNATION_SUSPEND]	= "suspend",
+#endif
 };
 };
 
 
 /*
 /*
@@ -867,6 +903,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
 		switch (i) {
 		switch (i) {
 		case HIBERNATION_SHUTDOWN:
 		case HIBERNATION_SHUTDOWN:
 		case HIBERNATION_REBOOT:
 		case HIBERNATION_REBOOT:
+#ifdef CONFIG_SUSPEND
+		case HIBERNATION_SUSPEND:
+#endif
 			break;
 			break;
 		case HIBERNATION_PLATFORM:
 		case HIBERNATION_PLATFORM:
 			if (hibernation_ops)
 			if (hibernation_ops)
@@ -907,6 +946,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
 		switch (mode) {
 		switch (mode) {
 		case HIBERNATION_SHUTDOWN:
 		case HIBERNATION_SHUTDOWN:
 		case HIBERNATION_REBOOT:
 		case HIBERNATION_REBOOT:
+#ifdef CONFIG_SUSPEND
+		case HIBERNATION_SUSPEND:
+#endif
 			hibernation_mode = mode;
 			hibernation_mode = mode;
 			break;
 			break;
 		case HIBERNATION_PLATFORM:
 		case HIBERNATION_PLATFORM:

+ 45 - 0
kernel/power/main.c

@@ -235,6 +235,47 @@ late_initcall(pm_debugfs_init);
 
 
 #endif /* CONFIG_PM_SLEEP */
 #endif /* CONFIG_PM_SLEEP */
 
 
+#ifdef CONFIG_PM_SLEEP_DEBUG
+/*
+ * pm_print_times: print time taken by devices to suspend and resume.
+ *
+ * show() returns whether printing of suspend and resume times is enabled.
+ * store() accepts 0 or 1.  0 disables printing and 1 enables it.
+ */
+bool pm_print_times_enabled;
+
+static ssize_t pm_print_times_show(struct kobject *kobj,
+				   struct kobj_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", pm_print_times_enabled);
+}
+
+static ssize_t pm_print_times_store(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	if (val > 1)
+		return -EINVAL;
+
+	pm_print_times_enabled = !!val;
+	return n;
+}
+
+power_attr(pm_print_times);
+
+static inline void pm_print_times_init(void)
+{
+	pm_print_times_enabled = !!initcall_debug;
+}
+#else /* !CONFIG_PP_SLEEP_DEBUG */
+static inline void pm_print_times_init(void) {}
+#endif /* CONFIG_PM_SLEEP_DEBUG */
+
 struct kobject *power_kobj;
 struct kobject *power_kobj;
 
 
 /**
 /**
@@ -531,6 +572,9 @@ static struct attribute * g[] = {
 #ifdef CONFIG_PM_DEBUG
 #ifdef CONFIG_PM_DEBUG
 	&pm_test_attr.attr,
 	&pm_test_attr.attr,
 #endif
 #endif
+#ifdef CONFIG_PM_SLEEP_DEBUG
+	&pm_print_times_attr.attr,
+#endif
 #endif
 #endif
 	NULL,
 	NULL,
 };
 };
@@ -566,6 +610,7 @@ static int __init pm_init(void)
 	error = sysfs_create_group(power_kobj, &attr_group);
 	error = sysfs_create_group(power_kobj, &attr_group);
 	if (error)
 	if (error)
 		return error;
 		return error;
+	pm_print_times_init();
 	return pm_autosleep_init();
 	return pm_autosleep_init();
 }
 }
 
 

+ 3 - 0
kernel/power/power.h

@@ -156,6 +156,9 @@ extern void swsusp_free(void);
 extern int swsusp_read(unsigned int *flags_p);
 extern int swsusp_read(unsigned int *flags_p);
 extern int swsusp_write(unsigned int flags);
 extern int swsusp_write(unsigned int flags);
 extern void swsusp_close(fmode_t);
 extern void swsusp_close(fmode_t);
+#ifdef CONFIG_SUSPEND
+extern int swsusp_unmark(void);
+#endif
 
 
 /* kernel/power/block_io.c */
 /* kernel/power/block_io.c */
 extern struct block_device *hib_resume_bdev;
 extern struct block_device *hib_resume_bdev;

+ 3 - 0
kernel/power/suspend.c

@@ -24,6 +24,7 @@
 #include <linux/export.h>
 #include <linux/export.h>
 #include <linux/suspend.h>
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
 #include <linux/syscore_ops.h>
+#include <linux/ftrace.h>
 #include <trace/events/power.h>
 #include <trace/events/power.h>
 
 
 #include "power.h"
 #include "power.h"
@@ -212,6 +213,7 @@ int suspend_devices_and_enter(suspend_state_t state)
 			goto Close;
 			goto Close;
 	}
 	}
 	suspend_console();
 	suspend_console();
+	ftrace_stop();
 	suspend_test_start();
 	suspend_test_start();
 	error = dpm_suspend_start(PMSG_SUSPEND);
 	error = dpm_suspend_start(PMSG_SUSPEND);
 	if (error) {
 	if (error) {
@@ -231,6 +233,7 @@ int suspend_devices_and_enter(suspend_state_t state)
 	suspend_test_start();
 	suspend_test_start();
 	dpm_resume_end(PMSG_RESUME);
 	dpm_resume_end(PMSG_RESUME);
 	suspend_test_finish("resume devices");
 	suspend_test_finish("resume devices");
+	ftrace_start();
 	resume_console();
 	resume_console();
  Close:
  Close:
 	if (suspend_ops->end)
 	if (suspend_ops->end)

+ 55 - 27
kernel/power/swap.c

@@ -448,9 +448,9 @@ static int save_image(struct swap_map_handle *handle,
 	struct timeval start;
 	struct timeval start;
 	struct timeval stop;
 	struct timeval stop;
 
 
-	printk(KERN_INFO "PM: Saving image data pages (%u pages) ...     ",
+	printk(KERN_INFO "PM: Saving image data pages (%u pages)...\n",
 		nr_to_write);
 		nr_to_write);
-	m = nr_to_write / 100;
+	m = nr_to_write / 10;
 	if (!m)
 	if (!m)
 		m = 1;
 		m = 1;
 	nr_pages = 0;
 	nr_pages = 0;
@@ -464,7 +464,8 @@ static int save_image(struct swap_map_handle *handle,
 		if (ret)
 		if (ret)
 			break;
 			break;
 		if (!(nr_pages % m))
 		if (!(nr_pages % m))
-			printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
+			printk(KERN_INFO "PM: Image saving progress: %3d%%\n",
+			       nr_pages / m * 10);
 		nr_pages++;
 		nr_pages++;
 	}
 	}
 	err2 = hib_wait_on_bio_chain(&bio);
 	err2 = hib_wait_on_bio_chain(&bio);
@@ -472,9 +473,7 @@ static int save_image(struct swap_map_handle *handle,
 	if (!ret)
 	if (!ret)
 		ret = err2;
 		ret = err2;
 	if (!ret)
 	if (!ret)
-		printk(KERN_CONT "\b\b\b\bdone\n");
-	else
-		printk(KERN_CONT "\n");
+		printk(KERN_INFO "PM: Image saving done.\n");
 	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
 	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
 	return ret;
 	return ret;
 }
 }
@@ -668,9 +667,9 @@ static int save_image_lzo(struct swap_map_handle *handle,
 
 
 	printk(KERN_INFO
 	printk(KERN_INFO
 		"PM: Using %u thread(s) for compression.\n"
 		"PM: Using %u thread(s) for compression.\n"
-		"PM: Compressing and saving image data (%u pages) ...     ",
+		"PM: Compressing and saving image data (%u pages)...\n",
 		nr_threads, nr_to_write);
 		nr_threads, nr_to_write);
-	m = nr_to_write / 100;
+	m = nr_to_write / 10;
 	if (!m)
 	if (!m)
 		m = 1;
 		m = 1;
 	nr_pages = 0;
 	nr_pages = 0;
@@ -690,8 +689,10 @@ static int save_image_lzo(struct swap_map_handle *handle,
 				       data_of(*snapshot), PAGE_SIZE);
 				       data_of(*snapshot), PAGE_SIZE);
 
 
 				if (!(nr_pages % m))
 				if (!(nr_pages % m))
-					printk(KERN_CONT "\b\b\b\b%3d%%",
-				               nr_pages / m);
+					printk(KERN_INFO
+					       "PM: Image saving progress: "
+					       "%3d%%\n",
+				               nr_pages / m * 10);
 				nr_pages++;
 				nr_pages++;
 			}
 			}
 			if (!off)
 			if (!off)
@@ -761,11 +762,8 @@ out_finish:
 	do_gettimeofday(&stop);
 	do_gettimeofday(&stop);
 	if (!ret)
 	if (!ret)
 		ret = err2;
 		ret = err2;
-	if (!ret) {
-		printk(KERN_CONT "\b\b\b\bdone\n");
-	} else {
-		printk(KERN_CONT "\n");
-	}
+	if (!ret)
+		printk(KERN_INFO "PM: Image saving done.\n");
 	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
 	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
 out_clean:
 out_clean:
 	if (crc) {
 	if (crc) {
@@ -973,9 +971,9 @@ static int load_image(struct swap_map_handle *handle,
 	int err2;
 	int err2;
 	unsigned nr_pages;
 	unsigned nr_pages;
 
 
-	printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ",
+	printk(KERN_INFO "PM: Loading image data pages (%u pages)...\n",
 		nr_to_read);
 		nr_to_read);
-	m = nr_to_read / 100;
+	m = nr_to_read / 10;
 	if (!m)
 	if (!m)
 		m = 1;
 		m = 1;
 	nr_pages = 0;
 	nr_pages = 0;
@@ -993,7 +991,8 @@ static int load_image(struct swap_map_handle *handle,
 		if (ret)
 		if (ret)
 			break;
 			break;
 		if (!(nr_pages % m))
 		if (!(nr_pages % m))
-			printk("\b\b\b\b%3d%%", nr_pages / m);
+			printk(KERN_INFO "PM: Image loading progress: %3d%%\n",
+			       nr_pages / m * 10);
 		nr_pages++;
 		nr_pages++;
 	}
 	}
 	err2 = hib_wait_on_bio_chain(&bio);
 	err2 = hib_wait_on_bio_chain(&bio);
@@ -1001,12 +1000,11 @@ static int load_image(struct swap_map_handle *handle,
 	if (!ret)
 	if (!ret)
 		ret = err2;
 		ret = err2;
 	if (!ret) {
 	if (!ret) {
-		printk("\b\b\b\bdone\n");
+		printk(KERN_INFO "PM: Image loading done.\n");
 		snapshot_write_finalize(snapshot);
 		snapshot_write_finalize(snapshot);
 		if (!snapshot_image_loaded(snapshot))
 		if (!snapshot_image_loaded(snapshot))
 			ret = -ENODATA;
 			ret = -ENODATA;
-	} else
-		printk("\n");
+	}
 	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
 	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
 	return ret;
 	return ret;
 }
 }
@@ -1185,9 +1183,9 @@ static int load_image_lzo(struct swap_map_handle *handle,
 
 
 	printk(KERN_INFO
 	printk(KERN_INFO
 		"PM: Using %u thread(s) for decompression.\n"
 		"PM: Using %u thread(s) for decompression.\n"
-		"PM: Loading and decompressing image data (%u pages) ...     ",
+		"PM: Loading and decompressing image data (%u pages)...\n",
 		nr_threads, nr_to_read);
 		nr_threads, nr_to_read);
-	m = nr_to_read / 100;
+	m = nr_to_read / 10;
 	if (!m)
 	if (!m)
 		m = 1;
 		m = 1;
 	nr_pages = 0;
 	nr_pages = 0;
@@ -1319,7 +1317,10 @@ static int load_image_lzo(struct swap_map_handle *handle,
 				       data[thr].unc + off, PAGE_SIZE);
 				       data[thr].unc + off, PAGE_SIZE);
 
 
 				if (!(nr_pages % m))
 				if (!(nr_pages % m))
-					printk("\b\b\b\b%3d%%", nr_pages / m);
+					printk(KERN_INFO
+					       "PM: Image loading progress: "
+					       "%3d%%\n",
+					       nr_pages / m * 10);
 				nr_pages++;
 				nr_pages++;
 
 
 				ret = snapshot_write_next(snapshot);
 				ret = snapshot_write_next(snapshot);
@@ -1344,7 +1345,7 @@ out_finish:
 	}
 	}
 	do_gettimeofday(&stop);
 	do_gettimeofday(&stop);
 	if (!ret) {
 	if (!ret) {
-		printk("\b\b\b\bdone\n");
+		printk(KERN_INFO "PM: Image loading done.\n");
 		snapshot_write_finalize(snapshot);
 		snapshot_write_finalize(snapshot);
 		if (!snapshot_image_loaded(snapshot))
 		if (!snapshot_image_loaded(snapshot))
 			ret = -ENODATA;
 			ret = -ENODATA;
@@ -1357,8 +1358,7 @@ out_finish:
 				}
 				}
 			}
 			}
 		}
 		}
-	} else
-		printk("\n");
+	}
 	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
 	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
 out_clean:
 out_clean:
 	for (i = 0; i < ring_size; i++)
 	for (i = 0; i < ring_size; i++)
@@ -1472,6 +1472,34 @@ void swsusp_close(fmode_t mode)
 	blkdev_put(hib_resume_bdev, mode);
 	blkdev_put(hib_resume_bdev, mode);
 }
 }
 
 
+/**
+ *      swsusp_unmark - Unmark swsusp signature in the resume device
+ */
+
+#ifdef CONFIG_SUSPEND
+int swsusp_unmark(void)
+{
+	int error;
+
+	hib_bio_read_page(swsusp_resume_block, swsusp_header, NULL);
+	if (!memcmp(HIBERNATE_SIG,swsusp_header->sig, 10)) {
+		memcpy(swsusp_header->sig,swsusp_header->orig_sig, 10);
+		error = hib_bio_write_page(swsusp_resume_block,
+					swsusp_header, NULL);
+	} else {
+		printk(KERN_ERR "PM: Cannot find swsusp signature!\n");
+		error = -ENODEV;
+	}
+
+	/*
+	 * We just returned from suspend, we don't need the image any more.
+	 */
+	free_all_swap_pages(root_swap);
+
+	return error;
+}
+#endif
+
 static int swsusp_header_init(void)
 static int swsusp_header_init(void)
 {
 {
 	swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);
 	swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);

+ 7 - 0
kernel/power/wakelock.c

@@ -9,6 +9,7 @@
  * manipulate wakelocks on Android.
  * manipulate wakelocks on Android.
  */
  */
 
 
+#include <linux/capability.h>
 #include <linux/ctype.h>
 #include <linux/ctype.h>
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/err.h>
@@ -188,6 +189,9 @@ int pm_wake_lock(const char *buf)
 	size_t len;
 	size_t len;
 	int ret = 0;
 	int ret = 0;
 
 
+	if (!capable(CAP_BLOCK_SUSPEND))
+		return -EPERM;
+
 	while (*str && !isspace(*str))
 	while (*str && !isspace(*str))
 		str++;
 		str++;
 
 
@@ -231,6 +235,9 @@ int pm_wake_unlock(const char *buf)
 	size_t len;
 	size_t len;
 	int ret = 0;
 	int ret = 0;
 
 
+	if (!capable(CAP_BLOCK_SUSPEND))
+		return -EPERM;
+
 	len = strlen(buf);
 	len = strlen(buf);
 	if (!len)
 	if (!len)
 		return -EINVAL;
 		return -EINVAL;