aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sys/kmem.h8
-rw-r--r--module/spl/spl-kmem.c36
-rw-r--r--module/splat/splat-kmem.c14
3 files changed, 52 insertions, 6 deletions
diff --git a/include/sys/kmem.h b/include/sys/kmem.h
index 6904bec3f..d5d3061a5 100644
--- a/include/sys/kmem.h
+++ b/include/sys/kmem.h
@@ -377,9 +377,13 @@ typedef enum kmem_cbrc {
#define KMC_ALLOC (1 << KMC_BIT_ALLOC)
#define KMC_MAX (1 << KMC_BIT_MAX)
-#define KMC_REAP_CHUNK INT_MAX
-#define KMC_DEFAULT_SEEKS 1
+#define KMC_REAP_CHUNK INT_MAX
+#define KMC_DEFAULT_SEEKS 1
+#define KMC_EXPIRE_AGE 0x1 /* Due to age */
+#define KMC_EXPIRE_MEM 0x2 /* Due to low memory */
+
+extern unsigned int spl_kmem_cache_expire;
extern struct list_head spl_kmem_cache_list;
extern struct rw_semaphore spl_kmem_cache_sem;
diff --git a/module/spl/spl-kmem.c b/module/spl/spl-kmem.c
index 6cd3acb72..413aa1245 100644
--- a/module/spl/spl-kmem.c
+++ b/module/spl/spl-kmem.c
@@ -34,6 +34,19 @@
#define SS_DEBUG_SUBSYS SS_KMEM
/*
+ * Cache expiration was implemented because it was part of the default Solaris
+ * kmem_cache behavior. The idea is that per-cpu objects which haven't been
+ * accessed in several seconds should be returned to the cache. On the other
+ * hand Linux slabs never move objects back to the slabs unless there is
+ * memory pressure on the system. By default both methods are disabled, but
+ * may be enabled by setting KMC_EXPIRE_AGE or KMC_EXPIRE_MEM.
+ */
+unsigned int spl_kmem_cache_expire = 0;
+EXPORT_SYMBOL(spl_kmem_cache_expire);
+module_param(spl_kmem_cache_expire, uint, 0644);
+MODULE_PARM_DESC(spl_kmem_cache_expire, "By age (0x1) or low memory (0x2)");
+
+/*
* The minimum amount of memory measured in pages to be free at all
* times on the system. This is similar to Linux's zone->pages_min
* multiplied by the number of zones and is sized based on that.
@@ -1317,6 +1330,10 @@ spl_cache_age(void *data)
ASSERT(skc->skc_magic == SKC_MAGIC);
+ /* Dynamically disabled at run time */
+ if (!(spl_kmem_cache_expire & KMC_EXPIRE_AGE))
+ return;
+
atomic_inc(&skc->skc_ref);
spl_on_each_cpu(spl_magazine_age, skc, 1);
spl_slab_reclaim(skc, skc->skc_reap, 0);
@@ -1609,9 +1626,10 @@ spl_kmem_cache_create(char *name, size_t size, size_t align,
if (rc)
SGOTO(out, rc);
- skc->skc_taskqid = taskq_dispatch_delay(spl_kmem_cache_taskq,
- spl_cache_age, skc, TQ_SLEEP,
- ddi_get_lbolt() + skc->skc_delay / 3 * HZ);
+ if (spl_kmem_cache_expire & KMC_EXPIRE_AGE)
+ skc->skc_taskqid = taskq_dispatch_delay(spl_kmem_cache_taskq,
+ spl_cache_age, skc, TQ_SLEEP,
+ ddi_get_lbolt() + skc->skc_delay / 3 * HZ);
down_write(&spl_kmem_cache_sem);
list_add_tail(&skc->skc_list, &spl_kmem_cache_list);
@@ -2168,7 +2186,17 @@ spl_kmem_cache_reap_now(spl_kmem_cache_t *skc, int count)
} while (do_reclaim);
}
- /* Reclaim from the cache, ignoring it's age and delay. */
+ /* Reclaim from the magazine then the slabs ignoring age and delay. */
+ if (spl_kmem_cache_expire & KMC_EXPIRE_MEM) {
+ spl_kmem_magazine_t *skm;
+ int i;
+
+ for_each_online_cpu(i) {
+ skm = skc->skc_mag[i];
+ spl_cache_flush(skc, skm, skm->skm_avail);
+ }
+ }
+
spl_slab_reclaim(skc, count, 1);
clear_bit(KMC_BIT_REAPING, &skc->skc_flags);
smp_mb__after_clear_bit();
diff --git a/module/splat/splat-kmem.c b/module/splat/splat-kmem.c
index 30750aa01..789e75e56 100644
--- a/module/splat/splat-kmem.c
+++ b/module/splat/splat-kmem.c
@@ -810,8 +810,13 @@ splat_kmem_test8(struct file *file, void *arg)
{
kmem_cache_priv_t *kcp;
kmem_cache_thread_t *kct;
+ unsigned int spl_kmem_cache_expire_old;
int i, rc = 0;
+ /* Enable cache aging just for this test if it is disabled */
+ spl_kmem_cache_expire_old = spl_kmem_cache_expire;
+ spl_kmem_cache_expire = KMC_EXPIRE_AGE;
+
kcp = splat_kmem_cache_test_kcp_alloc(file, SPLAT_KMEM_TEST8_NAME,
256, 0, 0);
if (!kcp) {
@@ -882,6 +887,8 @@ out_cache:
out_kcp:
splat_kmem_cache_test_kcp_free(kcp);
out:
+ spl_kmem_cache_expire = spl_kmem_cache_expire_old;
+
return rc;
}
@@ -898,8 +905,13 @@ splat_kmem_test9(struct file *file, void *arg)
{
kmem_cache_priv_t *kcp;
kmem_cache_thread_t *kct;
+ unsigned int spl_kmem_cache_expire_old;
int i, rc = 0, count = SPLAT_KMEM_OBJ_COUNT * 128;
+ /* Enable cache aging just for this test if it is disabled */
+ spl_kmem_cache_expire_old = spl_kmem_cache_expire;
+ spl_kmem_cache_expire = KMC_EXPIRE_AGE;
+
kcp = splat_kmem_cache_test_kcp_alloc(file, SPLAT_KMEM_TEST9_NAME,
256, 0, 0);
if (!kcp) {
@@ -968,6 +980,8 @@ out_cache:
out_kcp:
splat_kmem_cache_test_kcp_free(kcp);
out:
+ spl_kmem_cache_expire = spl_kmem_cache_expire_old;
+
return rc;
}