Hi,
The current 2.6.18-xen tree's kexec seems to be working for me OK on
x86_64 and on small i686 boxes, but it is broken on >1GB 32-bit
configurations, oopsing when the kexec kernel is set up with:
BUG: unable to handle kernel NULL pointer dereference at virtual
address 00000000
...
CPU: 0
EIP: 0061:[<c0415550>] Not tainted VLI
EFLAGS: 00010216 (2.6.18-20.el5.kraxel.7xen #1)
EIP is at xen_create_contiguous_region+0x9c/0x44b
eax: 00000000 ebx: 00001000 ecx: 00000400 edx: 00000000
esi: 0000000b edi: 00000000 ebp: 00000001 esp: ea292e90
ds: 007b es: 007b ss: 0069
Process kexec (pid: 2439, ti=ea292000 task=ea577aa0 task.ti=ea292000)
...
Call Trace:
[<c044ac8f>] get_page_from_freelist+0x1c1/0x325
[<c044fc72>] page_address+0x7a/0x81
[<c0438f04>] kimage_alloc_pages+0x64/0xa2
[<c0438fdf>] kimage_alloc_page+0x9d/0x2a5
[<c0439226>] kimage_add_entry+0x3f/0xbd
[<c0439780>] sys_kexec_load+0x2a0/0x3f7
[<c040534f>] syscall_call+0x7/0xb
=======================
I'm using the kexec code back-ported to the RHEL-5 kernel atm, but
current xen-unstable.hg appears to have the same problem.
The problem is in kimage_alloc_pages(), which tries to return contiguous
pages by calling
xen_create_contiguous_region((unsigned long)page_address(pages),
order, address_bits)
on the pages allocated. Unfortunately, page_address() returns NULL for
highmem pages. So as soon as we try this on a page in the highmem heap,
we get the above OOPS.
Fortunately it's easy to fix: we don't need to call
xen_create_contiguous_region() on highmem pages, because the only place
I can see in kexec which uses GFP_HIGHMEM also allocates only single
pages at a time (and those are by definition always contiguous anyway!)
So we really only need to call xen_(create|destroy)_contiguous_region()
if order>0. That will continue to do the right thing for lowmem high-
order allocations, while allowing single-page GFP_HIGHEM allocations to
work.
The patch below fixes this for me.
--Stephen
Don't try to call xen_create_contiguous_region() on highmem pages. It
won't work --- page_address() returns NULL on such pages --- but is also
unnecesary because the only place in kexec which uses GFP_HIGHMEM also
allocates only single pages at a time (and those are by definition
always contiguous anyway.)
So we really only need to call xen_(create|destroy)_contiguous_region()
if order>0. That will continue to do the right thing for lowmem
high-order allocations, while allowing single-page GFP_HIGHEM
allocations to work.
Signed-off-by: Stephen Tweedie <sct@xxxxxxxxxx>
--- linux-2.6.18.noarch/kernel/kexec.c.=K0010=.orig
+++ linux-2.6.18.noarch/kernel/kexec.c
@@ -345,10 +345,13 @@ static struct page *kimage_alloc_pages(g
else
address_bits = long_log2(limit);
- if (xen_create_contiguous_region((unsigned
long)page_address(pages),
- order, address_bits) < 0) {
- __free_pages(pages, order);
- return NULL;
+ if (order > 0) {
+ BUG_ON(gfp_mask & __GFP_HIGHMEM);
+ if (xen_create_contiguous_region((unsigned
long)page_address(pages),
+ order, address_bits) <
0) {
+ __free_pages(pages, order);
+ return NULL;
+ }
}
#endif
pages->mapping = NULL;
@@ -370,7 +373,8 @@ static void kimage_free_pages(struct pag
for (i = 0; i < count; i++)
ClearPageReserved(page + i);
#ifdef CONFIG_XEN
- xen_destroy_contiguous_region((unsigned long)page_address(page), order);
+ if (order > 0)
+ xen_destroy_contiguous_region((unsigned
long)page_address(page), order);
#endif
__free_pages(page, order);
}
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|