[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [patch] kexec is not highmem-aware



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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.