Debug helpers for BNX2X
[akaros.git] / user / parlib / slab.c
index 72356fd..1e2ad04 100644 (file)
 #include <stdio.h>
 #include <assert.h>
 #include <sys/mman.h>
+#include <sys/param.h>
 
 struct kmem_cache_list kmem_caches;
-struct mcs_pdr_lock kmem_caches_lock;
+struct spin_pdr_lock kmem_caches_lock;
 
 /* Backend/internal functions, defined later.  Grab the lock before calling
  * these. */
@@ -35,7 +36,7 @@ static void __kmem_cache_create(struct kmem_cache *kc, const char *name,
 {
        assert(kc);
        assert(align);
-       mcs_pdr_init(&kc->cache_lock);
+       spin_pdr_init(&kc->cache_lock);
        kc->name = name;
        kc->obj_size = obj_size;
        kc->align = align;
@@ -49,7 +50,7 @@ static void __kmem_cache_create(struct kmem_cache *kc, const char *name,
        
        /* put in cache list based on it's size */
        struct kmem_cache *i, *prev = NULL;
-       mcs_pdr_lock(&kmem_caches_lock);
+       spin_pdr_lock(&kmem_caches_lock);
        /* find the kmem_cache before us in the list.  yes, this is O(n). */
        SLIST_FOREACH(i, &kmem_caches, link) {
                if (i->obj_size < kc->obj_size)
@@ -61,12 +62,12 @@ static void __kmem_cache_create(struct kmem_cache *kc, const char *name,
                SLIST_INSERT_AFTER(prev, kc, link);
        else
                SLIST_INSERT_HEAD(&kmem_caches, kc, link);
-       mcs_pdr_unlock(&kmem_caches_lock);
+       spin_pdr_unlock(&kmem_caches_lock);
 }
 
 void kmem_cache_init(void)
 {
-       mcs_pdr_init(&kmem_caches_lock);
+       spin_pdr_init(&kmem_caches_lock);
        SLIST_INIT(&kmem_caches);
        /* We need to call the __ version directly to bootstrap the global
         * kmem_cache_cache. */
@@ -74,11 +75,13 @@ void kmem_cache_init(void)
                            sizeof(struct kmem_cache),
                            __alignof__(struct kmem_cache), 0, NULL, NULL);
        /* Build the slab and bufctl caches */
-       kmem_slab_cache = kmem_cache_create("kmem_slab", sizeof(struct kmem_slab),
-                              __alignof__(struct kmem_slab), 0, NULL, NULL); 
-       kmem_bufctl_cache = kmem_cache_create("kmem_bufctl",
-                                sizeof(struct kmem_bufctl),
-                                __alignof__(struct kmem_bufctl), 0, NULL, NULL); 
+       kmem_slab_cache = kmem_cache_alloc(&kmem_cache_cache, 0);
+       __kmem_cache_create(kmem_slab_cache, "kmem_slab", sizeof(struct kmem_slab),
+                           __alignof__(struct kmem_slab), 0, NULL, NULL); 
+       kmem_bufctl_cache = kmem_cache_alloc(&kmem_cache_cache, 0);
+       __kmem_cache_create(kmem_bufctl_cache, "kmem_bufctl",
+                           sizeof(struct kmem_bufctl),
+                           __alignof__(struct kmem_bufctl), 0, NULL, NULL); 
 }
 
 /* Cache management */
@@ -87,12 +90,7 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t obj_size,
                                      void (*ctor)(void *, size_t),
                                      void (*dtor)(void *, size_t))
 {
-       static atomic_t initialized = FALSE;
-       /* Init the slab system.  We'll set it to TRUE, and whoever one the race
-        * (among multiple initializers) will do the real init. */
-       if (!atomic_swap(&initialized, TRUE))
-               kmem_cache_init();
-
+       run_once(kmem_cache_init());
        struct kmem_cache *kc = kmem_cache_alloc(&kmem_cache_cache, 0);
        __kmem_cache_create(kc, name, obj_size, align, flags, ctor, dtor);
        return kc;
@@ -109,13 +107,13 @@ static void kmem_slab_destroy(struct kmem_cache *cp, struct kmem_slab *a_slab)
                                buf += a_slab->obj_size;
                        }
                }
-               munmap(ROUNDDOWN(a_slab, PGSIZE), PGSIZE);
+               munmap((void*)ROUNDDOWN((uintptr_t)a_slab, PGSIZE), PGSIZE);
        } else {
                struct kmem_bufctl *i;
                void *page_start = (void*)-1;
-               // compute how many pages are allocated, given a power of two allocator
-               size_t num_pages = ROUNDUPPWR2(a_slab->num_total_obj * a_slab->obj_size)
-                                               / PGSIZE;
+               /* compute how many pages are allocated, same as in grow */
+               size_t nr_pgs = ROUNDUP(NUM_BUF_PER_SLAB * a_slab->obj_size, PGSIZE) /
+                                       PGSIZE;
                TAILQ_FOREACH(i, &a_slab->bufctl_freelist, link) {
                        // Track the lowest buffer address, which is the start of the buffer
                        page_start = MIN(page_start, i->buf_addr);
@@ -125,7 +123,7 @@ static void kmem_slab_destroy(struct kmem_cache *cp, struct kmem_slab *a_slab)
                        kmem_cache_free(kmem_bufctl_cache, i);
                }
                // free the pages for the slab's buffer
-               munmap(page_start, num_pages * PGSIZE);
+               munmap(page_start, nr_pgs * PGSIZE);
                // free the slab object
                kmem_cache_free(kmem_slab_cache, a_slab);
        }
