diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/power/hibernate.c | 23 | ||||
-rw-r--r-- | kernel/power/main.c | 1 | ||||
-rw-r--r-- | kernel/power/power.h | 4 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 25 |
4 files changed, 48 insertions, 5 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 50aae660174d..431721313b71 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -982,10 +982,33 @@ static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *att | |||
982 | 982 | ||
983 | power_attr(image_size); | 983 | power_attr(image_size); |
984 | 984 | ||
985 | static ssize_t reserved_size_show(struct kobject *kobj, | ||
986 | struct kobj_attribute *attr, char *buf) | ||
987 | { | ||
988 | return sprintf(buf, "%lu\n", reserved_size); | ||
989 | } | ||
990 | |||
991 | static ssize_t reserved_size_store(struct kobject *kobj, | ||
992 | struct kobj_attribute *attr, | ||
993 | const char *buf, size_t n) | ||
994 | { | ||
995 | unsigned long size; | ||
996 | |||
997 | if (sscanf(buf, "%lu", &size) == 1) { | ||
998 | reserved_size = size; | ||
999 | return n; | ||
1000 | } | ||
1001 | |||
1002 | return -EINVAL; | ||
1003 | } | ||
1004 | |||
1005 | power_attr(reserved_size); | ||
1006 | |||
985 | static struct attribute * g[] = { | 1007 | static struct attribute * g[] = { |
986 | &disk_attr.attr, | 1008 | &disk_attr.attr, |
987 | &resume_attr.attr, | 1009 | &resume_attr.attr, |
988 | &image_size_attr.attr, | 1010 | &image_size_attr.attr, |
1011 | &reserved_size_attr.attr, | ||
989 | NULL, | 1012 | NULL, |
990 | }; | 1013 | }; |
991 | 1014 | ||
diff --git a/kernel/power/main.c b/kernel/power/main.c index de9aef8742f4..2981af4ce7cb 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -337,6 +337,7 @@ static int __init pm_init(void) | |||
337 | if (error) | 337 | if (error) |
338 | return error; | 338 | return error; |
339 | hibernate_image_size_init(); | 339 | hibernate_image_size_init(); |
340 | hibernate_reserved_size_init(); | ||
340 | power_kobj = kobject_create_and_add("power", NULL); | 341 | power_kobj = kobject_create_and_add("power", NULL); |
341 | if (!power_kobj) | 342 | if (!power_kobj) |
342 | return -ENOMEM; | 343 | return -ENOMEM; |
diff --git a/kernel/power/power.h b/kernel/power/power.h index 03634be55f62..9a00a0a26280 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -15,6 +15,7 @@ struct swsusp_info { | |||
15 | 15 | ||
16 | #ifdef CONFIG_HIBERNATION | 16 | #ifdef CONFIG_HIBERNATION |
17 | /* kernel/power/snapshot.c */ | 17 | /* kernel/power/snapshot.c */ |
18 | extern void __init hibernate_reserved_size_init(void); | ||
18 | extern void __init hibernate_image_size_init(void); | 19 | extern void __init hibernate_image_size_init(void); |
19 | 20 | ||
20 | #ifdef CONFIG_ARCH_HIBERNATION_HEADER | 21 | #ifdef CONFIG_ARCH_HIBERNATION_HEADER |
@@ -55,6 +56,7 @@ extern int hibernation_platform_enter(void); | |||
55 | 56 | ||
56 | #else /* !CONFIG_HIBERNATION */ | 57 | #else /* !CONFIG_HIBERNATION */ |
57 | 58 | ||
59 | static inline void hibernate_reserved_size_init(void) {} | ||
58 | static inline void hibernate_image_size_init(void) {} | 60 | static inline void hibernate_image_size_init(void) {} |
59 | #endif /* !CONFIG_HIBERNATION */ | 61 | #endif /* !CONFIG_HIBERNATION */ |
60 | 62 | ||
@@ -72,6 +74,8 @@ static struct kobj_attribute _name##_attr = { \ | |||
72 | 74 | ||
73 | /* Preferred image size in bytes (default 500 MB) */ | 75 | /* Preferred image size in bytes (default 500 MB) */ |
74 | extern unsigned long image_size; | 76 | extern unsigned long image_size; |
77 | /* Size of memory reserved for drivers (default SPARE_PAGES x PAGE_SIZE) */ | ||
78 | extern unsigned long reserved_size; | ||
75 | extern int in_suspend; | 79 | extern int in_suspend; |
76 | extern dev_t swsusp_resume_device; | 80 | extern dev_t swsusp_resume_device; |
77 | extern sector_t swsusp_resume_block; | 81 | extern sector_t swsusp_resume_block; |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index ca0aacc24874..d69e3323a85d 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -41,6 +41,18 @@ static void swsusp_set_page_forbidden(struct page *); | |||
41 | static void swsusp_unset_page_forbidden(struct page *); | 41 | static void swsusp_unset_page_forbidden(struct page *); |
42 | 42 | ||
43 | /* | 43 | /* |
44 | * Number of bytes to reserve for memory allocations made by device drivers | ||
45 | * from their ->freeze() and ->freeze_noirq() callbacks so that they don't | ||
46 | * cause image creation to fail (tunable via /sys/power/reserved_size). | ||
47 | */ | ||
48 | unsigned long reserved_size; | ||
49 | |||
50 | void __init hibernate_reserved_size_init(void) | ||
51 | { | ||
52 | reserved_size = SPARE_PAGES * PAGE_SIZE; | ||
53 | } | ||
54 | |||
55 | /* | ||
44 | * Preferred image size in bytes (tunable via /sys/power/image_size). | 56 | * Preferred image size in bytes (tunable via /sys/power/image_size). |
45 | * When it is set to N, the image creating code will do its best to | 57 | * When it is set to N, the image creating code will do its best to |
46 | * ensure the image size will not exceed N bytes, but if that is | 58 | * ensure the image size will not exceed N bytes, but if that is |
@@ -1263,11 +1275,13 @@ static unsigned long minimum_image_size(unsigned long saveable) | |||
1263 | * frame in use. We also need a number of page frames to be free during | 1275 | * frame in use. We also need a number of page frames to be free during |
1264 | * hibernation for allocations made while saving the image and for device | 1276 | * hibernation for allocations made while saving the image and for device |
1265 | * drivers, in case they need to allocate memory from their hibernation | 1277 | * drivers, in case they need to allocate memory from their hibernation |
1266 | * callbacks (these two numbers are given by PAGES_FOR_IO and SPARE_PAGES, | 1278 | * callbacks (these two numbers are given by PAGES_FOR_IO (which is a rough |
1267 | * respectively, both of which are rough estimates). To make this happen, we | 1279 | * estimate) and reserverd_size divided by PAGE_SIZE (which is tunable through |
1268 | * compute the total number of available page frames and allocate at least | 1280 | * /sys/power/reserved_size, respectively). To make this happen, we compute the |
1281 | * total number of available page frames and allocate at least | ||
1269 | * | 1282 | * |
1270 | * ([page frames total] + PAGES_FOR_IO + [metadata pages]) / 2 + 2 * SPARE_PAGES | 1283 | * ([page frames total] + PAGES_FOR_IO + [metadata pages]) / 2 |
1284 | * + 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE) | ||
1271 | * | 1285 | * |
1272 | * of them, which corresponds to the maximum size of a hibernation image. | 1286 | * of them, which corresponds to the maximum size of a hibernation image. |
1273 | * | 1287 | * |
@@ -1322,7 +1336,8 @@ int hibernate_preallocate_memory(void) | |||
1322 | count -= totalreserve_pages; | 1336 | count -= totalreserve_pages; |
1323 | 1337 | ||
1324 | /* Compute the maximum number of saveable pages to leave in memory. */ | 1338 | /* Compute the maximum number of saveable pages to leave in memory. */ |
1325 | max_size = (count - (size + PAGES_FOR_IO)) / 2 - 2 * SPARE_PAGES; | 1339 | max_size = (count - (size + PAGES_FOR_IO)) / 2 |
1340 | - 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE); | ||
1326 | /* Compute the desired number of image pages specified by image_size. */ | 1341 | /* Compute the desired number of image pages specified by image_size. */ |
1327 | size = DIV_ROUND_UP(image_size, PAGE_SIZE); | 1342 | size = DIV_ROUND_UP(image_size, PAGE_SIZE); |
1328 | if (size > max_size) | 1343 | if (size > max_size) |