s390/hibernate: Save and restore absolute zero pages
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>
Mon, 8 Apr 2013 14:09:31 +0000 (16:09 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 17 Apr 2013 12:07:30 +0000 (14:07 +0200)
Since commit 5f954c34 ([S390] hibernation: fix lowcore handling)
the absolute zero lowcore is lost during suspend/resume.
For example, this leads to the problem that the re-IPL device
for kdump is no longer set after resume.

With this patch during suspend a buffer is allocated in the new PM
notifier "suspend_pm_cb" and then the absolute zero lowcore is saved
to that buffer. The resume code then copies back this buffer to
absolute zero and afterwards the PM notifier releases the memory.

Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/kernel/entry.h
arch/s390/kernel/suspend.c
arch/s390/kernel/swsusp_asm64.S

index c3a736a3ed4458f0187d8f041f62fb1e590d877e..aa0ab02e9595f8c6d21d6827a8b0ca261c0d71ec 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/cputime.h>
 
 extern void *restart_stack;
+extern unsigned long suspend_zero_pages;
 
 void system_call(void);
 void pgm_check_handler(void);
index aa1494d0e380f907f56c74e53198dcad2dff592d..c479d2f9605ba6ef3dede5a669be872f97494b0f 100644 (file)
@@ -41,6 +41,7 @@ struct page_key_data {
 static struct page_key_data *page_key_data;
 static struct page_key_data *page_key_rp, *page_key_wp;
 static unsigned long page_key_rx, page_key_wx;
+unsigned long suspend_zero_pages;
 
 /*
  * For each page in the hibernation image one additional byte is
@@ -149,6 +150,36 @@ int pfn_is_nosave(unsigned long pfn)
        return 0;
 }
 
+/*
+ * PM notifier callback for suspend
+ */
+static int suspend_pm_cb(struct notifier_block *nb, unsigned long action,
+                        void *ptr)
+{
+       switch (action) {
+       case PM_SUSPEND_PREPARE:
+       case PM_HIBERNATION_PREPARE:
+               suspend_zero_pages = __get_free_pages(GFP_KERNEL, LC_ORDER);
+               if (!suspend_zero_pages)
+                       return NOTIFY_BAD;
+               break;
+       case PM_POST_SUSPEND:
+       case PM_POST_HIBERNATION:
+               free_pages(suspend_zero_pages, LC_ORDER);
+               break;
+       default:
+               return NOTIFY_DONE;
+       }
+       return NOTIFY_OK;
+}
+
+static int __init suspend_pm_init(void)
+{
+       pm_notifier(suspend_pm_cb, 0);
+       return 0;
+}
+arch_initcall(suspend_pm_init);
+
 void save_processor_state(void)
 {
        /* swsusp_arch_suspend() actually saves all cpu register contents.
index d4ca4e0617b52ae12e039a6110ef4872f9de07ee..c487be4cfc81c5a9cf288b448ec049b0f11fec66 100644 (file)
@@ -36,8 +36,8 @@ ENTRY(swsusp_arch_suspend)
        /* Store prefix register on stack */
        stpx    __SF_EMPTY(%r15)
 
-       /* Save prefix register contents for lowcore */
-       llgf    %r4,__SF_EMPTY(%r15)
+       /* Save prefix register contents for lowcore copy */
+       llgf    %r10,__SF_EMPTY(%r15)
 
        /* Get pointer to save area */
        lghi    %r1,0x1000
@@ -91,7 +91,18 @@ ENTRY(swsusp_arch_suspend)
        xc      __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
        spx     __SF_EMPTY(%r15)
 
+       /* Save absolute zero pages */
+       larl    %r2,suspend_zero_pages
+       lg      %r2,0(%r2)
+       lghi    %r4,0
+       lghi    %r3,2*PAGE_SIZE
+       lghi    %r5,2*PAGE_SIZE
+1:     mvcle   %r2,%r4,0
+       jo      1b
+
+       /* Copy lowcore to absolute zero lowcore */
        lghi    %r2,0
+       lgr     %r4,%r10
        lghi    %r3,2*PAGE_SIZE
        lghi    %r5,2*PAGE_SIZE
 1:     mvcle   %r2,%r4,0
@@ -248,8 +259,20 @@ restore_registers:
        /* Load old stack */
        lg      %r15,0x2f8(%r13)
 
+       /* Save prefix register */
+       mvc __SF_EMPTY(4,%r15),0x318(%r13)
+
+       /* Restore absolute zero pages */
+       lghi    %r2,0
+       larl    %r4,suspend_zero_pages
+       lg      %r4,0(%r4)
+       lghi    %r3,2*PAGE_SIZE
+       lghi    %r5,2*PAGE_SIZE
+1:     mvcle   %r2,%r4,0
+       jo      1b
+
        /* Restore prefix register */
-       spx     0x318(%r13)
+       spx     __SF_EMPTY(%r15)
 
        /* Activate DAT */
        stosm   __SF_EMPTY(%r15),0x04