Messages in this thread Patch in this message |  | | Date | Sat, 6 Oct 2001 17:31:26 +0200 (CEST) | From | Mikulas Patocka <> | Subject | Re: %u-order allocation failed |
| |
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)); |  |