Messages in this thread Patch in this message |  | | Date | Tue, 8 Apr 2008 01:05:14 +0300 (EEST) | From | Pekka J Enberg <> | Subject | Re: [PATCH] scsi: fix sense_slab/bio swapping livelock |
| |
On Tue, 8 Apr 2008, Pekka Enberg wrote: > Actually, a trivial way to implement that is to have a few "emergency kmalloc" > caches say for sizes 64, 128, 256, and 512 that have some pre-allocated pages > into which these GFP_TEMPORARY allocations are allowed to dip into on OOM and > OOM only.
So something like the following (totally untested) patch modulo the pre-allocation bits.
Pekka
diff --git a/mm/slub.c b/mm/slub.c index acc975f..e8f7cf3 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -264,6 +264,67 @@ static inline void stat(struct kmem_cache_cpu *c, enum stat_item si) #endif } +/* + * Emergency caches are for GFP_TEMPORARY allocations to dip into when we're + * OOM to make sure we can make some progress for writeback. + */ + +#define MIN_EMERGENCY_SIZE 32 +#define NR_EMERGENCY_CACHES 4 + +struct kmem_cache *emergency_caches[NR_EMERGENCY_CACHES]; + +static void init_emergency_caches(void) +{ + unsigned long size = MIN_EMERGENCY_SIZE; + int i; + + for (i = 0; i < NR_EMERGENCY_CACHES; i++) { + struct kmem_cache *cache; + char *name; + + name = kasprintf(GFP_KERNEL, "kmalloc-%d", 1 << i); + BUG_ON(!name); + + cache = kmem_cache_create(name, size, 0, 0, NULL); + BUG_ON(!cache); + kfree(name); + + emergency_caches[i] = cache; + + size *= 2; + } +} + +static struct kmem_cache *lookup_emergency_cache(unsigned long size) +{ + unsigned long cache_size = MIN_EMERGENCY_SIZE; + int i; + + for (i = 0; i < NR_EMERGENCY_CACHES; i++) { + if (size < cache_size) + return emergency_caches[i]; + + cache_size *= 2; + } + return NULL; +} + +static void *emergency_alloc(struct kmem_cache *cache, gfp_t gfp) +{ + struct kmem_cache *emergency_cache; + void *p; + + emergency_cache = lookup_emergency_cache(cache->objsize); + if (!emergency_cache) + return NULL; + + p = kmem_cache_alloc(emergency_cache, gfp); + if (p && cache->ctor) + cache->ctor(cache, p); + return p; +} + /******************************************************************** * Core slab cache functions *******************************************************************/ @@ -1528,6 +1589,9 @@ new_slab: goto load_freelist; } + if ((gfpflags & GFP_TEMPORARY) == GFP_TEMPORARY) + return emergency_alloc(s, gfpflags); + /* * No memory available. * @@ -2970,6 +3034,7 @@ void __init kmem_cache_init(void) #else kmem_size = sizeof(struct kmem_cache); #endif + init_emergency_caches(); printk(KERN_INFO "SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
|  |