Commit 6715045ddc7472a22be5e49d4047d2d89b391f45
1 parent
0109c2c48d
Exists in
master
and in
20 other branches
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>
Showing 1 changed file with 65 additions and 20 deletions Side-by-side Diff
kernel/power/snapshot.c
... | ... | @@ -1122,9 +1122,19 @@ |
1122 | 1122 | return nr_alloc; |
1123 | 1123 | } |
1124 | 1124 | |
1125 | -static unsigned long preallocate_image_memory(unsigned long nr_pages) | |
1125 | +static 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 | 1140 | #ifdef CONFIG_HIGHMEM |
1131 | 1141 | |
1132 | 1142 | |
1133 | 1143 | |
... | ... | @@ -1170,15 +1180,22 @@ |
1170 | 1180 | */ |
1171 | 1181 | static 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(); | |
1176 | - save_highmem = count_highmem_pages(); | |
1177 | - if (alloc_highmem > save_highmem) { | |
1178 | - to_free_highmem = alloc_highmem - save_highmem; | |
1185 | + save = count_data_pages(); | |
1186 | + if (alloc_normal >= save) { | |
1187 | + to_free_normal = alloc_normal - save; | |
1188 | + save = 0; | |
1179 | 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; | |
1196 | + } else { | |
1180 | 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 | 1201 | memory_bm_position_reset(©_bm); |
... | ... | @@ -1259,7 +1276,7 @@ |
1259 | 1276 | { |
1260 | 1277 | struct zone *zone; |
1261 | 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 | 1280 | struct timeval start, stop; |
1264 | 1281 | int error; |
1265 | 1282 | |
... | ... | @@ -1296,6 +1313,7 @@ |
1296 | 1313 | else |
1297 | 1314 | count += zone_page_state(zone, NR_FREE_PAGES); |
1298 | 1315 | } |
1316 | + avail_normal = count; | |
1299 | 1317 | count += highmem; |
1300 | 1318 | count -= totalreserve_pages; |
1301 | 1319 | |
1302 | 1320 | |
... | ... | @@ -1310,12 +1328,21 @@ |
1310 | 1328 | */ |
1311 | 1329 | if (size >= saveable) { |
1312 | 1330 | pages = preallocate_image_highmem(save_highmem); |
1313 | - pages += preallocate_image_memory(saveable - pages); | |
1331 | + pages += preallocate_image_memory(saveable - pages, avail_normal); | |
1314 | 1332 | goto out; |
1315 | 1333 | } |
1316 | 1334 | |
1317 | 1335 | /* Estimate the minimum size of the image. */ |
1318 | 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 | 1346 | if (size < pages) |
1320 | 1347 | size = min_t(unsigned long, pages, max_size); |
1321 | 1348 | |
... | ... | @@ -1336,16 +1363,34 @@ |
1336 | 1363 | */ |
1337 | 1364 | pages_highmem = preallocate_image_highmem(highmem / 2); |
1338 | 1365 | alloc = (count - max_size) - pages_highmem; |
1339 | - pages = preallocate_image_memory(alloc); | |
1340 | - if (pages < alloc) | |
1341 | - goto err_out; | |
1342 | - size = max_size - size; | |
1343 | - alloc = size; | |
1344 | - size = preallocate_highmem_fraction(size, highmem, count); | |
1345 | - pages_highmem += size; | |
1346 | - alloc -= size; | |
1347 | - pages += preallocate_image_memory(alloc); | |
1348 | - pages += pages_highmem; | |
1366 | + pages = preallocate_image_memory(alloc, avail_normal); | |
1367 | + if (pages < alloc) { | |
1368 | + /* We have exhausted non-highmem pages, try highmem. */ | |
1369 | + alloc -= pages; | |
1370 | + pages += pages_highmem; | |
1371 | + pages_highmem = preallocate_image_highmem(alloc); | |
1372 | + if (pages_highmem < alloc) | |
1373 | + goto err_out; | |
1374 | + 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 | 1396 | * We only need as many page frames for the image as there are saveable |