Added new kmalloc flag KMALLOC_ERROR
authorDavide Libenzi <dlibenzi@google.com>
Tue, 8 Dec 2015 19:58:57 +0000 (11:58 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 17 Dec 2015 20:24:44 +0000 (15:24 -0500)
Added new kmalloc flag KMALLOC_ERROR, to allow kernel allocation APIs to
throw error() in case of memory allocation failures.
This in turn allow code not to check for kmalloc return code, even in
case where KMALLOC_WAIT would not fit the model.

Signed-off-by: Davide Libenzi <dlibenzi@google.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/kmalloc.h
kern/src/page_alloc.c
kern/src/slab.c

index 26f23c1..1c06403 100644 (file)
@@ -31,7 +31,8 @@ void *debug_canary;
 
 /* Flags to pass to kmalloc */
 /* Not implemented yet. Block until it is available. */
-#define KMALLOC_WAIT                   4
+#define KMALLOC_WAIT                   (1 << 2)
+#define KMALLOC_ERROR                  (1 << 3)
 
 /* Kmalloc tag flags looks like this:
  *
index c2910c7..9e55457 100644 (file)
@@ -5,10 +5,12 @@
  * Kevin Klues <klueska@cs.berkeley.edu>    
  * Barret Rhoden <brho@cs.berkeley.edu> */
 
+#include <ros/errno.h>
 #include <sys/queue.h>
 #include <bitmask.h>
 #include <page_alloc.h>
 #include <pmap.h>
+#include <err.h>
 #include <string.h>
 #include <kmalloc.h>
 #include <blockdev.h>
@@ -206,6 +208,8 @@ void *get_cont_pages(size_t order, int flags)
        //If we couldn't find them, return NULL
        if( first == -1 ) {
                spin_unlock_irqsave(&colored_page_free_list_lock);
+               if (flags & KMALLOC_ERROR)
+                       error(ENOMEM, NULL);
                return NULL;
        }
 
@@ -262,7 +266,9 @@ void *get_cont_phys_pages_at(size_t order, physaddr_t at, int flags)
        for (unsigned long i = first_pg_nr; i < first_pg_nr + nr_pgs; i++) {
                if (!page_is_free(i)) {
                        spin_unlock_irqsave(&colored_page_free_list_lock);
-                       return 0;
+                       if (flags & KMALLOC_ERROR)
+                               error(ENOMEM, NULL);
+                       return NULL;
                }
        }
        for (unsigned long i = first_pg_nr; i < first_pg_nr + nr_pgs; i++)
index 91d9137..da1adf0 100644 (file)
 #include <stdio.h>
 #include <assert.h>
 #include <pmap.h>
+#include <kmalloc.h>
 
 struct kmem_cache_list kmem_caches;
 spinlock_t kmem_caches_lock;
 
 /* Backend/internal functions, defined later.  Grab the lock before calling
  * these. */
-static void kmem_cache_grow(struct kmem_cache *cp);
+static bool kmem_cache_grow(struct kmem_cache *cp);
 
 /* Cache of the kmem_cache objects, needed for bootstrapping */
 struct kmem_cache kmem_cache_cache;
@@ -161,9 +162,15 @@ void *kmem_cache_alloc(struct kmem_cache *cp, int flags)
        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
        if (!a_slab) {
-               if (TAILQ_EMPTY(&cp->empty_slab_list))
-                       // TODO: think about non-sleeping flags
-                       kmem_cache_grow(cp);
+               // TODO: think about non-sleeping flags
+               if (TAILQ_EMPTY(&cp->empty_slab_list) &&
+                       !kmem_cache_grow(cp)) {
+                       spin_unlock_irqsave(&cp->cache_lock);
+                       if (flags & KMALLOC_ERROR)
+                               error(ENOMEM, NULL);
+                       else
+                               panic("[German Accent]: OOM for a small slab growth!!!");
+               }
                // move to partial list
                a_slab = TAILQ_FIRST(&cp->empty_slab_list);
                TAILQ_REMOVE(&cp->empty_slab_list, a_slab, link);
@@ -242,15 +249,16 @@ void kmem_cache_free(struct kmem_cache *cp, void *buf)
  * Grab the cache lock before calling this.
  *
  * TODO: think about page colouring issues with kernel memory allocation. */
-static void kmem_cache_grow(struct kmem_cache *cp)
+static bool kmem_cache_grow(struct kmem_cache *cp)
 {
        struct kmem_slab *a_slab;
        struct kmem_bufctl *a_bufctl;
        if (cp->obj_size <= SLAB_LARGE_CUTOFF) {
                // Just get a single page for small slabs
                page_t *a_page;
+
                if (kpage_alloc(&a_page))
-                       panic("[German Accent]: OOM for a small slab growth!!!");
+                       return FALSE;
                // the slab struct is stored at the end of the page
                a_slab = (struct kmem_slab*)(page2kva(a_page) + PGSIZE -
                                             sizeof(struct kmem_slab));
@@ -274,6 +282,8 @@ static void kmem_cache_grow(struct kmem_cache *cp)
                *((uintptr_t**)(buf + cp->obj_size)) = NULL;
        } else {
                a_slab = kmem_cache_alloc(kmem_slab_cache, 0);
+               if (!a_slab)
+                       return FALSE;
                // TODO: hash table for back reference (BUF)
                a_slab->obj_size = ROUNDUP(cp->obj_size + sizeof(uintptr_t), cp->align);
                /* Figure out how much memory we want.  We need at least min_pgs.  We'll
@@ -282,8 +292,11 @@ static void kmem_cache_grow(struct kmem_cache *cp)
                                         PGSIZE;
                size_t order_pg_alloc = LOG2_UP(min_pgs);
                void *buf = get_cont_pages(order_pg_alloc, 0);
-               if (!buf)
-                       panic("[German Accent]: OOM for a large slab growth!!!");
+
+               if (!buf) {
+                       kmem_cache_free(kmem_slab_cache, a_slab);
+                       return FALSE;
+               }
                a_slab->num_busy_obj = 0;
                /* The number of objects is based on the rounded up amt requested. */
                a_slab->num_total_obj = ((1 << order_pg_alloc) * PGSIZE) /
@@ -305,6 +318,8 @@ static void kmem_cache_grow(struct kmem_cache *cp)
        }
        // add a_slab to the empty_list
        TAILQ_INSERT_HEAD(&cp->empty_slab_list, a_slab, link);
+
+       return TRUE;
 }
 
 /* This deallocs every slab from the empty list.  TODO: think a bit more about