@@ -137,7 +135,7 @@ void kmem_cache_destroy(struct kmem_cache *cp)
 {
        struct kmem_slab *a_slab, *next;
 
-       mcs_pdr_lock(&cp->cache_lock);
+       spin_pdr_lock(&cp->cache_lock);
        assert(TAILQ_EMPTY(&cp->full_slab_list));
        assert(TAILQ_EMPTY(&cp->partial_slab_list));
        /* Clean out the empty list.  We can't use a regular FOREACH here, since the
@@ -149,18 +147,18 @@ void kmem_cache_destroy(struct kmem_cache *cp)
                kmem_slab_destroy(cp, a_slab);
                a_slab = next;
        }
-       mcs_pdr_lock(&kmem_caches_lock);
+       spin_pdr_lock(&kmem_caches_lock);
        SLIST_REMOVE(&kmem_caches, cp, kmem_cache, link);
-       mcs_pdr_unlock(&kmem_caches_lock);
+       spin_pdr_unlock(&kmem_caches_lock);
        kmem_cache_free(&kmem_cache_cache, cp); 
-       mcs_pdr_unlock(&cp->cache_lock);
+       spin_pdr_unlock(&cp->cache_lock);
 }
 
 /* Front end: clients of caches use these */
 void *kmem_cache_alloc(struct kmem_cache *cp, int flags)
 {
        void *retval = NULL;
-       mcs_pdr_lock(&cp->cache_lock);
+       spin_pdr_lock(&cp->cache_lock);
        // look at partial list
        struct kmem_slab *a_slab = TAILQ_FIRST(&cp->partial_slab_list);
        //      if none, go to empty list and get an empty and make it partial
@@ -193,7 +191,7 @@ void *kmem_cache_alloc(struct kmem_cache *cp, int flags)
                TAILQ_INSERT_HEAD(&cp->full_slab_list, a_slab, link);
        }
        cp->nr_cur_alloc++;
-       mcs_pdr_unlock(&cp->cache_lock);
+       spin_pdr_unlock(&cp->cache_lock);
        return retval;
 }
 
@@ -208,11 +206,11 @@ void kmem_cache_free(struct kmem_cache *cp, void *buf)
        struct kmem_slab *a_slab;
        struct kmem_bufctl *a_bufctl;
 
-       mcs_pdr_lock(&cp->cache_lock);
+       spin_pdr_lock(&cp->cache_lock);
        if (cp->obj_size <= SLAB_LARGE_CUTOFF) {
                // find its slab
-               a_slab = (struct kmem_slab*)(ROUNDDOWN(buf, PGSIZE) + PGSIZE -
-                                            sizeof(struct kmem_slab));
+               a_slab = (struct kmem_slab*)(ROUNDDOWN((uintptr_t)buf, PGSIZE) +
+                                            PGSIZE - sizeof(struct kmem_slab));
                /* write location of next free small obj to the space at the end of the
                 * buffer, then list buf as the next free small obj */
                *(uintptr_t**)(buf + cp->obj_size) = a_slab->free_small_obj;
@@ -235,7 +233,7 @@ void kmem_cache_free(struct kmem_cache *cp, void *buf)
                TAILQ_REMOVE(&cp->partial_slab_list, a_slab, link);
                TAILQ_INSERT_HEAD(&cp->empty_slab_list, a_slab, link);
        }
