diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-12 16:17:27 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-12 16:17:27 -0400 |
| commit | 947ec0b0c1e7e80eef4fe64f7763a06d0cf04d2e (patch) | |
| tree | 29547b6975d58c3b252f08dc6c2dbda3b9adfa88 /kernel/power/snapshot.c | |
| parent | c53567ad4528b6efefc3fc22a354d20f6226a098 (diff) | |
| parent | 5818a6e2519b34cd6d0220d89f5729ab2725e1bf (diff) | |
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:
PM: Add empty suspend/resume device irq functions
PM/Hibernate: Move NVS routines into a seperate file (v2).
PM/Hibernate: Rename disk.c to hibernate.c
PM: Separate suspend to RAM functionality from core
Driver Core: Rework platform suspend/resume, print warning
PM: Remove device_type suspend()/resume()
PM/Hibernate: Move memory shrinking to snapshot.c (rev. 2)
PM/Suspend: Do not shrink memory before suspend
PM: Remove bus_type suspend_late()/resume_early() V2
PM core: rename suspend and resume functions
PM: Rename device_power_down/up()
PM: Remove unused asm/suspend.h
x86: unify power/cpu_(32|64).c
x86: unify power/cpu_(32|64) copyright notes
x86: unify power/cpu_(32|64) regarding restoring processor state
x86: unify power/cpu_(32|64) regarding saving processor state
x86: unify power/cpu_(32|64) global variables
x86: unify power/cpu_(32|64) headers
PM: Warn if interrupts are enabled during suspend-resume of sysdevs
PM/ACPI/x86: Fix sparse warning in arch/x86/kernel/acpi/sleep.c
Diffstat (limited to 'kernel/power/snapshot.c')
| -rw-r--r-- | kernel/power/snapshot.c | 80 |
1 files changed, 78 insertions, 2 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 33e2e4a819f9..523a451b45d3 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
| @@ -39,6 +39,14 @@ static int swsusp_page_is_free(struct page *); | |||
| 39 | static void swsusp_set_page_forbidden(struct page *); | 39 | static void swsusp_set_page_forbidden(struct page *); |
| 40 | static void swsusp_unset_page_forbidden(struct page *); | 40 | static void swsusp_unset_page_forbidden(struct page *); |
| 41 | 41 | ||
| 42 | /* | ||
| 43 | * Preferred image size in bytes (tunable via /sys/power/image_size). | ||
| 44 | * When it is set to N, swsusp will do its best to ensure the image | ||
| 45 | * size will not exceed N bytes, but if that is impossible, it will | ||
| 46 | * try to create the smallest image possible. | ||
| 47 | */ | ||
| 48 | unsigned long image_size = 500 * 1024 * 1024; | ||
| 49 | |||
| 42 | /* List of PBEs needed for restoring the pages that were allocated before | 50 | /* List of PBEs needed for restoring the pages that were allocated before |
| 43 | * the suspend and included in the suspend image, but have also been | 51 | * the suspend and included in the suspend image, but have also been |
| 44 | * allocated by the "resume" kernel, so their contents cannot be written | 52 | * allocated by the "resume" kernel, so their contents cannot be written |
| @@ -840,7 +848,7 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn) | |||
| 840 | * pages. | 848 | * pages. |
| 841 | */ | 849 | */ |
| 842 | 850 | ||
| 843 | unsigned int count_highmem_pages(void) | 851 | static unsigned int count_highmem_pages(void) |
| 844 | { | 852 | { |
| 845 | struct zone *zone; | 853 | struct zone *zone; |
| 846 | unsigned int n = 0; | 854 | unsigned int n = 0; |
| @@ -902,7 +910,7 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn) | |||
| 902 | * pages. | 910 | * pages. |
| 903 | */ | 911 | */ |
| 904 | 912 | ||
| 905 | unsigned int count_data_pages(void) | 913 | static unsigned int count_data_pages(void) |
| 906 | { | 914 | { |
| 907 | struct zone *zone; | 915 | struct zone *zone; |
| 908 | unsigned long pfn, max_zone_pfn; | 916 | unsigned long pfn, max_zone_pfn; |
| @@ -1058,6 +1066,74 @@ void swsusp_free(void) | |||
| 1058 | buffer = NULL; | 1066 | buffer = NULL; |
| 1059 | } | 1067 | } |
| 1060 | 1068 | ||
| 1069 | /** | ||
| 1070 | * swsusp_shrink_memory - Try to free as much memory as needed | ||
| 1071 | * | ||
| 1072 | * ... but do not OOM-kill anyone | ||
| 1073 | * | ||
| 1074 | * Notice: all userland should be stopped before it is called, or | ||
| 1075 | * livelock is possible. | ||
| 1076 | */ | ||
| 1077 | |||
| 1078 | #define SHRINK_BITE 10000 | ||
| 1079 | static inline unsigned long __shrink_memory(long tmp) | ||
| 1080 | { | ||
| 1081 | if (tmp > SHRINK_BITE) | ||
| 1082 | tmp = SHRINK_BITE; | ||
| 1083 | return shrink_all_memory(tmp); | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | int swsusp_shrink_memory(void) | ||
| 1087 | { | ||
| 1088 | long tmp; | ||
| 1089 | struct zone *zone; | ||
| 1090 | unsigned long pages = 0; | ||
| 1091 | unsigned int i = 0; | ||
| 1092 | char *p = "-\\|/"; | ||
| 1093 | struct timeval start, stop; | ||
| 1094 | |||
| 1095 | printk(KERN_INFO "PM: Shrinking memory... "); | ||
| 1096 | do_gettimeofday(&start); | ||
| 1097 | do { | ||
| 1098 | long size, highmem_size; | ||
| 1099 | |||
| 1100 | highmem_size = count_highmem_pages(); | ||
| 1101 | size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES; | ||
| 1102 | tmp = size; | ||
| 1103 | size += highmem_size; | ||
| 1104 | for_each_populated_zone(zone) { | ||
| 1105 | tmp += snapshot_additional_pages(zone); | ||
| 1106 | if (is_highmem(zone)) { | ||
| 1107 | highmem_size -= | ||
| 1108 | zone_page_state(zone, NR_FREE_PAGES); | ||
| 1109 | } else { | ||
| 1110 | tmp -= zone_page_state(zone, NR_FREE_PAGES); | ||
| 1111 | tmp += zone->lowmem_reserve[ZONE_NORMAL]; | ||
| 1112 | } | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | if (highmem_size < 0) | ||
| 1116 | highmem_size = 0; | ||
| 1117 | |||
| 1118 | tmp += highmem_size; | ||
| 1119 | if (tmp > 0) { | ||
| 1120 | tmp = __shrink_memory(tmp); | ||
| 1121 | if (!tmp) | ||
| 1122 | return -ENOMEM; | ||
| 1123 | pages += tmp; | ||
| 1124 | } else if (size > image_size / PAGE_SIZE) { | ||
| 1125 | tmp = __shrink_memory(size - (image_size / PAGE_SIZE)); | ||
| 1126 | pages += tmp; | ||
| 1127 | } | ||
| 1128 | printk("\b%c", p[i++%4]); | ||
| 1129 | } while (tmp > 0); | ||
| 1130 | do_gettimeofday(&stop); | ||
| 1131 | printk("\bdone (%lu pages freed)\n", pages); | ||
| 1132 | swsusp_show_speed(&start, &stop, pages, "Freed"); | ||
| 1133 | |||
| 1134 | return 0; | ||
| 1135 | } | ||
| 1136 | |||
| 1061 | #ifdef CONFIG_HIGHMEM | 1137 | #ifdef CONFIG_HIGHMEM |
| 1062 | /** | 1138 | /** |
| 1063 | * count_pages_for_highmem - compute the number of non-highmem pages | 1139 | * count_pages_for_highmem - compute the number of non-highmem pages |
