summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sys/kmem.h12
-rw-r--r--modules/spl/spl-kmem.c28
-rw-r--r--modules/spl/spl-proc.c9
3 files changed, 43 insertions, 6 deletions
diff --git a/include/sys/kmem.h b/include/sys/kmem.h
index d67e4f2a2..1dfc0bf1e 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 75a421ac7..80c4488b1 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 07e18102a..a8d3485a6 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 */