From 5c2bb9b2c314bcac7579b13a99127eb7050a7b90 Mon Sep 17 00:00:00 2001 From: behlendo Date: Fri, 9 May 2008 21:21:33 +0000 Subject: [PATCH] Stability hack. Under Solaris when KM_SLEEP is set kmem_cache_alloc() may not fail. To get this behavior I'd added a retry to the shim layer even though it is abusive to the VM, at least it should prevent the crash. Additionally I added a proc counter so I can easily check how often this is happening. It should be fairly rare, but likely will get worse and worse the longer the machine has been up. git-svn-id: https://outreach.scidac.gov/svn/spl/trunk@104 7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c --- include/sys/kmem.h | 12 ++++++------ modules/spl/spl-kmem.c | 28 ++++++++++++++++++++++++++++ modules/spl/spl-proc.c | 9 +++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/include/sys/kmem.h b/include/sys/kmem.h index d67e4f2a271..1dfc0bf1e31 100644 --- a/include/sys/kmem.h +++ b/include/sys/kmem.h @@ -32,7 +32,9 @@ extern atomic64_t kmem_alloc_used; extern unsigned long kmem_alloc_max; extern atomic64_t vmem_alloc_used; extern unsigned long vmem_alloc_max; + extern int kmem_warning_flag; +extern atomic64_t kmem_cache_alloc_failed; #define KMEM_HASH_BITS 10 #define KMEM_TABLE_SIZE (1 << KMEM_HASH_BITS) @@ -351,11 +353,9 @@ __kmem_cache_create(char *name, size_t size, size_t align, kmem_reclaim_t reclaim, void *priv, void *vmp, int flags); -int -extern __kmem_cache_destroy(kmem_cache_t *cache); - -void -extern __kmem_reap(void); +extern int __kmem_cache_destroy(kmem_cache_t *cache); +extern void *__kmem_cache_alloc(kmem_cache_t *cache, gfp_t flags); +extern void __kmem_reap(void); int kmem_init(void); void kmem_fini(void); @@ -363,7 +363,7 @@ void kmem_fini(void); #define kmem_cache_create(name,size,align,ctor,dtor,rclm,priv,vmp,flags) \ __kmem_cache_create(name,size,align,ctor,dtor,rclm,priv,vmp,flags) #define kmem_cache_destroy(cache) __kmem_cache_destroy(cache) -#define kmem_cache_alloc(cache, flags) kmem_cache_alloc(cache, flags) +#define kmem_cache_alloc(cache, flags) __kmem_cache_alloc(cache, flags) #define kmem_cache_free(cache, ptr) kmem_cache_free(cache, ptr) #define kmem_cache_reap_now(cache) kmem_cache_shrink(cache) #define kmem_reap() __kmem_reap() diff --git a/modules/spl/spl-kmem.c b/modules/spl/spl-kmem.c index 75a421ac73c..80c4488b1bd 100644 --- a/modules/spl/spl-kmem.c +++ b/modules/spl/spl-kmem.c @@ -16,6 +16,7 @@ unsigned long kmem_alloc_max = 0; atomic64_t vmem_alloc_used; unsigned long vmem_alloc_max = 0; int kmem_warning_flag = 1; +atomic64_t kmem_cache_alloc_failed; spinlock_t kmem_lock; struct hlist_head kmem_table[KMEM_TABLE_SIZE]; @@ -268,6 +269,7 @@ kmem_cache_generic_shrinker(int nr_to_scan, unsigned int gfp_mask) */ #undef kmem_cache_create #undef kmem_cache_destroy +#undef kmem_cache_alloc kmem_cache_t * __kmem_cache_create(char *name, size_t size, size_t align, @@ -360,6 +362,30 @@ __kmem_cache_destroy(kmem_cache_t *cache) } EXPORT_SYMBOL(__kmem_cache_destroy); +/* Under Solaris if the KM_SLEEP flag is passed we absolutely must + * sleep until we are allocated the memory. Under Linux you can still + * get a memory allocation failure, so I'm forced to keep requesting + * the memory even if the system is under substantial memory pressure + * of fragmentation prevents the allocation from succeeded. This is + * not the correct fix, or even a good one. But it will do for now. + */ +void * +__kmem_cache_alloc(kmem_cache_t *cache, gfp_t flags) +{ + void *rc; + ENTRY; + +restart: + rc = kmem_cache_alloc(cache, flags); + if ((rc == NULL) && (flags & KM_SLEEP)) { + atomic64_inc(&kmem_cache_alloc_failed); + GOTO(restart, rc); + } + + RETURN(rc); +} +EXPORT_SYMBOL(__kmem_cache_alloc); + void __kmem_reap(void) { @@ -395,6 +421,8 @@ kmem_init(void) for (i = 0; i < VMEM_TABLE_SIZE; i++) INIT_HLIST_HEAD(&vmem_table[i]); + + atomic64_set(&kmem_cache_alloc_failed, 0); } #endif RETURN(0); diff --git a/modules/spl/spl-proc.c b/modules/spl/spl-proc.c index 07e18102aef..a8d3485a6a4 100644 --- a/modules/spl/spl-proc.c +++ b/modules/spl/spl-proc.c @@ -60,6 +60,7 @@ enum { CTL_KMEM_KMEMMAX, /* Max alloc'd by kmem bytes */ CTL_KMEM_VMEMUSED, /* Currently alloc'd vmem bytes */ CTL_KMEM_VMEMMAX, /* Max alloc'd by vmem bytes */ + CTL_KMEM_ALLOC_FAILED, /* Cache allocation failed */ #endif CTL_MUTEX_STATS, /* Global mutex statistics */ @@ -660,6 +661,14 @@ static struct ctl_table spl_kmem_table[] = { .mode = 0444, .proc_handler = &proc_doulongvec_minmax, }, + { + .ctl_name = CTL_KMEM_ALLOC_FAILED, + .procname = "kmem_alloc_failed", + .data = &kmem_cache_alloc_failed, + .maxlen = sizeof(atomic64_t), + .mode = 0444, + .proc_handler = &proc_doatomic64, + }, {0}, }; #endif /* DEBUG_KMEM */ -- 2.45.2