Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7787d2c2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'pm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6:
  PM / Hibernate: Fix memory corruption related to swap
  PM / Hibernate: Use async I/O when reading compressed hibernation image
parents 60658f8a c9e664f1
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -360,7 +360,7 @@ void drain_local_pages(void *dummy);

extern gfp_t gfp_allowed_mask;

extern void set_gfp_allowed_mask(gfp_t mask);
extern gfp_t clear_gfp_allowed_mask(gfp_t mask);
extern void pm_restrict_gfp_mask(void);
extern void pm_restore_gfp_mask(void);

#endif /* __LINUX_GFP_H */
+12 −10
Original line number Diff line number Diff line
@@ -327,7 +327,6 @@ static int create_image(int platform_mode)
int hibernation_snapshot(int platform_mode)
{
	int error;
	gfp_t saved_mask;

	error = platform_begin(platform_mode);
	if (error)
@@ -339,7 +338,7 @@ int hibernation_snapshot(int platform_mode)
		goto Close;

	suspend_console();
	saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
	pm_restrict_gfp_mask();
	error = dpm_suspend_start(PMSG_FREEZE);
	if (error)
		goto Recover_platform;
@@ -348,7 +347,10 @@ int hibernation_snapshot(int platform_mode)
		goto Recover_platform;

	error = create_image(platform_mode);
	/* Control returns here after successful restore */
	/*
	 * Control returns here (1) after the image has been created or the
	 * image creation has failed and (2) after a successful restore.
	 */

 Resume_devices:
	/* We may need to release the preallocated image pages here. */
@@ -357,7 +359,10 @@ int hibernation_snapshot(int platform_mode)

	dpm_resume_end(in_suspend ?
		(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
	set_gfp_allowed_mask(saved_mask);

	if (error || !in_suspend)
		pm_restore_gfp_mask();

	resume_console();
 Close:
	platform_end(platform_mode);
@@ -452,17 +457,16 @@ static int resume_target_kernel(bool platform_mode)
int hibernation_restore(int platform_mode)
{
	int error;
	gfp_t saved_mask;

	pm_prepare_console();
	suspend_console();
	saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
	pm_restrict_gfp_mask();
	error = dpm_suspend_start(PMSG_QUIESCE);
	if (!error) {
		error = resume_target_kernel(platform_mode);
		dpm_resume_end(PMSG_RECOVER);
	}
	set_gfp_allowed_mask(saved_mask);
	pm_restore_gfp_mask();
	resume_console();
	pm_restore_console();
	return error;
@@ -476,7 +480,6 @@ int hibernation_restore(int platform_mode)
int hibernation_platform_enter(void)
{
	int error;
	gfp_t saved_mask;

	if (!hibernation_ops)
		return -ENOSYS;
@@ -492,7 +495,6 @@ int hibernation_platform_enter(void)

	entering_platform_hibernation = true;
	suspend_console();
	saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
	error = dpm_suspend_start(PMSG_HIBERNATE);
	if (error) {
		if (hibernation_ops->recover)
@@ -536,7 +538,6 @@ int hibernation_platform_enter(void)
 Resume_devices:
	entering_platform_hibernation = false;
	dpm_resume_end(PMSG_RESTORE);
	set_gfp_allowed_mask(saved_mask);
	resume_console();

 Close:
@@ -646,6 +647,7 @@ int hibernate(void)
		swsusp_free();
		if (!error)
			power_down();
		pm_restore_gfp_mask();
	} else {
		pr_debug("PM: Image restored successfully.\n");
	}
+2 −3
Original line number Diff line number Diff line
@@ -197,7 +197,6 @@ static int suspend_enter(suspend_state_t state)
int suspend_devices_and_enter(suspend_state_t state)
{
	int error;
	gfp_t saved_mask;

	if (!suspend_ops)
		return -ENOSYS;
@@ -208,7 +207,7 @@ int suspend_devices_and_enter(suspend_state_t state)
			goto Close;
	}
	suspend_console();
	saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
	pm_restrict_gfp_mask();
	suspend_test_start();
	error = dpm_suspend_start(PMSG_SUSPEND);
	if (error) {
@@ -225,7 +224,7 @@ int suspend_devices_and_enter(suspend_state_t state)
	suspend_test_start();
	dpm_resume_end(PMSG_RESUME);
	suspend_test_finish("resume devices");
	set_gfp_allowed_mask(saved_mask);
	pm_restore_gfp_mask();
	resume_console();
 Close:
	if (suspend_ops->end)
+38 −15
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
 *
 * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
 * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
 * Copyright (C) 2010 Bojan Smojver <bojan@rexursive.com>
 *
 * This file is released under the GPLv2.
 *
@@ -753,30 +754,43 @@ static int load_image_lzo(struct swap_map_handle *handle,
{
	unsigned int m;
	int error = 0;
	struct bio *bio;
	struct timeval start;
	struct timeval stop;
	unsigned nr_pages;
	size_t off, unc_len, cmp_len;
	unsigned char *unc, *cmp, *page;
	size_t i, off, unc_len, cmp_len;
	unsigned char *unc, *cmp, *page[LZO_CMP_PAGES];

	page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
	if (!page) {
	for (i = 0; i < LZO_CMP_PAGES; i++) {
		page[i] = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
		if (!page[i]) {
			printk(KERN_ERR "PM: Failed to allocate LZO page\n");

			while (i)
				free_page((unsigned long)page[--i]);

			return -ENOMEM;
		}
	}

	unc = vmalloc(LZO_UNC_SIZE);
	if (!unc) {
		printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");
		free_page((unsigned long)page);

		for (i = 0; i < LZO_CMP_PAGES; i++)
			free_page((unsigned long)page[i]);

		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);
		for (i = 0; i < LZO_CMP_PAGES; i++)
			free_page((unsigned long)page[i]);

		return -ENOMEM;
	}

@@ -787,6 +801,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
	if (!m)
		m = 1;
	nr_pages = 0;
	bio = NULL;
	do_gettimeofday(&start);

	error = snapshot_write_next(snapshot);
@@ -794,11 +809,11 @@ static int load_image_lzo(struct swap_map_handle *handle,
		goto out_finish;

	for (;;) {
		error = swap_read_page(handle, page, NULL); /* sync */
		error = swap_read_page(handle, page[0], NULL); /* sync */
		if (error)
			break;

		cmp_len = *(size_t *)page;
		cmp_len = *(size_t *)page[0];
		if (unlikely(!cmp_len ||
		             cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) {
			printk(KERN_ERR "PM: Invalid LZO compressed length\n");
@@ -806,13 +821,20 @@ static int load_image_lzo(struct swap_map_handle *handle,
			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 */
		for (off = PAGE_SIZE, i = 1;
		     off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
			error = swap_read_page(handle, page[i], &bio);
			if (error)
				goto out_finish;
		}

			memcpy(cmp + off, page, PAGE_SIZE);
		error = hib_wait_on_bio_chain(&bio); /* need all data now */
		if (error)
			goto out_finish;

		for (off = 0, i = 0;
		     off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
			memcpy(cmp + off, page[i], PAGE_SIZE);
		}

		unc_len = LZO_UNC_SIZE;
@@ -857,7 +879,8 @@ out_finish:

	vfree(cmp);
	vfree(unc);
	free_page((unsigned long)page);
	for (i = 0; i < LZO_CMP_PAGES; i++)
		free_page((unsigned long)page[i]);

	return error;
}
+2 −0
Original line number Diff line number Diff line
@@ -263,6 +263,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
	case SNAPSHOT_UNFREEZE:
		if (!data->frozen || data->ready)
			break;
		pm_restore_gfp_mask();
		thaw_processes();
		usermodehelper_enable();
		data->frozen = 0;
@@ -275,6 +276,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
			error = -EPERM;
			break;
		}
		pm_restore_gfp_mask();
		error = hibernation_snapshot(data->platform_support);
		if (!error)
			error = put_user(in_suspend, (int __user *)arg);
Loading