[PATCH] Fixes for prep_zero_page

From: Zwane Mwaikambo
Date: Sun Jan 09 2005 - 10:57:21 EST


On Sun, 9 Jan 2005, Andrew Morton wrote:

> Well it's doing clear_highpage() before __alloc_pages() has called
> kernel_map_pages(), so CONFIG_DEBUG_PAGEALLOC is quite kaput.
>
> So the current __GFP_ZERO buglist is:
>
> 1: Breaks CONFIG_DEBUG_PAGEALLOC
>
> 2: Breaks the cache aliasing protection for anonymous pages
>
> 3: prep_zero_page() uses KM_USER0 so __GFP_ZERO from IRQ context will
> cause rare memory corruption.

The following should take care of 1 and 3. I opted to unmap the pages
again after the clear page so that it remains isolated and we don't have
to make additional checks to see if we should unmap the pages.

Signed-off-by: Zwane Mwaikambo <zwane@xxxxxxxxxxxxxxxx>

Index: linux-2.6.10-mm2/include/linux/highmem.h
===================================================================
RCS file: /home/cvsroot/linux-2.6.10-mm2/include/linux/highmem.h,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 highmem.h
--- linux-2.6.10-mm2/include/linux/highmem.h 9 Jan 2005 04:51:52 -0000 1.1.1.1
+++ linux-2.6.10-mm2/include/linux/highmem.h 9 Jan 2005 15:32:17 -0000
@@ -50,6 +50,18 @@ static inline void clear_highpage(struct
kunmap_atomic(kaddr, KM_USER0);
}

+static inline void clear_irq_highpage(struct page *page)
+{
+ char *kaddr;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ kaddr = kmap_atomic(page, KM_IRQ0);
+ clear_page(kaddr);
+ kunmap_atomic(kaddr, KM_IRQ0);
+ local_irq_restore(flags);
+}
+
/*
* Same but also flushes aliased cache contents to RAM.
*/
Index: linux-2.6.10-mm2/mm/page_alloc.c
===================================================================
RCS file: /home/cvsroot/linux-2.6.10-mm2/mm/page_alloc.c,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 page_alloc.c
--- linux-2.6.10-mm2/mm/page_alloc.c 9 Jan 2005 04:52:40 -0000 1.1.1.1
+++ linux-2.6.10-mm2/mm/page_alloc.c 9 Jan 2005 15:46:00 -0000
@@ -691,10 +691,17 @@ perthread_pages_alloc(void)
*/
static inline void prep_zero_page(struct page *page, int order)
{
- int i;
+ int i, nr_pages = (1 << order);
+ int context = in_interrupt();

- for(i = 0; i < (1 << order); i++)
- clear_highpage(page + i);
+ kernel_map_pages(page, nr_pages, 1);
+ for(i = 0; i < nr_pages; i++) {
+ if (likely(!context))
+ clear_highpage(page + i);
+ else
+ clear_irq_highpage(page + i);
+ }
+ kernel_map_pages(page, nr_pages, 0);
}

static struct page *
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/