diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-09-11 18:50:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-09-11 18:50:53 -0400 |
commit | 84e1d836ef0759a152578a961894824bde89596f (patch) | |
tree | 47c439bfdc9e5ea91f9a71235d336257555fad78 | |
parent | 20f4cad6b247160055915db4f4aaeda82e6c50ed (diff) | |
parent | 6715045ddc7472a22be5e49d4047d2d89b391f45 (diff) |
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: Avoid hitting OOM during preallocation of memory
PM QoS: Correct pr_debug() misuse and improve parameter checks
PM: Prevent waiting forever on asynchronous resume after failing suspend
-rw-r--r-- | drivers/base/power/main.c | 1 | ||||
-rw-r--r-- | kernel/pm_qos_params.c | 4 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 85 |
3 files changed, 69 insertions, 21 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 5419a49ff135..276d5a701dc3 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -59,6 +59,7 @@ void device_pm_init(struct device *dev) | |||
59 | { | 59 | { |
60 | dev->power.status = DPM_ON; | 60 | dev->power.status = DPM_ON; |
61 | init_completion(&dev->power.completion); | 61 | init_completion(&dev->power.completion); |
62 | complete_all(&dev->power.completion); | ||
62 | dev->power.wakeup_count = 0; | 63 | dev->power.wakeup_count = 0; |
63 | pm_runtime_init(dev); | 64 | pm_runtime_init(dev); |
64 | } | 65 | } |
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c index b7e4c362361b..645e541a45f6 100644 --- a/kernel/pm_qos_params.c +++ b/kernel/pm_qos_params.c | |||
@@ -389,10 +389,12 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, | |||
389 | } else if (count == 11) { /* len('0x12345678/0') */ | 389 | } else if (count == 11) { /* len('0x12345678/0') */ |
390 | if (copy_from_user(ascii_value, buf, 11)) | 390 | if (copy_from_user(ascii_value, buf, 11)) |
391 | return -EFAULT; | 391 | return -EFAULT; |
392 | if (strlen(ascii_value) != 10) | ||
393 | return -EINVAL; | ||
392 | x = sscanf(ascii_value, "%x", &value); | 394 | x = sscanf(ascii_value, "%x", &value); |
393 | if (x != 1) | 395 | if (x != 1) |
394 | return -EINVAL; | 396 | return -EINVAL; |
395 | pr_debug(KERN_ERR "%s, %d, 0x%x\n", ascii_value, x, value); | 397 | pr_debug("%s, %d, 0x%x\n", ascii_value, x, value); |
396 | } else | 398 | } else |
397 | return -EINVAL; | 399 | return -EINVAL; |
398 | 400 | ||
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index f6cd6faf84fd..d3f795f01bbc 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -1121,9 +1121,19 @@ static unsigned long preallocate_image_pages(unsigned long nr_pages, gfp_t mask) | |||
1121 | return nr_alloc; | 1121 | return nr_alloc; |
1122 | } | 1122 | } |
1123 | 1123 | ||
1124 | static unsigned long preallocate_image_memory(unsigned long nr_pages) | 1124 | static unsigned long preallocate_image_memory(unsigned long nr_pages, |
1125 | unsigned long avail_normal) | ||
1125 | { | 1126 | { |
1126 | return preallocate_image_pages(nr_pages, GFP_IMAGE); | 1127 | unsigned long alloc; |
1128 | |||
1129 | if (avail_normal <= alloc_normal) | ||
1130 | return 0; | ||
1131 | |||
1132 | alloc = avail_normal - alloc_normal; | ||
1133 | if (nr_pages < alloc) | ||
1134 | alloc = nr_pages; | ||
1135 | |||
1136 | return preallocate_image_pages(alloc, GFP_IMAGE); | ||
1127 | } | 1137 | } |
1128 | 1138 | ||
1129 | #ifdef CONFIG_HIGHMEM | 1139 | #ifdef CONFIG_HIGHMEM |
@@ -1169,15 +1179,22 @@ static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages, | |||
1169 | */ | 1179 | */ |
1170 | static void free_unnecessary_pages(void) | 1180 | static void free_unnecessary_pages(void) |
1171 | { | 1181 | { |
1172 | unsigned long save_highmem, to_free_normal, to_free_highmem; | 1182 | unsigned long save, to_free_normal, to_free_highmem; |
1173 | 1183 | ||
1174 | to_free_normal = alloc_normal - count_data_pages(); | 1184 | save = count_data_pages(); |
1175 | save_highmem = count_highmem_pages(); | 1185 | if (alloc_normal >= save) { |
1176 | if (alloc_highmem > save_highmem) { | 1186 | to_free_normal = alloc_normal - save; |
1177 | to_free_highmem = alloc_highmem - save_highmem; | 1187 | save = 0; |
1188 | } else { | ||
1189 | to_free_normal = 0; | ||
1190 | save -= alloc_normal; | ||
1191 | } | ||
1192 | save += count_highmem_pages(); | ||
1193 | if (alloc_highmem >= save) { | ||
1194 | to_free_highmem = alloc_highmem - save; | ||
1178 | } else { | 1195 | } else { |
1179 | to_free_highmem = 0; | 1196 | to_free_highmem = 0; |
1180 | to_free_normal -= save_highmem - alloc_highmem; | 1197 | to_free_normal -= save - alloc_highmem; |
1181 | } | 1198 | } |
1182 | 1199 | ||
1183 | memory_bm_position_reset(©_bm); | 1200 | memory_bm_position_reset(©_bm); |
@@ -1258,7 +1275,7 @@ int hibernate_preallocate_memory(void) | |||
1258 | { | 1275 | { |
1259 | struct zone *zone; | 1276 | struct zone *zone; |
1260 | unsigned long saveable, size, max_size, count, highmem, pages = 0; | 1277 | unsigned long saveable, size, max_size, count, highmem, pages = 0; |
1261 | unsigned long alloc, save_highmem, pages_highmem; | 1278 | unsigned long alloc, save_highmem, pages_highmem, avail_normal; |
1262 | struct timeval start, stop; | 1279 | struct timeval start, stop; |
1263 | int error; | 1280 | int error; |
1264 | 1281 | ||
@@ -1295,6 +1312,7 @@ int hibernate_preallocate_memory(void) | |||
1295 | else | 1312 | else |
1296 | count += zone_page_state(zone, NR_FREE_PAGES); | 1313 | count += zone_page_state(zone, NR_FREE_PAGES); |
1297 | } | 1314 | } |
1315 | avail_normal = count; | ||
1298 | count += highmem; | 1316 | count += highmem; |
1299 | count -= totalreserve_pages; | 1317 | count -= totalreserve_pages; |
1300 | 1318 | ||
@@ -1309,12 +1327,21 @@ int hibernate_preallocate_memory(void) | |||
1309 | */ | 1327 | */ |
1310 | if (size >= saveable) { | 1328 | if (size >= saveable) { |
1311 | pages = preallocate_image_highmem(save_highmem); | 1329 | pages = preallocate_image_highmem(save_highmem); |
1312 | pages += preallocate_image_memory(saveable - pages); | 1330 | pages += preallocate_image_memory(saveable - pages, avail_normal); |
1313 | goto out; | 1331 | goto out; |
1314 | } | 1332 | } |
1315 | 1333 | ||
1316 | /* Estimate the minimum size of the image. */ | 1334 | /* Estimate the minimum size of the image. */ |
1317 | pages = minimum_image_size(saveable); | 1335 | pages = minimum_image_size(saveable); |
1336 | /* | ||
1337 | * To avoid excessive pressure on the normal zone, leave room in it to | ||
1338 | * accommodate an image of the minimum size (unless it's already too | ||
1339 | * small, in which case don't preallocate pages from it at all). | ||
1340 | */ | ||
1341 | if (avail_normal > pages) | ||
1342 | avail_normal -= pages; | ||
1343 | else | ||
1344 | avail_normal = 0; | ||
1318 | if (size < pages) | 1345 | if (size < pages) |
1319 | size = min_t(unsigned long, pages, max_size); | 1346 | size = min_t(unsigned long, pages, max_size); |
1320 | 1347 | ||
@@ -1335,16 +1362,34 @@ int hibernate_preallocate_memory(void) | |||
1335 | */ | 1362 | */ |
1336 | pages_highmem = preallocate_image_highmem(highmem / 2); | 1363 | pages_highmem = preallocate_image_highmem(highmem / 2); |
1337 | alloc = (count - max_size) - pages_highmem; | 1364 | alloc = (count - max_size) - pages_highmem; |
1338 | pages = preallocate_image_memory(alloc); | 1365 | pages = preallocate_image_memory(alloc, avail_normal); |
1339 | if (pages < alloc) | 1366 | if (pages < alloc) { |
1340 | goto err_out; | 1367 | /* We have exhausted non-highmem pages, try highmem. */ |
1341 | size = max_size - size; | 1368 | alloc -= pages; |
1342 | alloc = size; | 1369 | pages += pages_highmem; |
1343 | size = preallocate_highmem_fraction(size, highmem, count); | 1370 | pages_highmem = preallocate_image_highmem(alloc); |
1344 | pages_highmem += size; | 1371 | if (pages_highmem < alloc) |
1345 | alloc -= size; | 1372 | goto err_out; |
1346 | pages += preallocate_image_memory(alloc); | 1373 | pages += pages_highmem; |
1347 | pages += pages_highmem; | 1374 | /* |
1375 | * size is the desired number of saveable pages to leave in | ||
1376 | * memory, so try to preallocate (all memory - size) pages. | ||
1377 | */ | ||
1378 | alloc = (count - pages) - size; | ||
1379 | pages += preallocate_image_highmem(alloc); | ||
1380 | } else { | ||
1381 | /* | ||
1382 | * There are approximately max_size saveable pages at this point | ||
1383 | * and we want to reduce this number down to size. | ||
1384 | */ | ||
1385 | alloc = max_size - size; | ||
1386 | size = preallocate_highmem_fraction(alloc, highmem, count); | ||
1387 | pages_highmem += size; | ||
1388 | alloc -= size; | ||
1389 | size = preallocate_image_memory(alloc, avail_normal); | ||
1390 | pages_highmem += preallocate_image_highmem(alloc - size); | ||
1391 | pages += pages_highmem + size; | ||
1392 | } | ||
1348 | 1393 | ||
1349 | /* | 1394 | /* |
1350 | * We only need as many page frames for the image as there are saveable | 1395 | * We only need as many page frames for the image as there are saveable |