kernel - make lwbuf use objcache for ephemeral mappings
authorSamuel J. Greear <sjg@thesjg.com>
Wed, 31 Mar 2010 08:17:39 +0000 (02:17 -0600)
committerSamuel J. Greear <sjg@thesjg.com>
Wed, 31 Mar 2010 08:17:39 +0000 (02:17 -0600)
* Introduce ephemeral-tagged mappings to lwbuf, these are serviced directly
from objcache.

* Add kern.ipc.lwbuf_reserve, a boot-time tuneable that controls the number
of per-cpu lwbuf's reserved by the subsystem.

* Add kern.ipw.lwbuf_count, which prints the per-cpu number of lwbufs
available for allocation.

sys/cpu/i386/include/lwbuf.h
sys/cpu/i386/misc/lwbuf.c

index 4040aaf..9933a6a 100644 (file)
@@ -67,6 +67,7 @@ struct lwbuf {
     vm_page_t          m;              /* currently mapped page */
     vm_offset_t                kva;            /* va of mapping */
     cpumask_t          cpumask;        /* cpu mapping synchronization */
+    boolean_t          ephemeral;      /* lives out of objcache if true */
 };
 
 SLIST_HEAD(lwbuf_list, lwbuf);
index af65c81..ca0b054 100644 (file)
 static void lwbuf_init(void *);
 SYSINIT(sock_lwb, SI_BOOT2_MACHDEP, SI_ORDER_ANY, lwbuf_init, NULL);
 
-/* Number of pages of KVA to allocate at boot per cpu (1MB) */
-#define        LWBUF_BOOT_PAGES        256
-/* Number to allocate incrementally (128KB) */
-#define LWBUF_ALLOC_PAGES      32
+static struct objcache *lwbuf_cache;
 
 MALLOC_DEFINE(M_LWBUF, "lwbuf", "Lightweight buffers");
+struct objcache_malloc_args lwbuf_malloc_args = { sizeof(struct lwbuf), M_LWBUF };
 
-static boolean_t
-lwbuf_initpages(struct mdglobaldata *gd, int pages)
+/* Number of pages of KVA to allocate at boot per cpu (1MB) */
+static int lwbuf_reserve_pages = 256;
+
+SYSCTL_INT(_kern_ipc, OID_AUTO, lwbuf_reserve, CTLFLAG_RD,
+           &lwbuf_reserve_pages, 0,
+           "Per-CPU count of pre-allocated lightweight buffers");
+
+static int
+do_lwbuf_count(SYSCTL_HANDLER_ARGS)
 {
-    struct lwbuf *lwb;
-    vm_offset_t k;
+    int count[ncpus];
+    struct mdglobaldata *gd;
     int i;
 
+    for (i = 0; i < ncpus; i++) {
+        gd = &CPU_prvspace[i].mdglobaldata;
+        count[i] = gd->gd_lwbuf_count;
+    }
+
+    return (sysctl_handle_opaque(oidp, count, sizeof(int) * ncpus, req));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, lwbuf_count, CTLTYPE_INT|CTLFLAG_RD,
+            0, 0, do_lwbuf_count, "I",
+            "Per-CPU count of free lightweight buffers");
+
+static boolean_t
+lwbuf_cache_ctor(void *obj, void *pdata, int ocflags)
+{
+    struct lwbuf *lwb = (struct lwbuf *)obj;
+
     get_mplock();
-    k = kmem_alloc_nofault(&kernel_map, PAGE_SIZE * pages, PAGE_SIZE);
+    lwb->kva = kmem_alloc_nofault(&kernel_map, PAGE_SIZE, PAGE_SIZE);
     rel_mplock();
-    if (k == 0)
+    if (lwb->kva == 0)
         return (FALSE);
-    for (i = 0; i < pages; ++i) {
-        lwb = kmalloc(sizeof(*lwb), M_LWBUF, M_WAITOK | M_ZERO);
-        lwb->kva = k + (i * PAGE_SIZE);
-       lwb->gd = gd;
-        SLIST_INSERT_HEAD(&gd->gd_lwbuf_fpages, lwb, next);
-       ++gd->gd_lwbuf_count;
-    }
+    lwb->gd = mdcpu;
+    lwb->ephemeral = TRUE;
 
     return (TRUE);
 }
 
