History

Merge branch 'pm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6

* '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

Linus Torvalds committed 15 years ago

Commit 7787d2c2 parents 60658f8 c9e664f6 files · +68 −37Browse files

Unified · Split

6 files
  1. include/linux/gfp.h +2 −2
  2. kernel/power/hibernate.c +12 −10
  3. kernel/power/suspend.c +2 −3
  4. kernel/power/swap.c +38 −15
  5. kernel/power/user.c +2 −0
  6. mm/page_alloc.c +12 −7
include/linux/gfp.h+2−2
@@ -360,7 +360,7 @@ void drain_local_pages(void *dummy); · 359 unmodified lines
360360
361361 extern gfp_t gfp_allowed_mask;
362362
363−extern void set_gfp_allowed_mask(gfp_t mask);
364−extern gfp_t clear_gfp_allowed_mask(gfp_t mask);
363+extern void pm_restrict_gfp_mask(void);
364+extern void pm_restore_gfp_mask(void);
365365
366366 #endif /* __LINUX_GFP_H */
kernel/power/hibernate.c+12−10
@@ -327,7 +327,6 @@ static int create_image(int platform_mode) · 326 unmodified lines
327327 int hibernation_snapshot(int platform_mode)
328328 {
329329 int error;
330− gfp_t saved_mask;
331330
332331 error = platform_begin(platform_mode);
333332 if (error)
@@ -339,7 +338,7 @@ int hibernation_snapshot(int platform_mode) · 5 unmodified lines
339338 goto Close;
340339
341340 suspend_console();
342− saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
341+ pm_restrict_gfp_mask();
343342 error = dpm_suspend_start(PMSG_FREEZE);
344343 if (error)
345344 goto Recover_platform;
@@ -348,7 +347,10 @@ int hibernation_snapshot(int platform_mode) · 2 unmodified lines
348347 goto Recover_platform;
349348
350349 error = create_image(platform_mode);
351− /* Control returns here after successful restore */
350+ /*
351+ * Control returns here (1) after the image has been created or the
352+ * image creation has failed and (2) after a successful restore.
353+ */
352354
353355 Resume_devices:
354356 /* We may need to release the preallocated image pages here. */
@@ -357,7 +359,10 @@ int hibernation_snapshot(int platform_mode) · 2 unmodified lines
357359
358360 dpm_resume_end(in_suspend ?
359361 (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
360− set_gfp_allowed_mask(saved_mask);
362+
363+ if (error || !in_suspend)
364+ pm_restore_gfp_mask();
365+
361366 resume_console();
362367 Close:
363368 platform_end(platform_mode);
@@ -452,17 +457,16 @@ static int resume_target_kernel(bool platform_mode) · 88 unmodified lines
452457 int hibernation_restore(int platform_mode)
453458 {
454459 int error;
455− gfp_t saved_mask;
456460
457461 pm_prepare_console();
458462 suspend_console();
459− saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
463+ pm_restrict_gfp_mask();
460464 error = dpm_suspend_start(PMSG_QUIESCE);
461465 if (!error) {
462466 error = resume_target_kernel(platform_mode);
463467 dpm_resume_end(PMSG_RECOVER);
464468 }
465− set_gfp_allowed_mask(saved_mask);
469+ pm_restore_gfp_mask();
466470 resume_console();
467471 pm_restore_console();
468472 return error;
@@ -476,7 +480,6 @@ int hibernation_restore(int platform_mode) · 7 unmodified lines
476480 int hibernation_platform_enter(void)
477481 {
478482 int error;
479− gfp_t saved_mask;
480483
481484 if (!hibernation_ops)
482485 return -ENOSYS;
@@ -492,7 +495,6 @@ int hibernation_platform_enter(void) · 9 unmodified lines
492495
493496 entering_platform_hibernation = true;
494497 suspend_console();
495− saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
496498 error = dpm_suspend_start(PMSG_HIBERNATE);
497499 if (error) {
498500 if (hibernation_ops->recover)
@@ -536,7 +538,6 @@ int hibernation_platform_enter(void) · 37 unmodified lines
536538 Resume_devices:
537539 entering_platform_hibernation = false;
538540 dpm_resume_end(PMSG_RESTORE);
539− set_gfp_allowed_mask(saved_mask);
540541 resume_console();
541542
542543 Close:
@@ -646,6 +647,7 @@ int hibernate(void) · 103 unmodified lines
646647 swsusp_free();
647648 if (!error)
648649 power_down();
650+ pm_restore_gfp_mask();
649651 } else {
650652 pr_debug("PM: Image restored successfully.\n");
651653 }
kernel/power/suspend.c+2−3
@@ -197,7 +197,6 @@ static int suspend_enter(suspend_state_t state) · 196 unmodified lines
197197 int suspend_devices_and_enter(suspend_state_t state)
198198 {
199199 int error;
200− gfp_t saved_mask;
201200
202201 if (!suspend_ops)
203202 return -ENOSYS;
@@ -208,7 +207,7 @@ int suspend_devices_and_enter(suspend_state_t state) · 4 unmodified lines
208207 goto Close;
209208 }
210209 suspend_console();
211− saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
210+ pm_restrict_gfp_mask();
212211 suspend_test_start();
213212 error = dpm_suspend_start(PMSG_SUSPEND);
214213 if (error) {
@@ -225,7 +224,7 @@ int suspend_devices_and_enter(suspend_state_t state) · 10 unmodified lines
225224 suspend_test_start();
226225 dpm_resume_end(PMSG_RESUME);
227226 suspend_test_finish("resume devices");
228− set_gfp_allowed_mask(saved_mask);
227+ pm_restore_gfp_mask();
229228 resume_console();
230229 Close:
231230 if (suspend_ops->end)
kernel/power/swap.c+38−15
@@ -6,6 +6,7 @@ · 5 unmodified lines
66 *
77 * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
88 * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
9+ * Copyright (C) 2010 Bojan Smojver <bojan@rexursive.com>
910 *
1011 * This file is released under the GPLv2.
1112 *
@@ -753,30 +754,43 @@ static int load_image_lzo(struct swap_map_handle *handle, · 741 unmodified lines
753754 {
754755 unsigned int m;
755756 int error = 0;
757+ struct bio *bio;
756758 struct timeval start;
757759 struct timeval stop;
758760 unsigned nr_pages;
759− size_t off, unc_len, cmp_len;
760− unsigned char *unc, *cmp, *page;
761+ size_t i, off, unc_len, cmp_len;
762+ unsigned char *unc, *cmp, *page[LZO_CMP_PAGES];
761763
762− page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
763− if (!page) {
764− printk(KERN_ERR "PM: Failed to allocate LZO page\n");
765− return -ENOMEM;
764+ for (i = 0; i < LZO_CMP_PAGES; i++) {
765+ page[i] = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
766+ if (!page[i]) {
767+ printk(KERN_ERR "PM: Failed to allocate LZO page\n");
768+
769+ while (i)
770+ free_page((unsigned long)page[--i]);
771+
772+ return -ENOMEM;
773+ }
766774 }
767775
768776 unc = vmalloc(LZO_UNC_SIZE);
769777 if (!unc) {
770778 printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");
771− free_page((unsigned long)page);
779+
780+ for (i = 0; i < LZO_CMP_PAGES; i++)
781+ free_page((unsigned long)page[i]);
782+
772783 return -ENOMEM;
773784 }
774785
775786 cmp = vmalloc(LZO_CMP_SIZE);
776787 if (!cmp) {
777788 printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");
789+
778790 vfree(unc);
779− free_page((unsigned long)page);
791+ for (i = 0; i < LZO_CMP_PAGES; i++)
792+ free_page((unsigned long)page[i]);
793+
780794 return -ENOMEM;
781795 }
782796
@@ -787,6 +801,7 @@ static int load_image_lzo(struct swap_map_handle *handle, · 4 unmodified lines
787801 if (!m)
788802 m = 1;
789803 nr_pages = 0;
804+ bio = NULL;
790805 do_gettimeofday(&start);
791806
792807 error = snapshot_write_next(snapshot);
@@ -794,11 +809,11 @@ static int load_image_lzo(struct swap_map_handle *handle, · 1 unmodified line
794809 goto out_finish;
795810
796811 for (;;) {
797− error = swap_read_page(handle, page, NULL); /* sync */
812+ error = swap_read_page(handle, page[0], NULL); /* sync */
798813 if (error)
799814 break;
800815
801− cmp_len = *(size_t *)page;
816+ cmp_len = *(size_t *)page[0];
802817 if (unlikely(!cmp_len ||
803818 cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) {
804819 printk(KERN_ERR "PM: Invalid LZO compressed length\n");
@@ -806,13 +821,20 @@ static int load_image_lzo(struct swap_map_handle *handle, · 1 unmodified line
806821 break;
807822 }
808823
809− memcpy(cmp, page, PAGE_SIZE);
810− for (off = PAGE_SIZE; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) {
811− error = swap_read_page(handle, page, NULL); /* sync */
824+ for (off = PAGE_SIZE, i = 1;
825+ off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
826+ error = swap_read_page(handle, page[i], &bio);
812827 if (error)
813828 goto out_finish;
829+ }
814830
815− memcpy(cmp + off, page, PAGE_SIZE);
831+ error = hib_wait_on_bio_chain(&bio); /* need all data now */
832+ if (error)
833+ goto out_finish;
834+
835+ for (off = 0, i = 0;
836+ off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
837+ memcpy(cmp + off, page[i], PAGE_SIZE);
816838 }
817839
818840 unc_len = LZO_UNC_SIZE;
@@ -857,7 +879,8 @@ out_finish: · 38 unmodified lines
857879
858880 vfree(cmp);
859881 vfree(unc);
860− free_page((unsigned long)page);
882+ for (i = 0; i < LZO_CMP_PAGES; i++)
883+ free_page((unsigned long)page[i]);
861884
862885 return error;
863886 }
kernel/power/user.c+2−0
@@ -263,6 +263,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, · 262 unmodified lines
263263 case SNAPSHOT_UNFREEZE:
264264 if (!data->frozen || data->ready)
265265 break;
266+ pm_restore_gfp_mask();
266267 thaw_processes();
267268 usermodehelper_enable();
268269 data->frozen = 0;
@@ -275,6 +276,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, · 6 unmodified lines
275276 error = -EPERM;
276277 break;
277278 }
279+ pm_restore_gfp_mask();
278280 error = hibernation_snapshot(data->platform_support);
279281 if (!error)
280282 error = put_user(in_suspend, (int __user *)arg);
mm/page_alloc.c+12−7
@@ -104,19 +104,24 @@ gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK; · 103 unmodified lines
104104 * only be modified with pm_mutex held, unless the suspend/hibernate code is
105105 * guaranteed not to run in parallel with that modification).
106106 */
107−void set_gfp_allowed_mask(gfp_t mask)
107+
108+static gfp_t saved_gfp_mask;
109+
110+void pm_restore_gfp_mask(void)
108111 {
109112 WARN_ON(!mutex_is_locked(&pm_mutex));
110− gfp_allowed_mask = mask;
113+ if (saved_gfp_mask) {
114+ gfp_allowed_mask = saved_gfp_mask;
115+ saved_gfp_mask = 0;
116+ }
111117 }
112118
113−gfp_t clear_gfp_allowed_mask(gfp_t mask)
119+void pm_restrict_gfp_mask(void)
114120 {
115− gfp_t ret = gfp_allowed_mask;
116−
117121 WARN_ON(!mutex_is_locked(&pm_mutex));
118− gfp_allowed_mask &= ~mask;
119− return ret;
122+ WARN_ON(saved_gfp_mask);
123+ saved_gfp_mask = gfp_allowed_mask;
124+ gfp_allowed_mask &= ~GFP_IOFS;
120125 }
121126 #endif /* CONFIG_PM_SLEEP */
122127