Re: %u-order allocation failed

From: Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz)
Date: Sat Oct 06 2001 - 10:31:26 EST


On Sat, 6 Oct 2001, Mikulas Patocka wrote:

> On Sat, 6 Oct 2001, Rik van Riel wrote:
>
> > On Sat, 6 Oct 2001, Mikulas Patocka wrote:
> >
> > > Buddy allocator is broken - kill it. Or at least do not misuse it for
> > > anything except kernel or driver initialization.
> >
> > Please send patches to get rid of the buddy allocator while
> > still making it possible to allocate contiguous chunks of
> > memory.
> >
> > If you have any idea on how to fix things, this would be a
> > good time to let us know.
>
> Here goes the fix. (note that I didn't try to compile it so there may be
> bugs, but you see the point).
>
> kmalloc should be fixed too (used badly for example in select.c - and yes
> - I have seen real world bugreports for poll randomly failing with
> ENOMEM), but it will be hard to audit all drivers that they do not try to
> use dma on kmallocated memory.

This is enhanced version of a patch that fixes select and poll as well.
Again - not compiled, not tried.

Mikulas

diff -u -r linux-orig/fs/select.c linux/fs/select.c
--- linux-orig/fs/select.c Sat Oct 6 16:20:45 2001
+++ linux/fs/select.c Sat Oct 6 16:54:44 2001
@@ -236,7 +236,7 @@
 
 static void *select_bits_alloc(int size)
 {
- return kmalloc(6 * size, GFP_KERNEL);
+ return kmalloc(6 * size, GFP_KERNEL | __GFP_VMALLOC);
 }
 
 static void select_bits_free(void *bits, int size)
@@ -438,7 +438,7 @@
         if (nfds != 0) {
                 fds = (struct pollfd **)kmalloc(
                         (1 + (nfds - 1) / POLLFD_PER_PAGE) * sizeof(struct pollfd *),
- GFP_KERNEL);
+ GFP_KERNEL | __GFP_VMALLOC);
                 if (fds == NULL)
                         goto out;
         }
diff -u -r linux-orig/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- linux-orig/include/asm-i386/processor.h Sat Oct 6 16:21:50 2001
+++ linux/include/asm-i386/processor.h Sat Oct 6 16:31:15 2001
@@ -448,7 +448,7 @@
 #define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
 
 #define THREAD_SIZE (2*PAGE_SIZE)
-#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
+#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL | __GFP_VMALLOC,1))
 #define free_task_struct(p) free_pages((unsigned long) (p), 1)
 #define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count)
 
diff -u -r linux-orig/include/linux/mm.h linux/include/linux/mm.h
--- linux-orig/include/linux/mm.h Sat Oct 6 16:21:59 2001
+++ linux/include/linux/mm.h Sat Oct 6 16:28:12 2001
@@ -550,6 +550,7 @@
 #define __GFP_IO 0x40 /* Can start low memory physical IO? */
 #define __GFP_HIGHIO 0x80 /* Can start high mem physical IO? */
 #define __GFP_FS 0x100 /* Can call down to low-level FS? */
+#define __GFP_VMALLOC 0x200 /* Can vmalloc pages if buddy allocator fails */
 
 #define GFP_NOHIGHIO (__GFP_HIGH | __GFP_WAIT | __GFP_IO)
 #define GFP_NOIO (__GFP_HIGH | __GFP_WAIT)
diff -u -r linux-orig/mm/page_alloc.c linux/mm/page_alloc.c
--- linux-orig/mm/page_alloc.c Sat Oct 6 16:21:47 2001
+++ linux/mm/page_alloc.c Sat Oct 6 16:36:28 2001
@@ -18,6 +18,7 @@
 #include <linux/bootmem.h>
 #include <linux/slab.h>
 #include <linux/compiler.h>
+#include <linux/vmalloc.h>
 
 int nr_swap_pages;
 int nr_active_pages;
@@ -421,9 +422,9 @@
         struct page * page;
 
         page = alloc_pages(gfp_mask, order);
- if (!page)
- return 0;
- return (unsigned long) page_address(page);
+ if (page) return (unsigned long) page_address(page);
+ if (gfp_mask & __GFP_VMALLOC) return (unsigned long)__vmalloc(PAGE_SIZE << order, gfp_mask, PAGE_KERNEL);
+ return 0;
 }
 
 unsigned long get_zeroed_page(unsigned int gfp_mask)
@@ -447,6 +448,10 @@
 
 void free_pages(unsigned long addr, unsigned int order)
 {
+ if (addr >= VMALLOC_START && addr < VMALLOC_END) {
+ vfree((void *)addr);
+ return;
+ }
         if (addr != 0)
                 __free_pages(virt_to_page(addr), order);
 }
diff -u -r linux-orig/mm/slab.c linux/mm/slab.c
--- linux-orig/mm/slab.c Sat Oct 6 16:21:48 2001
+++ linux/mm/slab.c Sat Oct 6 17:04:37 2001
@@ -73,6 +73,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/compiler.h>
+#include <linux/vmalloc.h>
 #include <asm/uaccess.h>
 
 /*
@@ -1536,10 +1537,14 @@
         cache_sizes_t *csizep = cache_sizes;
 
         for (; csizep->cs_size; csizep++) {
+ void *p;
                 if (size > csizep->cs_size)
                         continue;
- return __kmem_cache_alloc(flags & GFP_DMA ?
- csizep->cs_dmacachep : csizep->cs_cachep, flags);
+ if ((p = __kmem_cache_alloc(flags & GFP_DMA ?
+ csizep->cs_dmacachep : csizep->cs_cachep, flags & ~__GFP_VMALLOC)))
+ return p;
+ if (flags & __GFP_VMALLOC) return __vmalloc(size, flags, PAGE_KERNEL);
+ return NULL;
         }
         return NULL;
 }
@@ -1580,6 +1585,10 @@
 
         if (!objp)
                 return;
+ if ((unsigned long)objp >= VMALLOC_START && (unsigned long)obj < VMALLOC_END) {
+ vfree(objp);
+ return;
+ }
         local_irq_save(flags);
         CHECK_PAGE(virt_to_page(objp));
         c = GET_PAGE_CACHE(virt_to_page(objp));
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sun Oct 07 2001 - 21:00:42 EST