aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorAnisse Astier <anisse@astier.eu>2016-09-09 04:43:32 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-09-12 20:35:27 -0400
commit1ad1410f632d4141221634308a5e56f339f92009 (patch)
treeabe5eb613d5142ab3b8a6f273c1fd26efef8ffc2 /kernel/power
parentfa7fd6fa38e36d88bc9f2d0e45e5b9bd0387079f (diff)
PM / Hibernate: allow hibernation with PAGE_POISONING_ZERO
PAGE_POISONING_ZERO disables zeroing new pages on alloc, they are poisoned (zeroed) as they become available. In the hibernate use case, free pages will appear in the system without being cleared, left there by the loading kernel. This patch will make sure free pages are cleared on resume when PAGE_POISONING_ZERO is enabled. We free the pages just after resume because we can't do it later: going through any device resume code might allocate some memory and invalidate the free pages bitmap. Thus we don't need to disable hibernation when PAGE_POISONING_ZERO is enabled. Signed-off-by: Anisse Astier <anisse@astier.eu> Reviewed-by: Kees Cook <keescook@chromium.org> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/hibernate.c21
-rw-r--r--kernel/power/power.h2
-rw-r--r--kernel/power/snapshot.c22
3 files changed, 27 insertions, 18 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 33c79b6105c5..b26dbc48c75b 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -306,8 +306,10 @@ static int create_image(int platform_mode)
306 if (error) 306 if (error)
307 printk(KERN_ERR "PM: Error %d creating hibernation image\n", 307 printk(KERN_ERR "PM: Error %d creating hibernation image\n",
308 error); 308 error);
309 if (!in_suspend) 309 if (!in_suspend) {
310 events_check_enabled = false; 310 events_check_enabled = false;
311 clear_free_pages();
312 }
311 313
312 platform_leave(platform_mode); 314 platform_leave(platform_mode);
313 315
@@ -1189,22 +1191,6 @@ static int __init nohibernate_setup(char *str)
1189 return 1; 1191 return 1;
1190} 1192}
1191 1193
1192static int __init page_poison_nohibernate_setup(char *str)
1193{
1194#ifdef CONFIG_PAGE_POISONING_ZERO
1195 /*
1196 * The zeroing option for page poison skips the checks on alloc.
1197 * since hibernation doesn't save free pages there's no way to
1198 * guarantee the pages will still be zeroed.
1199 */
1200 if (!strcmp(str, "on")) {
1201 pr_info("Disabling hibernation due to page poisoning\n");
1202 return nohibernate_setup(str);
1203 }
1204#endif
1205 return 1;
1206}
1207
1208__setup("noresume", noresume_setup); 1194__setup("noresume", noresume_setup);
1209__setup("resume_offset=", resume_offset_setup); 1195__setup("resume_offset=", resume_offset_setup);
1210__setup("resume=", resume_setup); 1196__setup("resume=", resume_setup);
@@ -1212,4 +1198,3 @@ __setup("hibernate=", hibernate_setup);
1212__setup("resumewait", resumewait_setup); 1198__setup("resumewait", resumewait_setup);
1213__setup("resumedelay=", resumedelay_setup); 1199__setup("resumedelay=", resumedelay_setup);
1214__setup("nohibernate", nohibernate_setup); 1200__setup("nohibernate", nohibernate_setup);
1215__setup("page_poison=", page_poison_nohibernate_setup);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 242d8b827dd5..56d1d0dedf76 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -110,6 +110,8 @@ extern int create_basic_memory_bitmaps(void);
110extern void free_basic_memory_bitmaps(void); 110extern void free_basic_memory_bitmaps(void);
111extern int hibernate_preallocate_memory(void); 111extern int hibernate_preallocate_memory(void);
112 112
113extern void clear_free_pages(void);
114
113/** 115/**
114 * Auxiliary structure used for reading the snapshot image data and 116 * Auxiliary structure used for reading the snapshot image data and
115 * metadata from and writing them to the list of page backup entries 117 * metadata from and writing them to the list of page backup entries
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index b02228411d57..4f0f0604f1c4 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -1132,6 +1132,28 @@ void free_basic_memory_bitmaps(void)
1132 pr_debug("PM: Basic memory bitmaps freed\n"); 1132 pr_debug("PM: Basic memory bitmaps freed\n");
1133} 1133}
1134 1134
1135void clear_free_pages(void)
1136{
1137#ifdef CONFIG_PAGE_POISONING_ZERO
1138 struct memory_bitmap *bm = free_pages_map;
1139 unsigned long pfn;
1140
1141 if (WARN_ON(!(free_pages_map)))
1142 return;
1143
1144 memory_bm_position_reset(bm);
1145 pfn = memory_bm_next_pfn(bm);
1146 while (pfn != BM_END_OF_MAP) {
1147 if (pfn_valid(pfn))
1148 clear_highpage(pfn_to_page(pfn));
1149
1150 pfn = memory_bm_next_pfn(bm);
1151 }
1152 memory_bm_position_reset(bm);
1153 pr_info("PM: free pages cleared after restore\n");
1154#endif /* PAGE_POISONING_ZERO */
1155}
1156
1135/** 1157/**
1136 * snapshot_additional_pages - Estimate the number of extra pages needed. 1158 * snapshot_additional_pages - Estimate the number of extra pages needed.
1137 * @zone: Memory zone to carry out the computation for. 1159 * @zone: Memory zone to carry out the computation for.