aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-09-11 14:58:27 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2010-09-11 15:03:53 -0400
commit6715045ddc7472a22be5e49d4047d2d89b391f45 (patch)
treed9a48095e915407f6d54db29cfce44c201ae9cef /kernel
parent0109c2c48d062a04685638926a35ed20153fedc8 (diff)
PM / Hibernate: Avoid hitting OOM during preallocation of memory
There is a problem in hibernate_preallocate_memory() that it calls preallocate_image_memory() with an argument that may be greater than the total number of available non-highmem memory pages. If that's the case, the OOM condition is guaranteed to trigger, which in turn can cause significant slowdown to occur during hibernation. To avoid that, make preallocate_image_memory() adjust its argument before calling preallocate_image_pages(), so that the total number of saveable non-highem pages left is not less than the minimum size of a hibernation image. Change hibernate_preallocate_memory() to try to allocate from highmem if the number of pages allocated by preallocate_image_memory() is too low. Modify free_unnecessary_pages() to take all possible memory allocation patterns into account. Reported-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Tested-by: M. Vefa Bicakci <bicave@superonline.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/snapshot.c85
1 files changed, 65 insertions, 20 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 5e7edfb05e66..5209b39e6982 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -1122,9 +1122,19 @@ static unsigned long preallocate_image_pages(unsigned long nr_pages, gfp_t mask)
1122 return nr_alloc; 1122 return nr_alloc;
1123} 1123}
1124 1124
1125static unsigned long preallocate_image_memory(unsigned long nr_pages) 1125static unsigned long preallocate_image_memory(unsigned long nr_pages,
1126 unsigned long avail_normal)
1126{ 1127{
1127 return preallocate_image_pages(nr_pages, GFP_IMAGE); 1128 unsigned long alloc;
1129
1130 if (avail_normal <= alloc_normal)
1131 return 0;
1132
1133 alloc = avail_normal - alloc_normal;
1134 if (nr_pages < alloc)
1135 alloc = nr_pages;
1136
1137 return preallocate_image_pages(alloc, GFP_IMAGE);
1128} 1138}
1129 1139
1130#ifdef CONFIG_HIGHMEM 1140#ifdef CONFIG_HIGHMEM
@@ -1170,15 +1180,22 @@ static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
1170 */ 1180 */
1171static void free_unnecessary_pages(void) 1181static void free_unnecessary_pages(void)
1172{ 1182{
1173 unsigned long save_highmem, to_free_normal, to_free_highmem; 1183 unsigned long save, to_free_normal, to_free_highmem;
1174 1184
1175 to_free_normal = alloc_normal - count_data_pages(); 1185 save = count_data_pages();
1176 save_highmem = count_highmem_pages(); 1186 if (alloc_normal >= save) {
1177 if (alloc_highmem > save_highmem) { 1187 to_free_normal = alloc_normal - save;
1178 to_free_highmem = alloc_highmem - save_highmem; 1188 save = 0;
1189 } else {
1190 to_free_normal = 0;
1191 save -= alloc_normal;
1192 }
1193 save += count_highmem_pages();
1194 if (alloc_highmem >= save) {
1195 to_free_highmem = alloc_highmem - save;
1179 } else { 1196 } else {
1180 to_free_highmem = 0; 1197 to_free_highmem = 0;
1181 to_free_normal -= save_highmem - alloc_highmem; 1198 to_free_normal -= save - alloc_highmem;
1182 } 1199 }
1183 1200
1184 memory_bm_position_reset(&copy_bm); 1201 memory_bm_position_reset(&copy_bm);
@@ -1259,7 +1276,7 @@ int hibernate_preallocate_memory(void)
1259{ 1276{
1260 struct zone *zone; 1277 struct zone *zone;
1261 unsigned long saveable, size, max_size, count, highmem, pages = 0; 1278 unsigned long saveable, size, max_size, count, highmem, pages = 0;
1262 unsigned long alloc, save_highmem, pages_highmem; 1279 unsigned long alloc, save_highmem, pages_highmem, avail_normal;
1263 struct timeval start, stop; 1280 struct timeval start, stop;
1264 int error; 1281 int error;
1265 1282
@@ -1296,6 +1313,7 @@ int hibernate_preallocate_memory(void)
1296 else 1313 else
1297 count += zone_page_state(zone, NR_FREE_PAGES); 1314 count += zone_page_state(zone, NR_FREE_PAGES);
1298 } 1315 }
1316 avail_normal = count;
1299 count += highmem; 1317 count += highmem;
1300 count -= totalreserve_pages; 1318 count -= totalreserve_pages;
1301 1319
@@ -1310,12 +1328,21 @@ int hibernate_preallocate_memory(void)
1310 */ 1328 */
1311 if (size >= saveable) { 1329 if (size >= saveable) {
1312 pages = preallocate_image_highmem(save_highmem); 1330 pages = preallocate_image_highmem(save_highmem);
1313 pages += preallocate_image_memory(saveable - pages); 1331 pages += preallocate_image_memory(saveable - pages, avail_normal);
1314 goto out; 1332 goto out;
1315 } 1333 }
1316 1334
1317 /* Estimate the minimum size of the image. */ 1335 /* Estimate the minimum size of the image. */
1318 pages = minimum_image_size(saveable); 1336 pages = minimum_image_size(saveable);
1337 /*
1338 * To avoid excessive pressure on the normal zone, leave room in it to
1339 * accommodate an image of the minimum size (unless it's already too
1340 * small, in which case don't preallocate pages from it at all).
1341 */
1342 if (avail_normal > pages)
1343 avail_normal -= pages;
1344 else
1345 avail_normal = 0;
1319 if (size < pages) 1346 if (size < pages)
1320 size = min_t(unsigned long, pages, max_size); 1347 size = min_t(unsigned long, pages, max_size);
1321 1348
@@ -1336,16 +1363,34 @@ int hibernate_preallocate_memory(void)
1336 */ 1363 */
1337 pages_highmem = preallocate_image_highmem(highmem / 2); 1364 pages_highmem = preallocate_image_highmem(highmem / 2);
1338 alloc = (count - max_size) - pages_highmem; 1365 alloc = (count - max_size) - pages_highmem;
1339 pages = preallocate_image_memory(alloc); 1366 pages = preallocate_image_memory(alloc, avail_normal);
1340 if (pages < alloc) 1367 if (pages < alloc) {
1341 goto err_out; 1368 /* We have exhausted non-highmem pages, try highmem. */
1342 size = max_size - size; 1369 alloc -= pages;
1343 alloc = size; 1370 pages += pages_highmem;
1344 size = preallocate_highmem_fraction(size, highmem, count); 1371 pages_highmem = preallocate_image_highmem(alloc);
1345 pages_highmem += size; 1372 if (pages_highmem < alloc)
1346 alloc -= size; 1373 goto err_out;
1347 pages += preallocate_image_memory(alloc); 1374 pages += pages_highmem;
1348 pages += pages_highmem; 1375 /*
1376 * size is the desired number of saveable pages to leave in
1377 * memory, so try to preallocate (all memory - size) pages.
1378 */
1379 alloc = (count - pages) - size;
1380 pages += preallocate_image_highmem(alloc);
1381 } else {
1382 /*
1383 * There are approximately max_size saveable pages at this point
1384 * and we want to reduce this number down to size.
1385 */
1386 alloc = max_size - size;
1387 size = preallocate_highmem_fraction(alloc, highmem, count);
1388 pages_highmem += size;
1389 alloc -= size;
1390 size = preallocate_image_memory(alloc, avail_normal);
1391 pages_highmem += preallocate_image_highmem(alloc - size);
1392 pages += pages_highmem + size;
1393 }
1349 1394
1350 /* 1395 /*
1351 * We only need as many page frames for the image as there are saveable 1396 * We only need as many page frames for the image as there are saveable