Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 2330

kernel-2.6.18-128.1.10.el5.src.rpm

From: Nigel Cunningham <ncunning@redhat.com>
Subject: [RHEL5 PATCH] BZ 215954 Fix x86_64/relocatable kernel/swsusp 	breakage.
Date: Tue, 20 Feb 2007 15:40:09 +1100
Bugzilla: 215954
Message-Id: <1171946409.9627.15.camel@nigel.suspend2.net>
Changelog: [suspend] Fix x86_64/relocatable kernel/swsusp breakage.


Hi all.

This patch the three issues that cause swsusp to fail on x86_64 with
relocatable kernels:

1) __pa -> __pa_symbol equivalent modification needed in the assembly
for switching back to the resumed kernel's page tables. Without this,
the kernel reboots after copying the original data back
2) __pa -> __pa_symbol needed for nosave_begin_pfn and nosave_end_pfn.
With (1) but without this, __nosave data is included in the saved image,
so after restoring the original kernel context, the computer thinks it's
suspending, writes an empty image and powers down again.
3) swap header address fixes, needed because the page used for reading
and writing the header isn't allocated as needed, and therefore also
needs the __pa -> __pa_symbol conversion.

Many thanks to Vivek for his help - relocatable kernels were a mystery
to me. The Signed-off-by for Vivek is for the asm modifications; blame
me for the rest.

Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
Signed-off-by: Nigel Cunningham <ncunning@redhat.com>

diff -ruN linux-2.6.18.noarch/arch/x86_64/kernel/suspend_asm.S working-linux-2.6.18.x86_64-clean/arch/x86_64/kernel/suspend_asm.S
--- linux-2.6.18.noarch/arch/x86_64/kernel/suspend_asm.S	2006-09-19 23:42:06.000000000 -0400
+++ working-linux-2.6.18.x86_64-clean/arch/x86_64/kernel/suspend_asm.S	2007-02-19 22:00:37.000000000 -0500
@@ -71,8 +71,8 @@
 	jmp	loop
 done:
 	/* go back to the original page tables */
-	leaq	init_level4_pgt(%rip), %rax
-	subq	$__START_KERNEL_map, %rax
+	movq	$(init_level4_pgt - __START_KERNEL_map), %rax
+	addq	phys_base(%rip), %rax
 	movq	%rax, %cr3
 	/* Flush TLB, including "global" things (vmalloc) */
 	movq	mmu_cr4_features(%rip), %rax
diff -ruN linux-2.6.18.noarch/kernel/power/snapshot.c working-linux-2.6.18.x86_64-clean/kernel/power/snapshot.c
--- linux-2.6.18.noarch/kernel/power/snapshot.c	2007-02-19 22:50:24.000000000 -0500
+++ working-linux-2.6.18.x86_64-clean/kernel/power/snapshot.c	2007-02-19 22:41:58.000000000 -0500
@@ -158,8 +158,8 @@
 
 static inline int pfn_is_nosave(unsigned long pfn)
 {
-	unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
-	unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT;
+	unsigned long nosave_begin_pfn = __pa_symbol(&__nosave_begin) >> PAGE_SHIFT;
+	unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT;
 	return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
 }
 
diff -ruN linux-2.6.18.noarch/kernel/power/swap.c working-linux-2.6.18.x86_64-clean/kernel/power/swap.c
--- linux-2.6.18.noarch/kernel/power/swap.c	2007-02-19 22:50:24.000000000 -0500
+++ working-linux-2.6.18.x86_64-clean/kernel/power/swap.c	2007-02-19 22:16:04.000000000 -0500
@@ -40,6 +40,12 @@
 	char	sig[10];
 } __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header;
 
+#if defined(__pa_symbol)
+#define SWSUSP_HEADER_VIRT (__va(__pa_symbol(&swsusp_header)))
+#else
+#define SWSUSP_HEADER_VIRT (&swsusp_header)
+#endif
+
 /*
  * Saving part...
  */
@@ -51,14 +57,14 @@
 	int error;
 
 	rw_swap_page_sync(READ, swp_entry(root_swap, 0),
-			  virt_to_page((unsigned long)&swsusp_header), NULL);
+			  virt_to_page(SWSUSP_HEADER_VIRT), NULL);
 	if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) ||
 	    !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
 		memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
 		memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
 		swsusp_header.image = start;
 		error = rw_swap_page_sync(WRITE, swp_entry(root_swap, 0),
-				virt_to_page((unsigned long)&swsusp_header),
+				virt_to_page(SWSUSP_HEADER_VIRT),
 				NULL);
 	} else {
 		pr_debug("swsusp: Partition is not swap space.\n");
@@ -599,12 +605,12 @@
 	if (!IS_ERR(resume_bdev)) {
 		set_blocksize(resume_bdev, PAGE_SIZE);
 		memset(&swsusp_header, 0, sizeof(swsusp_header));
-		if ((error = bio_read_page(0, &swsusp_header, NULL)))
+		if ((error = bio_read_page(0, SWSUSP_HEADER_VIRT, NULL)))
 			return error;
 		if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
 			memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
 			/* Reset swap signature now */
-			error = bio_write_page(0, &swsusp_header);
+			error = bio_write_page(0, SWSUSP_HEADER_VIRT);
 		} else {
 			return -EINVAL;
 		}