diff options
author | Nick Piggin <npiggin@suse.de> | 2009-06-15 06:35:10 -0400 |
---|---|---|
committer | Pekka Enberg <penberg@cs.helsinki.fi> | 2009-06-15 06:55:26 -0400 |
commit | 964cf35c88f93b4927dbc4e950dfa4d880c7f9d1 (patch) | |
tree | a5be2d66c2a53e9483007f7581bb5170f50d6ff7 | |
parent | 45e3e1935e2857c54783291107d33323b3ef33c8 (diff) |
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 <heiko.carstens@de.ibm.com>
Tested-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
-rw-r--r-- | mm/slub.c | 17 |
1 files changed, 14 insertions, 3 deletions
@@ -2610,6 +2610,7 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags) | |||
2610 | struct kmem_cache *s; | 2610 | struct kmem_cache *s; |
2611 | char *text; | 2611 | char *text; |
2612 | size_t realsize; | 2612 | size_t realsize; |
2613 | unsigned long slabflags; | ||
2613 | 2614 | ||
2614 | s = kmalloc_caches_dma[index]; | 2615 | s = kmalloc_caches_dma[index]; |
2615 | if (s) | 2616 | if (s) |
@@ -2631,9 +2632,18 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags) | |||
2631 | (unsigned int)realsize); | 2632 | (unsigned int)realsize); |
2632 | s = kmalloc(kmem_size, flags & ~SLUB_DMA); | 2633 | s = kmalloc(kmem_size, flags & ~SLUB_DMA); |
2633 | 2634 | ||
2635 | /* | ||
2636 | * Must defer sysfs creation to a workqueue because we don't know | ||
2637 | * what context we are called from. Before sysfs comes up, we don't | ||
2638 | * need to do anything because our sysfs initcall will start by | ||
2639 | * adding all existing slabs to sysfs. | ||
2640 | */ | ||
2641 | slabflags = SLAB_CACHE_DMA; | ||
2642 | if (slab_state >= SYSFS) | ||
2643 | slabflags |= __SYSFS_ADD_DEFERRED; | ||
2644 | |||
2634 | if (!s || !text || !kmem_cache_open(s, flags, text, | 2645 | if (!s || !text || !kmem_cache_open(s, flags, text, |
2635 | realsize, ARCH_KMALLOC_MINALIGN, | 2646 | realsize, ARCH_KMALLOC_MINALIGN, slabflags, NULL)) { |
2636 | SLAB_CACHE_DMA|__SYSFS_ADD_DEFERRED, NULL)) { | ||
2637 | kfree(s); | 2647 | kfree(s); |
2638 | kfree(text); | 2648 | kfree(text); |
2639 | goto unlock_out; | 2649 | goto unlock_out; |
@@ -2642,7 +2652,8 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags) | |||
2642 | list_add(&s->list, &slab_caches); | 2652 | list_add(&s->list, &slab_caches); |
2643 | kmalloc_caches_dma[index] = s; | 2653 | kmalloc_caches_dma[index] = s; |
2644 | 2654 | ||
2645 | schedule_work(&sysfs_add_work); | 2655 | if (slab_state >= SYSFS) |
2656 | schedule_work(&sysfs_add_work); | ||
2646 | 2657 | ||
2647 | unlock_out: | 2658 | unlock_out: |
2648 | up_write(&slub_lock); | 2659 | up_write(&slub_lock); |