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 Original line Diff line number Diff line
@@ -360,7 +360,7 @@ void drain_local_pages(void *dummy);


extern gfp_t gfp_allowed_mask;
extern gfp_t gfp_allowed_mask;


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


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


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


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


	error = create_image(platform_mode);
	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:
 Resume_devices:
	/* We may need to release the preallocated image pages here. */
	/* 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 ?
	dpm_resume_end(in_suspend ?
		(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
		(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
	set_gfp_allowed_mask(saved_mask);

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

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


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


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


	entering_platform_hibernation = true;
	entering_platform_hibernation = true;
	suspend_console();
	suspend_console();
	saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
	error = dpm_suspend_start(PMSG_HIBERNATE);
	error = dpm_suspend_start(PMSG_HIBERNATE);
	if (error) {
	if (error) {
		if (hibernation_ops->recover)
		if (hibernation_ops->recover)
@@ -536,7 +538,6 @@ 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);
	set_gfp_allowed_mask(saved_mask);
	resume_console();
	resume_console();


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


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


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

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

			return -ENOMEM;
			return -ENOMEM;
		}
		}
	}


	unc = vmalloc(LZO_UNC_SIZE);
	unc = vmalloc(LZO_UNC_SIZE);
	if (!unc) {
	if (!unc) {
		printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");
		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;
		return -ENOMEM;
	}
	}


	cmp = vmalloc(LZO_CMP_SIZE);
	cmp = vmalloc(LZO_CMP_SIZE);
	if (!cmp) {
	if (!cmp) {
		printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");
		printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");

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

		return -ENOMEM;
		return -ENOMEM;
	}
	}


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


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


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


		cmp_len = *(size_t *)page;
		cmp_len = *(size_t *)page[0];
		if (unlikely(!cmp_len ||
		if (unlikely(!cmp_len ||
		             cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) {
		             cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) {
			printk(KERN_ERR "PM: Invalid LZO compressed length\n");
			printk(KERN_ERR "PM: Invalid LZO compressed length\n");
@@ -806,13 +821,20 @@ static int load_image_lzo(struct swap_map_handle *handle,
			break;
			break;
		}
		}


		memcpy(cmp, page, PAGE_SIZE);
		for (off = PAGE_SIZE, i = 1;
		for (off = PAGE_SIZE; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) {
		     off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
			error = swap_read_page(handle, page, NULL); /* sync */
			error = swap_read_page(handle, page[i], &bio);
			if (error)
			if (error)
				goto out_finish;
				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;
		unc_len = LZO_UNC_SIZE;
@@ -857,7 +879,8 @@ static int load_image_lzo(struct swap_map_handle *handle,


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


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