-       mcs_pdr_unlock(&cp->cache_lock);
+       spin_pdr_unlock(&cp->cache_lock);
 }
 
 /* Back end: internal functions */
@@ -255,7 +253,7 @@ static void kmem_cache_grow(struct kmem_cache *cp)
                // Just get a single page for small slabs
                a_page = mmap(0, PGSIZE, PROT_READ | PROT_WRITE,
                              MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
-               assert(a_page);
+               assert(a_page != MAP_FAILED);
                // the slab struct is stored at the end of the page
                a_slab = (struct kmem_slab*)(a_page + PGSIZE -
                                             sizeof(struct kmem_slab));
@@ -281,15 +279,16 @@ static void kmem_cache_grow(struct kmem_cache *cp)
                a_slab = kmem_cache_alloc(kmem_slab_cache, 0);
                // TODO: hash table for back reference (BUF)
                a_slab->obj_size = ROUNDUP(cp->obj_size + sizeof(uintptr_t), cp->align);
-               // alloc n pages, such that it can hold at least 8 items
-               size_t num_pgs = ROUNDUP(NUM_BUF_PER_SLAB * a_slab->obj_size, PGSIZE) /
-                                          PGSIZE;
-               // round up for the contiguous page allocator
-               void *buf = mmap(0, num_pgs * PGSIZE, PROT_READ | PROT_WRITE,
+               /* Need at least nr_pgs to hold NUM_BUF objects.  Note we don't round up
+                * to the next higher order (power of 2) number of pages, like we do in
+                * the kernel. */
+               size_t nr_pgs = ROUNDUP(NUM_BUF_PER_SLAB * a_slab->obj_size, PGSIZE) /
+                                        PGSIZE;
+               void *buf = mmap(0, nr_pgs * PGSIZE, PROT_READ | PROT_WRITE,
                                 MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
-               assert(buf);
+               assert(buf != MAP_FAILED);
                a_slab->num_busy_obj = 0;
-               a_slab->num_total_obj = ROUNDUPPWR2(num_pgs)*PGSIZE / a_slab->obj_size;
+               a_slab->num_total_obj = nr_pgs * PGSIZE / a_slab->obj_size;
                TAILQ_INIT(&a_slab->bufctl_freelist);
                /* for each buffer, set up a bufctl and point to the buffer */
                for (int i = 0; i < a_slab->num_total_obj; i++) {
@@ -317,19 +316,19 @@ void kmem_cache_reap(struct kmem_cache *cp)
        struct kmem_slab *a_slab, *next;
        
        // Destroy all empty slabs.  Refer to the notes about the while loop
-       mcs_pdr_lock(&cp->cache_lock);
+       spin_pdr_lock(&cp->cache_lock);
        a_slab = TAILQ_FIRST(&cp->empty_slab_list);
        while (a_slab) {
                next = TAILQ_NEXT(a_slab, link);
                kmem_slab_destroy(cp, a_slab);
                a_slab = next;
        }
-       mcs_pdr_unlock(&cp->cache_lock);
+       spin_pdr_unlock(&cp->cache_lock);
 }
 
 void print_kmem_cache(struct kmem_cache *cp)
 {
-       mcs_pdr_lock(&cp->cache_lock);
+       spin_pdr_lock(&cp->cache_lock);
        printf("\nPrinting kmem_cache:\n---------------------\n");
        printf("Name: %s\n", cp->name);
        printf("Objsize: %d\n", cp->obj_size);
@@ -341,7 +340,7 @@ void print_kmem_cache(struct kmem_cache *cp)
        printf("Slab Partial: 0x%08x\n", cp->partial_slab_list);
        printf("Slab Empty: 0x%08x\n", cp->empty_slab_list);
        printf("Current Allocations: %d\n", cp->nr_cur_alloc);
-       mcs_pdr_unlock(&cp->cache_lock);
+       spin_pdr_unlock(&cp->cache_lock);
 }
 
 void print_kmem_slab(struct kmem_slab *slab)