mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-14 00:24:41 -04:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6: (26 commits) PM / Wakeup: Show wakeup sources statistics in debugfs PM: Introduce library for device-specific OPPs (v7) PM: Add sysfs attr for rechecking dev hash from PM trace PM: Lock PM device list mutex in show_dev_hash() PM / Runtime: Remove idle notification after failing suspend PM / Hibernate: Modify signature used to mark swap PM / Runtime: Reduce code duplication in core helper functions PM: Allow wakeup events to abort freezing of tasks PM: runtime: add missed pm_request_autosuspend PM / Hibernate: Make some boot messages look less scary PM / Runtime: Implement autosuspend support PM / Runtime: Add no_callbacks flag PM / Runtime: Combine runtime PM entry points PM / Runtime: Merge synchronous and async runtime routines PM / Runtime: Replace boolean arguments with bitflags PM / Runtime: Move code in drivers/base/power/runtime.c sysfs: Add sysfs_merge_group() and sysfs_unmerge_group() PM: Fix potential issue with failing asynchronous suspend PM / Wakeup: Introduce wakeup source objects and event statistics (v3) PM: Fix signed/unsigned warning in dpm_show_time() ...
This commit is contained in:
commit
a8cbf22559
33 changed files with 3447 additions and 635 deletions
|
|
@ -86,6 +86,7 @@ config PM_SLEEP_SMP
|
|||
depends on SMP
|
||||
depends on ARCH_SUSPEND_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
|
||||
depends on PM_SLEEP
|
||||
select HOTPLUG
|
||||
select HOTPLUG_CPU
|
||||
default y
|
||||
|
||||
|
|
@ -137,6 +138,8 @@ config SUSPEND_FREEZER
|
|||
config HIBERNATION
|
||||
bool "Hibernation (aka 'suspend to disk')"
|
||||
depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
|
||||
select LZO_COMPRESS
|
||||
select LZO_DECOMPRESS
|
||||
select SUSPEND_NVS if HAS_IOMEM
|
||||
---help---
|
||||
Enable the suspend to disk (STD) functionality, which is usually
|
||||
|
|
@ -242,3 +245,17 @@ config PM_OPS
|
|||
bool
|
||||
depends on PM_SLEEP || PM_RUNTIME
|
||||
default y
|
||||
|
||||
config PM_OPP
|
||||
bool "Operating Performance Point (OPP) Layer library"
|
||||
depends on PM
|
||||
---help---
|
||||
SOCs have a standard set of tuples consisting of frequency and
|
||||
voltage pairs that the device will support per voltage domain. This
|
||||
is called Operating Performance Point or OPP. The actual definitions
|
||||
of OPP varies over silicon within the same family of devices.
|
||||
|
||||
OPP layer organizes the data internally using device pointers
|
||||
representing individual voltage domains and provides SOC
|
||||
implementations a ready to use framework to manage OPPs.
|
||||
For more information, read <file:Documentation/power/opp.txt>
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "power.h"
|
||||
|
||||
|
||||
static int nocompress = 0;
|
||||
static int noresume = 0;
|
||||
static char resume_file[256] = CONFIG_PM_STD_PARTITION;
|
||||
dev_t swsusp_resume_device;
|
||||
|
|
@ -638,6 +639,8 @@ int hibernate(void)
|
|||
|
||||
if (hibernation_mode == HIBERNATION_PLATFORM)
|
||||
flags |= SF_PLATFORM_MODE;
|
||||
if (nocompress)
|
||||
flags |= SF_NOCOMPRESS_MODE;
|
||||
pr_debug("PM: writing image.\n");
|
||||
error = swsusp_write(flags);
|
||||
swsusp_free();
|
||||
|
|
@ -705,7 +708,7 @@ static int software_resume(void)
|
|||
goto Unlock;
|
||||
}
|
||||
|
||||
pr_debug("PM: Checking image partition %s\n", resume_file);
|
||||
pr_debug("PM: Checking hibernation image partition %s\n", resume_file);
|
||||
|
||||
/* Check if the device is there */
|
||||
swsusp_resume_device = name_to_dev_t(resume_file);
|
||||
|
|
@ -730,10 +733,10 @@ static int software_resume(void)
|
|||
}
|
||||
|
||||
Check_image:
|
||||
pr_debug("PM: Resume from partition %d:%d\n",
|
||||
pr_debug("PM: Hibernation image partition %d:%d present\n",
|
||||
MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
|
||||
|
||||
pr_debug("PM: Checking hibernation image.\n");
|
||||
pr_debug("PM: Looking for hibernation image.\n");
|
||||
error = swsusp_check();
|
||||
if (error)
|
||||
goto Unlock;
|
||||
|
|
@ -765,14 +768,14 @@ static int software_resume(void)
|
|||
goto Done;
|
||||
}
|
||||
|
||||
pr_debug("PM: Reading hibernation image.\n");
|
||||
pr_debug("PM: Loading hibernation image.\n");
|
||||
|
||||
error = swsusp_read(&flags);
|
||||
swsusp_close(FMODE_READ);
|
||||
if (!error)
|
||||
hibernation_restore(flags & SF_PLATFORM_MODE);
|
||||
|
||||
printk(KERN_ERR "PM: Restore failed, recovering.\n");
|
||||
printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n");
|
||||
swsusp_free();
|
||||
thaw_processes();
|
||||
Done:
|
||||
|
|
@ -785,7 +788,7 @@ static int software_resume(void)
|
|||
/* For success case, the suspend path will release the lock */
|
||||
Unlock:
|
||||
mutex_unlock(&pm_mutex);
|
||||
pr_debug("PM: Resume from disk failed.\n");
|
||||
pr_debug("PM: Hibernation image not present or could not be loaded.\n");
|
||||
return error;
|
||||
close_finish:
|
||||
swsusp_close(FMODE_READ);
|
||||
|
|
@ -1004,6 +1007,15 @@ static int __init resume_offset_setup(char *str)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int __init hibernate_setup(char *str)
|
||||
{
|
||||
if (!strncmp(str, "noresume", 8))
|
||||
noresume = 1;
|
||||
else if (!strncmp(str, "nocompress", 10))
|
||||
nocompress = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __init noresume_setup(char *str)
|
||||
{
|
||||
noresume = 1;
|
||||
|
|
@ -1013,3 +1025,4 @@ static int __init noresume_setup(char *str)
|
|||
__setup("noresume", noresume_setup);
|
||||
__setup("resume_offset=", resume_offset_setup);
|
||||
__setup("resume=", resume_setup);
|
||||
__setup("hibernate=", hibernate_setup);
|
||||
|
|
|
|||
|
|
@ -237,18 +237,18 @@ static ssize_t wakeup_count_show(struct kobject *kobj,
|
|||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
unsigned long val;
|
||||
unsigned int val;
|
||||
|
||||
return pm_get_wakeup_count(&val) ? sprintf(buf, "%lu\n", val) : -EINTR;
|
||||
return pm_get_wakeup_count(&val) ? sprintf(buf, "%u\n", val) : -EINTR;
|
||||
}
|
||||
|
||||
static ssize_t wakeup_count_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t n)
|
||||
{
|
||||
unsigned long val;
|
||||
unsigned int val;
|
||||
|
||||
if (sscanf(buf, "%lu", &val) == 1) {
|
||||
if (sscanf(buf, "%u", &val) == 1) {
|
||||
if (pm_save_wakeup_count(val))
|
||||
return n;
|
||||
}
|
||||
|
|
@ -281,12 +281,30 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
|
|||
}
|
||||
|
||||
power_attr(pm_trace);
|
||||
|
||||
static ssize_t pm_trace_dev_match_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return show_trace_dev_match(buf, PAGE_SIZE);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
pm_trace_dev_match_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t n)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
power_attr(pm_trace_dev_match);
|
||||
|
||||
#endif /* CONFIG_PM_TRACE */
|
||||
|
||||
static struct attribute * g[] = {
|
||||
&state_attr.attr,
|
||||
#ifdef CONFIG_PM_TRACE
|
||||
&pm_trace_attr.attr,
|
||||
&pm_trace_dev_match_attr.attr,
|
||||
#endif
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
&pm_async_attr.attr,
|
||||
|
|
@ -308,7 +326,7 @@ EXPORT_SYMBOL_GPL(pm_wq);
|
|||
|
||||
static int __init pm_start_workqueue(void)
|
||||
{
|
||||
pm_wq = create_freezeable_workqueue("pm");
|
||||
pm_wq = alloc_workqueue("pm", WQ_FREEZEABLE, 0);
|
||||
|
||||
return pm_wq ? 0 : -ENOMEM;
|
||||
}
|
||||
|
|
@ -321,6 +339,7 @@ static int __init pm_init(void)
|
|||
int error = pm_start_workqueue();
|
||||
if (error)
|
||||
return error;
|
||||
hibernate_image_size_init();
|
||||
power_kobj = kobject_create_and_add("power", NULL);
|
||||
if (!power_kobj)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ struct swsusp_info {
|
|||
} __attribute__((aligned(PAGE_SIZE)));
|
||||
|
||||
#ifdef CONFIG_HIBERNATION
|
||||
/* kernel/power/snapshot.c */
|
||||
extern void __init hibernate_image_size_init(void);
|
||||
|
||||
#ifdef CONFIG_ARCH_HIBERNATION_HEADER
|
||||
/* Maximum size of architecture specific data in a hibernation header */
|
||||
#define MAX_ARCH_HEADER_SIZE (sizeof(struct new_utsname) + 4)
|
||||
|
|
@ -49,7 +52,11 @@ static inline char *check_image_kernel(struct swsusp_info *info)
|
|||
extern int hibernation_snapshot(int platform_mode);
|
||||
extern int hibernation_restore(int platform_mode);
|
||||
extern int hibernation_platform_enter(void);
|
||||
#endif
|
||||
|
||||
#else /* !CONFIG_HIBERNATION */
|
||||
|
||||
static inline void hibernate_image_size_init(void) {}
|
||||
#endif /* !CONFIG_HIBERNATION */
|
||||
|
||||
extern int pfn_is_nosave(unsigned long);
|
||||
|
||||
|
|
@ -134,6 +141,7 @@ extern int swsusp_swap_in_use(void);
|
|||
* the image header.
|
||||
*/
|
||||
#define SF_PLATFORM_MODE 1
|
||||
#define SF_NOCOMPRESS_MODE 2
|
||||
|
||||
/* kernel/power/hibernate.c */
|
||||
extern int swsusp_check(void);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ static int try_to_freeze_tasks(bool sig_only)
|
|||
struct timeval start, end;
|
||||
u64 elapsed_csecs64;
|
||||
unsigned int elapsed_csecs;
|
||||
bool wakeup = false;
|
||||
|
||||
do_gettimeofday(&start);
|
||||
|
||||
|
|
@ -78,6 +79,11 @@ static int try_to_freeze_tasks(bool sig_only)
|
|||
if (!todo || time_after(jiffies, end_time))
|
||||
break;
|
||||
|
||||
if (!pm_check_wakeup_events()) {
|
||||
wakeup = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to retry, but first give the freezing tasks some
|
||||
* time to enter the regrigerator.
|
||||
|
|
@ -97,8 +103,9 @@ static int try_to_freeze_tasks(bool sig_only)
|
|||
* but it cleans up leftover PF_FREEZE requests.
|
||||
*/
|
||||
printk("\n");
|
||||
printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "
|
||||
printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds "
|
||||
"(%d tasks refusing to freeze, wq_busy=%d):\n",
|
||||
wakeup ? "aborted" : "failed",
|
||||
elapsed_csecs / 100, elapsed_csecs % 100,
|
||||
todo - wq_busy, wq_busy);
|
||||
|
||||
|
|
@ -107,7 +114,7 @@ static int try_to_freeze_tasks(bool sig_only)
|
|||
read_lock(&tasklist_lock);
|
||||
do_each_thread(g, p) {
|
||||
task_lock(p);
|
||||
if (freezing(p) && !freezer_should_skip(p))
|
||||
if (!wakeup && freezing(p) && !freezer_should_skip(p))
|
||||
sched_show_task(p);
|
||||
cancel_freezing(p);
|
||||
task_unlock(p);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,12 @@ static void swsusp_unset_page_forbidden(struct page *);
|
|||
* size will not exceed N bytes, but if that is impossible, it will
|
||||
* try to create the smallest image possible.
|
||||
*/
|
||||
unsigned long image_size = 500 * 1024 * 1024;
|
||||
unsigned long image_size;
|
||||
|
||||
void __init hibernate_image_size_init(void)
|
||||
{
|
||||
image_size = ((totalram_pages * 2) / 5) * PAGE_SIZE;
|
||||
}
|
||||
|
||||
/* List of PBEs needed for restoring the pages that were allocated before
|
||||
* the suspend and included in the suspend image, but have also been
|
||||
|
|
@ -1318,12 +1323,14 @@ int hibernate_preallocate_memory(void)
|
|||
|
||||
/* Compute the maximum number of saveable pages to leave in memory. */
|
||||
max_size = (count - (size + PAGES_FOR_IO)) / 2 - 2 * SPARE_PAGES;
|
||||
/* Compute the desired number of image pages specified by image_size. */
|
||||
size = DIV_ROUND_UP(image_size, PAGE_SIZE);
|
||||
if (size > max_size)
|
||||
size = max_size;
|
||||
/*
|
||||
* If the maximum is not less than the current number of saveable pages
|
||||
* in memory, allocate page frames for the image and we're done.
|
||||
* If the desired number of image pages is at least as large as the
|
||||
* current number of saveable pages in memory, allocate page frames for
|
||||
* the image and we're done.
|
||||
*/
|
||||
if (size >= saveable) {
|
||||
pages = preallocate_image_highmem(save_highmem);
|
||||
|
|
|
|||
|
|
@ -24,10 +24,12 @@
|
|||
#include <linux/swapops.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/lzo.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "power.h"
|
||||
|
||||
#define SWSUSP_SIG "S1SUSPEND"
|
||||
#define HIBERNATE_SIG "LINHIB0001"
|
||||
|
||||
/*
|
||||
* The swap map is a data structure used for keeping track of each page
|
||||
|
|
@ -193,7 +195,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
|
|||
if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) ||
|
||||
!memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
|
||||
memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
|
||||
memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
|
||||
memcpy(swsusp_header->sig, HIBERNATE_SIG, 10);
|
||||
swsusp_header->image = handle->first_sector;
|
||||
swsusp_header->flags = flags;
|
||||
error = hib_bio_write_page(swsusp_resume_block,
|
||||
|
|
@ -357,6 +359,18 @@ static int swap_writer_finish(struct swap_map_handle *handle,
|
|||
return error;
|
||||
}
|
||||
|
||||
/* We need to remember how much compressed data we need to read. */
|
||||
#define LZO_HEADER sizeof(size_t)
|
||||
|
||||
/* Number of pages/bytes we'll compress at one time. */
|
||||
#define LZO_UNC_PAGES 32
|
||||
#define LZO_UNC_SIZE (LZO_UNC_PAGES * PAGE_SIZE)
|
||||
|
||||
/* Number of pages/bytes we need for compressed data (worst case). */
|
||||
#define LZO_CMP_PAGES DIV_ROUND_UP(lzo1x_worst_compress(LZO_UNC_SIZE) + \
|
||||
LZO_HEADER, PAGE_SIZE)
|
||||
#define LZO_CMP_SIZE (LZO_CMP_PAGES * PAGE_SIZE)
|
||||
|
||||
/**
|
||||
* save_image - save the suspend image data
|
||||
*/
|
||||
|
|
@ -404,6 +418,137 @@ static int save_image(struct swap_map_handle *handle,
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* save_image_lzo - Save the suspend image data compressed with LZO.
|
||||
* @handle: Swap mam handle to use for saving the image.
|
||||
* @snapshot: Image to read data from.
|
||||
* @nr_to_write: Number of pages to save.
|
||||
*/
|
||||
static int save_image_lzo(struct swap_map_handle *handle,
|
||||
struct snapshot_handle *snapshot,
|
||||
unsigned int nr_to_write)
|
||||
{
|
||||
unsigned int m;
|
||||
int ret = 0;
|
||||
int nr_pages;
|
||||
int err2;
|
||||
struct bio *bio;
|
||||
struct timeval start;
|
||||
struct timeval stop;
|
||||
size_t off, unc_len, cmp_len;
|
||||
unsigned char *unc, *cmp, *wrk, *page;
|
||||
|
||||
page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
|
||||
if (!page) {
|
||||
printk(KERN_ERR "PM: Failed to allocate LZO page\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wrk = vmalloc(LZO1X_1_MEM_COMPRESS);
|
||||
if (!wrk) {
|
||||
printk(KERN_ERR "PM: Failed to allocate LZO workspace\n");
|
||||
free_page((unsigned long)page);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
unc = vmalloc(LZO_UNC_SIZE);
|
||||
if (!unc) {
|
||||
printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");
|
||||
vfree(wrk);
|
||||
free_page((unsigned long)page);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cmp = vmalloc(LZO_CMP_SIZE);
|
||||
if (!cmp) {
|
||||
printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");
|
||||
vfree(unc);
|
||||
vfree(wrk);
|
||||
free_page((unsigned long)page);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
printk(KERN_INFO
|
||||
"PM: Compressing and saving image data (%u pages) ... ",
|
||||
nr_to_write);
|
||||
m = nr_to_write / 100;
|
||||
if (!m)
|
||||
m = 1;
|
||||
nr_pages = 0;
|
||||
bio = NULL;
|
||||
do_gettimeofday(&start);
|
||||
for (;;) {
|
||||
for (off = 0; off < LZO_UNC_SIZE; off += PAGE_SIZE) {
|
||||
ret = snapshot_read_next(snapshot);
|
||||
if (ret < 0)
|
||||
goto out_finish;
|
||||
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
memcpy(unc + off, data_of(*snapshot), PAGE_SIZE);
|
||||
|
||||
if (!(nr_pages % m))
|
||||
printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
|
||||
nr_pages++;
|
||||
}
|
||||
|
||||
if (!off)
|
||||
break;
|
||||
|
||||
unc_len = off;
|
||||
ret = lzo1x_1_compress(unc, unc_len,
|
||||
cmp + LZO_HEADER, &cmp_len, wrk);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "PM: LZO compression failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(!cmp_len ||
|
||||
cmp_len > lzo1x_worst_compress(unc_len))) {
|
||||
printk(KERN_ERR "PM: Invalid LZO compressed length\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
*(size_t *)cmp = cmp_len;
|
||||
|
||||
/*
|
||||
* Given we are writing one page at a time to disk, we copy
|
||||
* that much from the buffer, although the last bit will likely
|
||||
* be smaller than full page. This is OK - we saved the length
|
||||
* of the compressed data, so any garbage at the end will be
|
||||
* discarded when we read it.
|
||||
*/
|
||||
for (off = 0; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) {
|
||||
memcpy(page, cmp + off, PAGE_SIZE);
|
||||
|
||||
ret = swap_write_page(handle, page, &bio);
|
||||
if (ret)
|
||||
goto out_finish;
|
||||
}
|
||||
}
|
||||
|
||||
out_finish:
|
||||
err2 = hib_wait_on_bio_chain(&bio);
|
||||
do_gettimeofday(&stop);
|
||||
if (!ret)
|
||||
ret = err2;
|
||||
if (!ret)
|
||||
printk(KERN_CONT "\b\b\b\bdone\n");
|
||||
else
|
||||
printk(KERN_CONT "\n");
|
||||
swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
|
||||
|
||||
vfree(cmp);
|
||||
vfree(unc);
|
||||
vfree(wrk);
|
||||
free_page((unsigned long)page);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* enough_swap - Make sure we have enough swap to save the image.
|
||||
*
|
||||
|
|
@ -411,12 +556,16 @@ static int save_image(struct swap_map_handle *handle,
|
|||
* space avaiable from the resume partition.
|
||||
*/
|
||||
|
||||
static int enough_swap(unsigned int nr_pages)
|
||||
static int enough_swap(unsigned int nr_pages, unsigned int flags)
|
||||
{
|
||||
unsigned int free_swap = count_swap_pages(root_swap, 1);
|
||||
unsigned int required;
|
||||
|
||||
pr_debug("PM: Free swap pages: %u\n", free_swap);
|
||||
return free_swap > nr_pages + PAGES_FOR_IO;
|
||||
|
||||
required = PAGES_FOR_IO + ((flags & SF_NOCOMPRESS_MODE) ?
|
||||
nr_pages : (nr_pages * LZO_CMP_PAGES) / LZO_UNC_PAGES + 1);
|
||||
return free_swap > required;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -443,7 +592,7 @@ int swsusp_write(unsigned int flags)
|
|||
printk(KERN_ERR "PM: Cannot get swap writer\n");
|
||||
return error;
|
||||
}
|
||||
if (!enough_swap(pages)) {
|
||||
if (!enough_swap(pages, flags)) {
|
||||
printk(KERN_ERR "PM: Not enough free swap\n");
|
||||
error = -ENOSPC;
|
||||
goto out_finish;
|
||||
|
|
@ -458,8 +607,11 @@ int swsusp_write(unsigned int flags)
|
|||
}
|
||||
header = (struct swsusp_info *)data_of(snapshot);
|
||||
error = swap_write_page(&handle, header, NULL);
|
||||
if (!error)
|
||||
error = save_image(&handle, &snapshot, pages - 1);
|
||||
if (!error) {
|
||||
error = (flags & SF_NOCOMPRESS_MODE) ?
|
||||
save_image(&handle, &snapshot, pages - 1) :
|
||||
save_image_lzo(&handle, &snapshot, pages - 1);
|
||||
}
|
||||
out_finish:
|
||||
error = swap_writer_finish(&handle, flags, error);
|
||||
return error;
|
||||
|
|
@ -589,6 +741,127 @@ static int load_image(struct swap_map_handle *handle,
|
|||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* load_image_lzo - Load compressed image data and decompress them with LZO.
|
||||
* @handle: Swap map handle to use for loading data.
|
||||
* @snapshot: Image to copy uncompressed data into.
|
||||
* @nr_to_read: Number of pages to load.
|
||||
*/
|
||||
static int load_image_lzo(struct swap_map_handle *handle,
|
||||
struct snapshot_handle *snapshot,
|
||||
unsigned int nr_to_read)
|
||||
{
|
||||
unsigned int m;
|
||||
int error = 0;
|
||||
struct timeval start;
|
||||
struct timeval stop;
|
||||
unsigned nr_pages;
|
||||
size_t off, unc_len, cmp_len;
|
||||
unsigned char *unc, *cmp, *page;
|
||||
|
||||
page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
|
||||
if (!page) {
|
||||
printk(KERN_ERR "PM: Failed to allocate LZO page\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
unc = vmalloc(LZO_UNC_SIZE);
|
||||
if (!unc) {
|
||||
printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");
|
||||
free_page((unsigned long)page);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cmp = vmalloc(LZO_CMP_SIZE);
|
||||
if (!cmp) {
|
||||
printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");
|
||||
vfree(unc);
|
||||
free_page((unsigned long)page);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
printk(KERN_INFO
|
||||
"PM: Loading and decompressing image data (%u pages) ... ",
|
||||
nr_to_read);
|
||||
m = nr_to_read / 100;
|
||||
if (!m)
|
||||
m = 1;
|
||||
nr_pages = 0;
|
||||
do_gettimeofday(&start);
|
||||
|
||||
error = snapshot_write_next(snapshot);
|
||||
if (error <= 0)
|
||||
goto out_finish;
|
||||
|
||||
for (;;) {
|
||||
error = swap_read_page(handle, page, NULL); /* sync */
|
||||
if (error)
|
||||
break;
|
||||
|
||||
cmp_len = *(size_t *)page;
|
||||
if (unlikely(!cmp_len ||
|
||||
cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) {
|
||||
printk(KERN_ERR "PM: Invalid LZO compressed length\n");
|
||||
error = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(cmp, page, PAGE_SIZE);
|
||||
for (off = PAGE_SIZE; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) {
|
||||
error = swap_read_page(handle, page, NULL); /* sync */
|
||||
if (error)
|
||||
goto out_finish;
|
||||
|
||||
memcpy(cmp + off, page, PAGE_SIZE);
|
||||
}
|
||||
|
||||
unc_len = LZO_UNC_SIZE;
|
||||
error = lzo1x_decompress_safe(cmp + LZO_HEADER, cmp_len,
|
||||
unc, &unc_len);
|
||||
if (error < 0) {
|
||||
printk(KERN_ERR "PM: LZO decompression failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(!unc_len ||
|
||||
unc_len > LZO_UNC_SIZE ||
|
||||
unc_len & (PAGE_SIZE - 1))) {
|
||||
printk(KERN_ERR "PM: Invalid LZO uncompressed length\n");
|
||||
error = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (off = 0; off < unc_len; off += PAGE_SIZE) {
|
||||
memcpy(data_of(*snapshot), unc + off, PAGE_SIZE);
|
||||
|
||||
if (!(nr_pages % m))
|
||||
printk("\b\b\b\b%3d%%", nr_pages / m);
|
||||
nr_pages++;
|
||||
|
||||
error = snapshot_write_next(snapshot);
|
||||
if (error <= 0)
|
||||
goto out_finish;
|
||||
}
|
||||
}
|
||||
|
||||
out_finish:
|
||||
do_gettimeofday(&stop);
|
||||
if (!error) {
|
||||
printk("\b\b\b\bdone\n");
|
||||
snapshot_write_finalize(snapshot);
|
||||
if (!snapshot_image_loaded(snapshot))
|
||||
error = -ENODATA;
|
||||
} else
|
||||
printk("\n");
|
||||
swsusp_show_speed(&start, &stop, nr_to_read, "Read");
|
||||
|
||||
vfree(cmp);
|
||||
vfree(unc);
|
||||
free_page((unsigned long)page);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* swsusp_read - read the hibernation image.
|
||||
* @flags_p: flags passed by the "frozen" kernel in the image header should
|
||||
|
|
@ -612,8 +885,11 @@ int swsusp_read(unsigned int *flags_p)
|
|||
goto end;
|
||||
if (!error)
|
||||
error = swap_read_page(&handle, header, NULL);
|
||||
if (!error)
|
||||
error = load_image(&handle, &snapshot, header->pages - 1);
|
||||
if (!error) {
|
||||
error = (*flags_p & SF_NOCOMPRESS_MODE) ?
|
||||
load_image(&handle, &snapshot, header->pages - 1) :
|
||||
load_image_lzo(&handle, &snapshot, header->pages - 1);
|
||||
}
|
||||
swap_reader_finish(&handle);
|
||||
end:
|
||||
if (!error)
|
||||
|
|
@ -640,7 +916,7 @@ int swsusp_check(void)
|
|||
if (error)
|
||||
goto put;
|
||||
|
||||
if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) {
|
||||
if (!memcmp(HIBERNATE_SIG, swsusp_header->sig, 10)) {
|
||||
memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
|
||||
/* Reset swap signature now */
|
||||
error = hib_bio_write_page(swsusp_resume_block,
|
||||
|
|
@ -653,13 +929,13 @@ put:
|
|||
if (error)
|
||||
blkdev_put(hib_resume_bdev, FMODE_READ);
|
||||
else
|
||||
pr_debug("PM: Signature found, resuming\n");
|
||||
pr_debug("PM: Image signature found, resuming\n");
|
||||
} else {
|
||||
error = PTR_ERR(hib_resume_bdev);
|
||||
}
|
||||
|
||||
if (error)
|
||||
pr_debug("PM: Error %d checking image file\n", error);
|
||||
pr_debug("PM: Image not found (code %d)\n", error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue