From a073aeb0604b7d410be58135fb9d5c43671af263 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Sun, 8 Dec 2013 17:01:45 -0500 Subject: Add KMC_SLAB cache type For small objects the Linux slab allocator has several advantages over its counterpart in the SPL. These include: 1) It is more memory-efficient and packs objects more tightly. 2) It is continually tuned to maximize performance. Therefore it makes sense to layer the SPLs slab allocator on top of the Linux slab allocator. This allows us to leverage the advantages above while preserving the Illumos semantics we depend on. However, there are some things we need to be careful of: 1) The Linux slab allocator was never designed to work well with large objects. Because the SPL slab must still handle this use case a cut off limit was added to transition from Linux slab backed objects to kmem or vmem backed slabs. spl_kmem_cache_slab_limit - Objects less than or equal to this size in bytes will be backed by the Linux slab. By default this value is zero which disables the Linux slab functionality. Reasonable values for this cut off limit are in the range of 4096-16386 bytes. spl_kmem_cache_kmem_limit - Objects less than or equal to this size in bytes will be backed by a kmem slab. Objects over this size will be vmem backed instead. This value defaults to 1/8 a page, or 512 bytes on an x86_64 architecture. 2) Be aware that using the Linux slab may inadvertently introduce new deadlocks. Care has been taken previously to ensure that all allocations which occur in the write path use GFP_NOIO. However, there may be internal allocations performed in the Linux slab which do not honor these flags. If this is the case a deadlock may occur. The path forward is definitely to start relying on the Linux slab. But for that to happen we need to start building confidence that there aren't any unexpected surprises lurking for us. And ideally need to move completely away from using the SPLs slab for large memory allocations. This patch is a first step. NOTES: 1) The KMC_NOMAGAZINE flag was leveraged to support the Linux slab backed caches but it is not supported for kmem/vmem backed caches. 2) Regardless of the spl_kmem_cache_*_limit settings a cache may be explicitly set to a given type by passed the KMC_KMEM, KMC_VMEM, or KMC_SLAB flags during cache creation. 3) The constructors, destructors, and reclaim callbacks are all functional and will be called regardless of the cache type. 4) KMC_SLAB caches will not appear in /proc/spl/kmem/slab due to the issues involved in presenting correct object accounting. Instead they will appear in /proc/slabinfo under the same names. 5) Several kmem SPLAT tests needed to be fixed because they relied incorrectly on internal kmem slab accounting. With the updated test cases all the SPLAT tests pass as expected. 6) An autoconf test was added to ensure that the __GFP_COMP flag was correctly added to the default flags used when allocating a slab. This is required to ensure all pages in higher order slabs are properly refcounted, see ae16ed9. 7) When using the SLUB allocator there is no need to attempt to set the __GFP_COMP flag. This has been the default behavior for the SLUB since Linux 2.6.25. 8) When using the SLUB it may be desirable to set the slub_nomerge kernel parameter to prevent caches from being merged. Original-patch-by: DHE Signed-off-by: Brian Behlendorf Signed-off-by: Prakash Surya Signed-off-by: Tim Chase Signed-off-by: DHE Signed-off-by: Chunwei Chen Closes #356 --- module/splat/splat-kmem.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'module/splat') diff --git a/module/splat/splat-kmem.c b/module/splat/splat-kmem.c index 25a52b43d..4d060c138 100644 --- a/module/splat/splat-kmem.c +++ b/module/splat/splat-kmem.c @@ -394,18 +394,25 @@ splat_kmem_cache_test_debug(struct file *file, char *name, { int j; - splat_vprint(file, name, - "%s cache objects %d, slabs %u/%u objs %u/%u mags ", - kcp->kcp_cache->skc_name, kcp->kcp_count, + splat_vprint(file, name, "%s cache objects %d", + kcp->kcp_cache->skc_name, kcp->kcp_count); + + if (kcp->kcp_cache->skc_flags & (KMC_KMEM | KMC_VMEM)) { + splat_vprint(file, name, ", slabs %u/%u objs %u/%u", (unsigned)kcp->kcp_cache->skc_slab_alloc, (unsigned)kcp->kcp_cache->skc_slab_total, (unsigned)kcp->kcp_cache->skc_obj_alloc, (unsigned)kcp->kcp_cache->skc_obj_total); - for_each_online_cpu(j) - splat_print(file, "%u/%u ", - kcp->kcp_cache->skc_mag[j]->skm_avail, - kcp->kcp_cache->skc_mag[j]->skm_size); + if (!(kcp->kcp_cache->skc_flags & KMC_NOMAGAZINE)) { + splat_vprint(file, name, "%s", "mags"); + + for_each_online_cpu(j) + splat_print(file, "%u/%u ", + kcp->kcp_cache->skc_mag[j]->skm_avail, + kcp->kcp_cache->skc_mag[j]->skm_size); + } + } splat_print(file, "%s\n", ""); } @@ -900,14 +907,14 @@ splat_kmem_test8(struct file *file, void *arg) kmem_cache_reap_now(kcp->kcp_cache); splat_kmem_cache_test_debug(file, SPLAT_KMEM_TEST8_NAME, kcp); - if (kcp->kcp_cache->skc_obj_total == 0) + if (kcp->kcp_count == 0) break; set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 10); } - if (kcp->kcp_cache->skc_obj_total == 0) { + if (kcp->kcp_count == 0) { splat_vprint(file, SPLAT_KMEM_TEST8_NAME, "Successfully created %d objects " "in cache %s and reclaimed them\n", @@ -915,7 +922,7 @@ splat_kmem_test8(struct file *file, void *arg) } else { splat_vprint(file, SPLAT_KMEM_TEST8_NAME, "Failed to reclaim %u/%d objects from cache %s\n", - (unsigned)kcp->kcp_cache->skc_obj_total, + (unsigned)kcp->kcp_count, SPLAT_KMEM_OBJ_COUNT, SPLAT_KMEM_CACHE_NAME); rc = -ENOMEM; } @@ -995,14 +1002,14 @@ splat_kmem_test9(struct file *file, void *arg) for (i = 0; i < 60; i++) { splat_kmem_cache_test_debug(file, SPLAT_KMEM_TEST9_NAME, kcp); - if (kcp->kcp_cache->skc_obj_total == 0) + if (kcp->kcp_count == 0) break; set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); } - if (kcp->kcp_cache->skc_obj_total == 0) { + if (kcp->kcp_count == 0) { splat_vprint(file, SPLAT_KMEM_TEST9_NAME, "Successfully created %d objects " "in cache %s and reclaimed them\n", @@ -1010,7 +1017,7 @@ splat_kmem_test9(struct file *file, void *arg) } else { splat_vprint(file, SPLAT_KMEM_TEST9_NAME, "Failed to reclaim %u/%d objects from cache %s\n", - (unsigned)kcp->kcp_cache->skc_obj_total, count, + (unsigned)kcp->kcp_count, count, SPLAT_KMEM_CACHE_NAME); rc = -ENOMEM; } -- cgit v1.2.3