From: Nick Piggin Date: Mon, 15 Jun 2009 10:35:10 +0000 (+0300) Subject: SLUB: Fix early boot GFP_DMA allocations X-Git-Tag: v2.6.31-rc1~290^2^2 X-Git-Url: http://ftp.safe.ca/?a=commitdiff_plain;h=964cf35c88f93b4927dbc4e950dfa4d880c7f9d1;hp=45e3e1935e2857c54783291107d33323b3ef33c8;p=safe%2Fjmp%2Flinux-2.6 SLUB: Fix early boot GFP_DMA allocations Recent change to use slab allocations earlier exposed a bug where SLUB can call schedule_work and try to call sysfs before it is safe to do so. Reported-by: Heiko Carstens Tested-by: Heiko Carstens Signed-off-by: Nick Piggin Signed-off-by: Pekka Enberg --- diff --git a/mm/slub.c b/mm/slub.c index 30354bf..dcbfda0 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2610,6 +2610,7 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags) struct kmem_cache *s; char *text; size_t realsize; + unsigned long slabflags; s = kmalloc_caches_dma[index]; if (s) @@ -2631,9 +2632,18 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags) (unsigned int)realsize); s = kmalloc(kmem_size, flags & ~SLUB_DMA); + /* + * Must defer sysfs creation to a workqueue because we don't know + * what context we are called from. Before sysfs comes up, we don't + * need to do anything because our sysfs initcall will start by + * adding all existing slabs to sysfs. + */ + slabflags = SLAB_CACHE_DMA; + if (slab_state >= SYSFS) + slabflags |= __SYSFS_ADD_DEFERRED; + if (!s || !text || !kmem_cache_open(s, flags, text, - realsize, ARCH_KMALLOC_MINALIGN, - SLAB_CACHE_DMA|__SYSFS_ADD_DEFERRED, NULL)) { + realsize, ARCH_KMALLOC_MINALIGN, slabflags, NULL)) { kfree(s); kfree(text); goto unlock_out; @@ -2642,7 +2652,8 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags) list_add(&s->list, &slab_caches); kmalloc_caches_dma[index] = s; - schedule_work(&sysfs_add_work); + if (slab_state >= SYSFS) + schedule_work(&sysfs_add_work); unlock_out: up_write(&slub_lock);