kernel/power: allow hibernation with page_poison sanity checking
authorVlastimil Babka <vbabka@suse.cz>
Tue, 15 Dec 2020 03:13:38 +0000 (19:13 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 15 Dec 2020 20:13:46 +0000 (12:13 -0800)
Page poisoning used to be incompatible with hibernation, as the state of
poisoned pages was lost after resume, thus enabling CONFIG_HIBERNATION
forces CONFIG_PAGE_POISONING_NO_SANITY.  For the same reason, the
poisoning with zeroes variant CONFIG_PAGE_POISONING_ZERO used to disable
hibernation.  The latter restriction was removed by commit 1ad1410f632d
("PM / Hibernate: allow hibernation with PAGE_POISONING_ZERO") and
similarly for init_on_free by commit 18451f9f9e58 ("PM: hibernate: fix
crashes with init_on_free=1") by making sure free pages are cleared after
resume.

We can use the same mechanism to instead poison free pages with
PAGE_POISON after resume.  This covers both zero and 0xAA patterns.  Thus
we can remove the Kconfig restriction that disables page poison sanity
checking when hibernation is enabled.

Link: https://lkml.kernel.org/r/20201113104033.22907-4-vbabka@suse.cz
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> [hibernation]
Reviewed-by: David Hildenbrand <david@redhat.com>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Laura Abbott <labbott@kernel.org>
Cc: Mateusz Nosek <mateusznosek0@gmail.com>
Cc: Michal Hocko <mhocko@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/mm.h
kernel/power/hibernate.c
kernel/power/power.h
kernel/power/snapshot.c
mm/Kconfig.debug

index 026707a..3e1fe8c 100644 (file)
@@ -2903,6 +2903,7 @@ static inline void kernel_unpoison_pages(struct page *page, int numpages)
 #else
 static inline bool page_poisoning_enabled(void) { return false; }
 static inline bool page_poisoning_enabled_static(void) { return false; }
+static inline void __kernel_poison_pages(struct page *page, int nunmpages) { }
 static inline void kernel_poison_pages(struct page *page, int numpages) { }
 static inline void kernel_unpoison_pages(struct page *page, int numpages) { }
 #endif
index 2fc7d50..da0b419 100644 (file)
@@ -326,7 +326,7 @@ static int create_image(int platform_mode)
 
        if (!in_suspend) {
                events_check_enabled = false;
-               clear_free_pages();
+               clear_or_poison_free_pages();
        }
 
        platform_leave(platform_mode);
index 24f12d5..778bf43 100644 (file)
@@ -106,7 +106,7 @@ extern int create_basic_memory_bitmaps(void);
 extern void free_basic_memory_bitmaps(void);
 extern int hibernate_preallocate_memory(void);
 
-extern void clear_free_pages(void);
+extern void clear_or_poison_free_pages(void);
 
 /**
  *     Auxiliary structure used for reading the snapshot image data and
index d848377..d63560e 100644 (file)
@@ -1178,7 +1178,15 @@ void free_basic_memory_bitmaps(void)
        pr_debug("Basic memory bitmaps freed\n");
 }
 
-void clear_free_pages(void)
+static void clear_or_poison_free_page(struct page *page)
+{
+       if (page_poisoning_enabled_static())
+               __kernel_poison_pages(page, 1);
+       else if (want_init_on_free())
+               clear_highpage(page);
+}
+
+void clear_or_poison_free_pages(void)
 {
        struct memory_bitmap *bm = free_pages_map;
        unsigned long pfn;
@@ -1186,12 +1194,12 @@ void clear_free_pages(void)
        if (WARN_ON(!(free_pages_map)))
                return;
 
-       if (IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) || want_init_on_free()) {
+       if (page_poisoning_enabled() || want_init_on_free()) {
                memory_bm_position_reset(bm);
                pfn = memory_bm_next_pfn(bm);
                while (pfn != BM_END_OF_MAP) {
                        if (pfn_valid(pfn))
-                               clear_highpage(pfn_to_page(pfn));
+                               clear_or_poison_free_page(pfn_to_page(pfn));
 
                        pfn = memory_bm_next_pfn(bm);
                }
index 864f129..c57786a 100644 (file)
@@ -64,7 +64,6 @@ config PAGE_OWNER
 
 config PAGE_POISONING
        bool "Poison pages after freeing"
-       select PAGE_POISONING_NO_SANITY if HIBERNATION
        help
          Fill the pages with poison patterns after free_pages() and verify
          the patterns before alloc_pages. The filling of the memory helps