diff options
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 |