From 846955c8afe5ebca2f8841b042ca3342e08a092b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 22 Sep 2009 22:58:44 +0200 Subject: [S390] hibernation: fix guest page hinting related crash On resume the system that loads the to be resumed image might have unstable pages. When the resume image is copied back and a write access happen to an unstable page this causes an exception and the system crashes. To fix this set all free pages to stable before copying the resumed image data. Also after everything has been restored set all free pages of the resumed system to unstable again. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/swsusp_asm64.S | 7 ++++++ arch/s390/mm/page-states.c | 52 ++++++++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index 7cd6b096f0d1..9a86ccb91a8a 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S @@ -102,6 +102,9 @@ swsusp_arch_resume: aghi %r15,-STACK_FRAME_OVERHEAD stg %r1,__SF_BACKCHAIN(%r15) + /* Make all free pages stable */ + lghi %r2,1 + brasl %r14,arch_set_page_states #ifdef CONFIG_SMP /* Save boot cpu number */ brasl %r14,smp_get_phys_cpu_id @@ -178,6 +181,10 @@ swsusp_arch_resume: /* Activate DAT */ stosm __SF_EMPTY(%r15),0x04 + /* Make all free pages unstable */ + lghi %r2,0 + brasl %r14,arch_set_page_states + /* Return 0 */ lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) lghi %r2,0 diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c index f92ec203ad92..098923ae458f 100644 --- a/arch/s390/mm/page-states.c +++ b/arch/s390/mm/page-states.c @@ -50,28 +50,64 @@ void __init cmma_init(void) cmma_flag = 0; } -void arch_free_page(struct page *page, int order) +static inline void set_page_unstable(struct page *page, int order) { int i, rc; - if (!cmma_flag) - return; for (i = 0; i < (1 << order); i++) asm volatile(".insn rrf,0xb9ab0000,%0,%1,%2,0" : "=&d" (rc) - : "a" ((page_to_pfn(page) + i) << PAGE_SHIFT), + : "a" (page_to_phys(page + i)), "i" (ESSA_SET_UNUSED)); } -void arch_alloc_page(struct page *page, int order) +void arch_free_page(struct page *page, int order) { - int i, rc; - if (!cmma_flag) return; + set_page_unstable(page, order); +} + +static inline void set_page_stable(struct page *page, int order) +{ + int i, rc; + for (i = 0; i < (1 << order); i++) asm volatile(".insn rrf,0xb9ab0000,%0,%1,%2,0" : "=&d" (rc) - : "a" ((page_to_pfn(page) + i) << PAGE_SHIFT), + : "a" (page_to_phys(page + i)), "i" (ESSA_SET_STABLE)); } + +void arch_alloc_page(struct page *page, int order) +{ + if (!cmma_flag) + return; + set_page_stable(page, order); +} + +void arch_set_page_states(int make_stable) +{ + unsigned long flags, order, t; + struct list_head *l; + struct page *page; + struct zone *zone; + + if (!cmma_flag) + return; + if (make_stable) + drain_local_pages(NULL); + for_each_populated_zone(zone) { + spin_lock_irqsave(&zone->lock, flags); + for_each_migratetype_order(order, t) { + list_for_each(l, &zone->free_area[order].free_list[t]) { + page = list_entry(l, struct page, lru); + if (make_stable) + set_page_stable(page, order); + else + set_page_unstable(page, order); + } + } + spin_unlock_irqrestore(&zone->lock, flags); + } +} -- cgit v1.2.2