Fix vmem_size()

Add a minimal implementation of vmem_size() which accounts for the
virtual memory usage of the SPL's kmem cache.  This functionality
is only useful on 32-bit systems with a small virtual address space.

The following assumptions are made:

  1) The major SPL consumer of virtual memory is the kmem cache.
  2) Memory allocated with vmem_alloc() is short lived and can be ignored.
  3) Allow a 4MB floor as a generous pad given normal consumption.
  4) The spl_kmem_cache_sem only contends with cache create/destroy.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
Ubuntu 2016-10-28 20:56:38 +00:00 committed by Brian Behlendorf
parent 7b25c48e6e
commit 1b457bcbe5
2 changed files with 44 additions and 9 deletions

View File

@ -24,6 +24,7 @@
#include <sys/debug.h> #include <sys/debug.h>
#include <sys/vmem.h> #include <sys/vmem.h>
#include <sys/kmem_cache.h>
#include <linux/mm_compat.h> #include <linux/mm_compat.h>
#include <linux/module.h> #include <linux/module.h>
@ -36,14 +37,39 @@ EXPORT_SYMBOL(zio_alloc_arena);
vmem_t *zio_arena = NULL; vmem_t *zio_arena = NULL;
EXPORT_SYMBOL(zio_arena); EXPORT_SYMBOL(zio_arena);
#define VMEM_FLOOR_SIZE (4 * 1024 * 1024) /* 4MB floor */
/*
* Return approximate virtual memory usage based on these assumptions:
*
* 1) The major SPL consumer of virtual memory is the kmem cache.
* 2) Memory allocated with vmem_alloc() is short lived and can be ignored.
* 3) Allow a 4MB floor as a generous pad given normal consumption.
* 4) The spl_kmem_cache_sem only contends with cache create/destroy.
*/
size_t size_t
vmem_size(vmem_t *vmp, int typemask) vmem_size(vmem_t *vmp, int typemask)
{ {
ASSERT3P(vmp, ==, NULL); spl_kmem_cache_t *skc;
ASSERT3S(typemask & VMEM_ALLOC, ==, VMEM_ALLOC); size_t alloc = VMEM_FLOOR_SIZE;
ASSERT3S(typemask & VMEM_FREE, ==, VMEM_FREE);
if ((typemask & VMEM_ALLOC) && (typemask & VMEM_FREE))
return (VMALLOC_TOTAL); return (VMALLOC_TOTAL);
down_read(&spl_kmem_cache_sem);
list_for_each_entry(skc, &spl_kmem_cache_list, skc_list) {
if (skc->skc_flags & KMC_VMEM)
alloc += skc->skc_slab_size * skc->skc_slab_total;
}
up_read(&spl_kmem_cache_sem);
if (typemask & VMEM_ALLOC)
return (MIN(alloc, VMALLOC_TOTAL));
else if (typemask & VMEM_FREE)
return (MAX(VMALLOC_TOTAL - alloc, 0));
else
return (0);
} }
EXPORT_SYMBOL(vmem_size); EXPORT_SYMBOL(vmem_size);

View File

@ -1131,9 +1131,15 @@ out:
static int static int
splat_kmem_test10(struct file *file, void *arg) splat_kmem_test10(struct file *file, void *arg)
{ {
uint64_t size, alloc, rc = 0; uint64_t size, alloc, maxsize, limit, rc = 0;
for (size = 32; size <= 1024*1024; size *= 2) { #if defined(CONFIG_64BIT)
maxsize = (1024 * 1024);
#else
maxsize = (128 * 1024);
#endif
for (size = 32; size <= maxsize; size *= 2) {
splat_vprint(file, SPLAT_KMEM_TEST10_NAME, "%-22s %s", "name", splat_vprint(file, SPLAT_KMEM_TEST10_NAME, "%-22s %s", "name",
"time (sec)\tslabs \tobjs \thash\n"); "time (sec)\tslabs \tobjs \thash\n");
@ -1142,8 +1148,10 @@ splat_kmem_test10(struct file *file, void *arg)
for (alloc = 1; alloc <= 1024; alloc *= 2) { for (alloc = 1; alloc <= 1024; alloc *= 2) {
/* Skip tests which exceed 1/2 of physical memory. */ /* Skip tests which exceed 1/2 of memory. */
if (size * alloc * SPLAT_KMEM_THREADS > physmem / 2) limit = MIN(physmem * PAGE_SIZE,
vmem_size(NULL, VMEM_ALLOC | VMEM_FREE)) / 2;
if (size * alloc * SPLAT_KMEM_THREADS > limit)
continue; continue;
rc = splat_kmem_cache_thread_test(file, arg, rc = splat_kmem_cache_thread_test(file, arg,
@ -1223,7 +1231,8 @@ splat_kmem_test13(struct file *file, void *arg)
int i, rc = 0, max_time = 10; int i, rc = 0, max_time = 10;
size = 128 * 1024; size = 128 * 1024;
count = ((physmem * PAGE_SIZE) / 4 / size); count = MIN(physmem * PAGE_SIZE, vmem_size(NULL,
VMEM_ALLOC | VMEM_FREE)) / 4 / size;
kcp = splat_kmem_cache_test_kcp_alloc(file, SPLAT_KMEM_TEST13_NAME, kcp = splat_kmem_cache_test_kcp_alloc(file, SPLAT_KMEM_TEST13_NAME,
size, 0, 0); size, 0, 0);