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
360 360
361extern gfp_t gfp_allowed_mask;361extern gfp_t gfp_allowed_mask;
362 362
363extern void set_gfp_allowed_mask(gfp_t mask);363extern void pm_restrict_gfp_mask(void);
364extern gfp_t clear_gfp_allowed_mask(gfp_t mask);364extern void pm_restore_gfp_mask(void);
365 365
366#endif /* __LINUX_GFP_H */366#endif /* __LINUX_GFP_H */
kernel/power/hibernate.c+12−10
@@ -327,7 +327,6 @@ static int create_image(int platform_mode) · 326 unmodified lines
327int hibernation_snapshot(int platform_mode)327int hibernation_snapshot(int platform_mode)
328{328{
329 int error;329 int error;
330 gfp_t saved_mask;
331 330
332 error = platform_begin(platform_mode);331 error = platform_begin(platform_mode);
333 if (error)332 if (error)
@@ -339,7 +338,7 @@ int hibernation_snapshot(int platform_mode) · 5 unmodified lines
339 goto Close;338 goto Close;
340 339
341 suspend_console();340 suspend_console();
342 saved_mask = clear_gfp_allowed_mask(GFP_IOFS);341 pm_restrict_gfp_mask();
343 error = dpm_suspend_start(PMSG_FREEZE);342 error = dpm_suspend_start(PMSG_FREEZE);
344 if (error)343 if (error)
345 goto Recover_platform;344 goto Recover_platform;
@@ -348,7 +347,10 @@ int hibernation_snapshot(int platform_mode) · 2 unmodified lines
348 goto Recover_platform;347 goto Recover_platform;
349 348
350 error = create_image(platform_mode);349 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 */
352 354
353 Resume_devices:355 Resume_devices:
354 /* We may need to release the preallocated image pages here. */356 /* We may need to release the preallocated image pages here. */
@@ -357,7 +359,10 @@ int hibernation_snapshot(int platform_mode) · 2 unmodified lines
357 359
358 dpm_resume_end(in_suspend ?360 dpm_resume_end(in_suspend ?
359 (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);361 (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
361 resume_console();366 resume_console();
362 Close:367 Close:
363 platform_end(platform_mode);368 platform_end(platform_mode);
@@ -452,17 +457,16 @@ static int resume_target_kernel(bool platform_mode) · 88 unmodified lines
452int hibernation_restore(int platform_mode)457int hibernation_restore(int platform_mode)
453{458{
454 int error;459 int error;
455 gfp_t saved_mask;
456 460
457 pm_prepare_console();461 pm_prepare_console();
458 suspend_console();462 suspend_console();
459 saved_mask = clear_gfp_allowed_mask(GFP_IOFS);463 pm_restrict_gfp_mask();
460 error = dpm_suspend_start(PMSG_QUIESCE);464 error = dpm_suspend_start(PMSG_QUIESCE);
461 if (!error) {465 if (!error) {
462 error = resume_target_kernel(platform_mode);466 error = resume_target_kernel(platform_mode);
463 dpm_resume_end(PMSG_RECOVER);467 dpm_resume_end(PMSG_RECOVER);
464 }468 }
465 set_gfp_allowed_mask(saved_mask);469 pm_restore_gfp_mask();
466 resume_console();470 resume_console();
467 pm_restore_console();471 pm_restore_console();
468 return error;472 return error;
@@ -476,7 +480,6 @@ int hibernation_restore(int platform_mode) · 7 unmodified lines
476int hibernation_platform_enter(void)480int hibernation_platform_enter(void)
477{481{
478 int error;482 int error;
479 gfp_t saved_mask;
480 483
481 if (!hibernation_ops)484 if (!hibernation_ops)
482 return -ENOSYS;485 return -ENOSYS;
@@ -492,7 +495,6 @@ int hibernation_platform_enter(void) · 9 unmodified lines
492 495
493 entering_platform_hibernation = true;496 entering_platform_hibernation = true;
494 suspend_console();497 suspend_console();
495 saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
496 error = dpm_suspend_start(PMSG_HIBERNATE);498 error = dpm_suspend_start(PMSG_HIBERNATE);
497 if (error) {499 if (error) {
498 if (hibernation_ops->recover)500 if (hibernation_ops->recover)
@@ -536,7 +538,6 @@ int hibernation_platform_enter(void) · 37 unmodified lines
536 Resume_devices:538 Resume_devices:
537 entering_platform_hibernation = false;539 entering_platform_hibernation = false;
538 dpm_resume_end(PMSG_RESTORE);540 dpm_resume_end(PMSG_RESTORE);
539 set_gfp_allowed_mask(saved_mask);
540 resume_console();541 resume_console();
541 542
542 Close:543 Close:
@@ -646,6 +647,7 @@ int hibernate(void) · 103 unmodified lines
646 swsusp_free();647 swsusp_free();
647 if (!error)648 if (!error)
648 power_down();649 power_down();
650 pm_restore_gfp_mask();
649 } else {651 } else {
650 pr_debug("PM: Image restored successfully.\n");652 pr_debug("PM: Image restored successfully.\n");
651 }653 }
kernel/power/suspend.c+2−3
@@ -197,7 +197,6 @@ static int suspend_enter(suspend_state_t state) · 196 unmodified lines
197int suspend_devices_and_enter(suspend_state_t state)197int suspend_devices_and_enter(suspend_state_t state)
198{198{
199 int error;199 int error;
200 gfp_t saved_mask;
201 200
202 if (!suspend_ops)201 if (!suspend_ops)
203 return -ENOSYS;202 return -ENOSYS;
@@ -208,7 +207,7 @@ int suspend_devices_and_enter(suspend_state_t state) · 4 unmodified lines
208 goto Close;207 goto Close;
209 }208 }
210 suspend_console();209 suspend_console();
211 saved_mask = clear_gfp_allowed_mask(GFP_IOFS);210 pm_restrict_gfp_mask();
212 suspend_test_start();211 suspend_test_start();
213 error = dpm_suspend_start(PMSG_SUSPEND);212 error = dpm_suspend_start(PMSG_SUSPEND);
214 if (error) {213 if (error) {
@@ -225,7 +224,7 @@ int suspend_devices_and_enter(suspend_state_t state) · 10 unmodified lines
225 suspend_test_start();224 suspend_test_start();
226 dpm_resume_end(PMSG_RESUME);225 dpm_resume_end(PMSG_RESUME);
227 suspend_test_finish("resume devices");226 suspend_test_finish("resume devices");
228 set_gfp_allowed_mask(saved_mask);227 pm_restore_gfp_mask();
229 resume_console();228 resume_console();
230 Close:229 Close:
231 if (suspend_ops->end)230 if (suspend_ops->end)
kernel/power/swap.c+38−15
@@ -6,6 +6,7 @@ · 5 unmodified lines
6 *6 *
7 * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>7 * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
8 * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>8 * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
9 * Copyright (C) 2010 Bojan Smojver <bojan@rexursive.com>
9 *10 *
10 * This file is released under the GPLv2.11 * This file is released under the GPLv2.
11 *12 *
@@ -753,30 +754,43 @@ static int load_image_lzo(struct swap_map_handle *handle, · 741 unmodified lines
753{754{
754 unsigned int m;755 unsigned int m;
755 int error = 0;756 int error = 0;
757 struct bio *bio;
756 struct timeval start;758 struct timeval start;
757 struct timeval stop;759 struct timeval stop;
758 unsigned nr_pages;760 unsigned nr_pages;
759 size_t off, unc_len, cmp_len;761 size_t i, off, unc_len, cmp_len;
760 unsigned char *unc, *cmp, *page;762 unsigned char *unc, *cmp, *page[LZO_CMP_PAGES];
761 763
762 page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);764 for (i = 0; i < LZO_CMP_PAGES; i++) {
763 if (!page) {765 page[i] = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
764 printk(KERN_ERR "PM: Failed to allocate LZO page\n");766 if (!page[i]) {
765 return -ENOMEM;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 }
766 }774 }
767 775
768 unc = vmalloc(LZO_UNC_SIZE);776 unc = vmalloc(LZO_UNC_SIZE);
769 if (!unc) {777 if (!unc) {
770 printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");778 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
772 return -ENOMEM;783 return -ENOMEM;
773 }784 }
774 785
775 cmp = vmalloc(LZO_CMP_SIZE);786 cmp = vmalloc(LZO_CMP_SIZE);
776 if (!cmp) {787 if (!cmp) {
777 printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");788 printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");
789
778 vfree(unc);790 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
780 return -ENOMEM;794 return -ENOMEM;
781 }795 }
782 796
@@ -787,6 +801,7 @@ static int load_image_lzo(struct swap_map_handle *handle, · 4 unmodified lines
787 if (!m)801 if (!m)
788 m = 1;802 m = 1;
789 nr_pages = 0;803 nr_pages = 0;
804 bio = NULL;
790 do_gettimeofday(&start);805 do_gettimeofday(&start);
791 806
792 error = snapshot_write_next(snapshot);807 error = snapshot_write_next(snapshot);
@@ -794,11 +809,11 @@ static int load_image_lzo(struct swap_map_handle *handle, · 1 unmodified line
794 goto out_finish;809 goto out_finish;
795 810
796 for (;;) {811 for (;;) {
797 error = swap_read_page(handle, page, NULL); /* sync */812 error = swap_read_page(handle, page[0], NULL); /* sync */
798 if (error)813 if (error)
799 break;814 break;
800 815
801 cmp_len = *(size_t *)page;816 cmp_len = *(size_t *)page[0];
802 if (unlikely(!cmp_len ||817 if (unlikely(!cmp_len ||
803 cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) {818 cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) {
804 printk(KERN_ERR "PM: Invalid LZO compressed length\n");819 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
806 break;821 break;
807 }822 }
808 823
809 memcpy(cmp, page, PAGE_SIZE);824 for (off = PAGE_SIZE, i = 1;
810 for (off = PAGE_SIZE; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) {825 off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
811 error = swap_read_page(handle, page, NULL); /* sync */826 error = swap_read_page(handle, page[i], &bio);
812 if (error)827 if (error)
813 goto out_finish;828 goto out_finish;
829 }
814 830
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);
816 }838 }
817 839
818 unc_len = LZO_UNC_SIZE;840 unc_len = LZO_UNC_SIZE;
@@ -857,7 +879,8 @@ out_finish: · 38 unmodified lines
857 879
858 vfree(cmp);880 vfree(cmp);
859 vfree(unc);881 vfree(unc);
860 free_page((unsigned long)page);882 for (i = 0; i < LZO_CMP_PAGES; i++)
883 free_page((unsigned long)page[i]);
861 884
862 return error;885 return error;
863}886}
kernel/power/user.c+2−0
@@ -263,6 +263,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, · 262 unmodified lines
263 case SNAPSHOT_UNFREEZE:263 case SNAPSHOT_UNFREEZE:
264 if (!data->frozen || data->ready)264 if (!data->frozen || data->ready)
265 break;265 break;
266 pm_restore_gfp_mask();
266 thaw_processes();267 thaw_processes();
267 usermodehelper_enable();268 usermodehelper_enable();
268 data->frozen = 0;269 data->frozen = 0;
@@ -275,6 +276,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, · 6 unmodified lines
275 error = -EPERM;276 error = -EPERM;
276 break;277 break;
277 }278 }
279 pm_restore_gfp_mask();
278 error = hibernation_snapshot(data->platform_support);280 error = hibernation_snapshot(data->platform_support);
279 if (!error)281 if (!error)
280 error = put_user(in_suspend, (int __user *)arg);282 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
104 * only be modified with pm_mutex held, unless the suspend/hibernate code is104 * only be modified with pm_mutex held, unless the suspend/hibernate code is
105 * guaranteed not to run in parallel with that modification).105 * guaranteed not to run in parallel with that modification).
106 */106 */
107void set_gfp_allowed_mask(gfp_t mask)107
108static gfp_t saved_gfp_mask;
109
110void pm_restore_gfp_mask(void)
108{111{
109 WARN_ON(!mutex_is_locked(&pm_mutex));112 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 }
111}117}
112 118
113gfp_t clear_gfp_allowed_mask(gfp_t mask)119void pm_restrict_gfp_mask(void)
114{120{
115 gfp_t ret = gfp_allowed_mask;
116
117 WARN_ON(!mutex_is_locked(&pm_mutex));121 WARN_ON(!mutex_is_locked(&pm_mutex));
118 gfp_allowed_mask &= ~mask;122 WARN_ON(saved_gfp_mask);
119 return ret;123 saved_gfp_mask = gfp_allowed_mask;
124 gfp_allowed_mask &= ~GFP_IOFS;
120}125}
121#endif /* CONFIG_PM_SLEEP */126#endif /* CONFIG_PM_SLEEP */
122 127