+static void
+lwbuf_cache_dtor(void *obj, void *pdata)
+{
+    struct lwbuf *lwb = (struct lwbuf *)obj;
+
+    get_mplock();
+    kmem_free(&kernel_map, lwb->kva, PAGE_SIZE);
+    rel_mplock();
+}
+
 static void
 lwbuf_init(void *arg)
 {
     struct mdglobaldata *gd = mdcpu;
-    int i;
+    struct lwbuf *lwb;
+    vm_offset_t k;
+    int i, j;
 
     for (i = 0; i < ncpus; ++i) {
        gd = &CPU_prvspace[i].mdglobaldata;
         SLIST_INIT(&gd->gd_lwbuf_fpages);
-        lwbuf_initpages(gd, LWBUF_BOOT_PAGES);
+        get_mplock();
+        k = kmem_alloc_nofault(&kernel_map, PAGE_SIZE * lwbuf_reserve_pages,
+                               PAGE_SIZE);
+        rel_mplock();
+        if (k == 0) {
+            gd->gd_lwbuf_count = 0;
+            continue;
+        }
+        for (j = 0; j < lwbuf_reserve_pages; ++j) {
+            lwb = kmalloc(sizeof(*lwb), M_LWBUF, M_WAITOK | M_ZERO);
+            lwb->kva = k + (j * PAGE_SIZE);
+            lwb->gd = gd;
+            lwb->ephemeral = FALSE;
+            SLIST_INSERT_HEAD(&gd->gd_lwbuf_fpages, lwb, next);
+        }
+        gd->gd_lwbuf_count = lwbuf_reserve_pages;
     }
+
+    lwbuf_cache = objcache_create("lwbuf", 0, 0,
+        lwbuf_cache_ctor, lwbuf_cache_dtor, NULL,
+        objcache_malloc_alloc, objcache_malloc_free,
+        &lwbuf_malloc_args);
 }
 
 struct lwbuf *
@@ -108,7 +156,7 @@ lwbuf_alloc(vm_page_t m)
 
     crit_enter_gd(&gd->mi);
     while ((lwb = SLIST_FIRST(&gd->gd_lwbuf_fpages)) == NULL) {
-       if (lwbuf_initpages(gd, LWBUF_ALLOC_PAGES) == FALSE)
+        if ((lwb = objcache_get(lwbuf_cache, M_WAITOK)) == NULL)
             tsleep(&gd->gd_lwbuf_fpages, 0, "lwbuf", 0);
     }
     --gd->gd_lwbuf_count;
@@ -140,19 +188,15 @@ lwbuf_free(struct lwbuf *lwb)
     lwb->cpumask = 0;
 
     if (gd == lwb->gd) {
-       if (gd->gd_lwbuf_count > LWBUF_BOOT_PAGES) {
-           get_mplock();
-           kmem_free(&kernel_map, lwb->kva, PAGE_SIZE);
-           rel_mplock();
-           bzero(lwb, sizeof(*lwb));
-           kfree(lwb, M_LWBUF);
-       } else {
-           crit_enter_gd(&gd->mi);
-           SLIST_INSERT_HEAD(&gd->gd_lwbuf_fpages, lwb, next);
-           if (gd->gd_lwbuf_count++ == 0)
-               wakeup_one(&gd->gd_lwbuf_fpages);
-           crit_exit_gd(&gd->mi);
-       }
+        if (lwb->ephemeral == FALSE) {
+            crit_enter_gd(&gd->mi);
+            SLIST_INSERT_HEAD(&gd->gd_lwbuf_fpages, lwb, next);
+            if (gd->gd_lwbuf_count++ == 0)
+                wakeup_one(&gd->gd_lwbuf_fpages);
+            crit_exit_gd(&gd->mi);
+        } else {
+            objcache_put(lwbuf_cache, lwb);
+        }
     }
 #ifdef SMP
     else {