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 c3a736a..aa0ab02 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 aa1494d..c479d2f 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 d4ca4e0..c487be4 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