T289: Refactor slot allocator code to allow slot_alloc_root() to resize L1 cnode
authorSimon Gerber <simon.gerber@inf.ethz.ch>
Wed, 21 Sep 2016 15:10:38 +0000 (17:10 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Wed, 21 Sep 2016 15:10:40 +0000 (17:10 +0200)
Closes T289.

Signed-off-by: Simon Gerber <simon.gerber@inf.ethz.ch>

lib/barrelfish/slot_alloc/slot_alloc.c
lib/barrelfish/slot_alloc/twolevel_slot_alloc.c
lib/mm/slot_alloc.c

index e0ff239..b9e1a63 100644 (file)
@@ -54,13 +54,30 @@ errval_t slot_alloc(struct capref *ret)
  */
 errval_t slot_alloc_root(struct capref *ret)
 {
+    errval_t err;
     struct slot_alloc_state *state = get_slot_alloc_state();
+    size_t rootcn_free = single_slot_alloc_freecount(&state->rootca);
+    // If there's only one root cnode slot left, we need to trigger refill as
+    // the multi slot allocator might need a root cnode slot as well if it's
+    // just about to run out of slots and root_slot_allocator_refill calls
+    // into slot_alloc().
+    if (rootcn_free == 1) {
+        err = root_slot_allocator_refill(NULL, NULL);
+        if (err_is_fail(err)) {
+            return err_push(err, LIB_ERR_ROOTSA_RESIZE);
+        }
+    }
     struct slot_allocator *ca = (struct slot_allocator*)(&state->rootca);
     return ca->alloc(ca, ret);
 }
 
 typedef errval_t (*cn_ram_alloc_func_t)(void *st, uint8_t reqbits, struct capref *ret);
 
+static errval_t rootcn_alloc(void *st, uint8_t reqbits, struct capref *ret)
+{
+    return ram_alloc(ret, reqbits);
+}
+
 errval_t root_slot_allocator_refill(cn_ram_alloc_func_t myalloc, void *allocst)
 {
     errval_t err;
@@ -75,6 +92,11 @@ errval_t root_slot_allocator_refill(cn_ram_alloc_func_t myalloc, void *allocst)
 
     // Double size of root cnode
     struct capref root_ram, newroot_cap;
+    if (myalloc == NULL) {
+        // Fall back to plain ram_alloc if caller has not provided allocator
+        // function.
+        myalloc = rootcn_alloc;
+    }
     err = myalloc(allocst, rootbits + 1 + OBJBITS_CTE, &root_ram);
     if (err_is_fail(err)) {
         return err_push(err, MM_ERR_SLOT_MM_ALLOC);
index aed709d..208570b 100644 (file)
  */
 
 #include <barrelfish/barrelfish.h>
+#include <barrelfish/core_state.h>
 #include "internal.h"
 #include "../../newlib/newlib/libc/include/stdlib.h"
 
-static errval_t rootcn_alloc(void *st, uint8_t reqbits, struct capref *ret)
-{
-    return ram_alloc(ret, reqbits);
-}
-
 /**
  * \brief slot allocator
  *
@@ -62,20 +58,23 @@ errval_t two_level_alloc(struct slot_allocator *ca, struct capref *ret)
         // Cnode: in Root CN
         struct capref cap;
         struct cnoderef cnode;
-        err = slot_alloc_root(&cap);
         thread_mutex_unlock(&ca->mutex);
+        // Do not call slot_alloc_root() here as we want control over refill.
+        struct slot_alloc_state *state = get_slot_alloc_state();
+        struct slot_allocator *rca = (struct slot_allocator *)(&state->rootca);
+        err = rca->alloc(rca, &cap);
         // From here: we may call back into slot_alloc when resizing root
         // cnode and/or creating new L2 Cnode.
         if (err_no(err) == LIB_ERR_SLOT_ALLOC_NO_SPACE) {
             // resize root slot allocator (and rootcn)
-            err = root_slot_allocator_refill(rootcn_alloc, NULL);
+            err = root_slot_allocator_refill(NULL, NULL);
             if (err_is_fail(err)) {
                 return err_push(err, LIB_ERR_ROOTSA_RESIZE);
             }
-            err = slot_alloc_root(&cap);
+            err = rca->alloc(rca, &cap);
         }
         if (err_is_fail(err)) {
-            DEBUG_ERR(err, "slot_alloc_root failed");
+            DEBUG_ERR(err, "allocating root cnode slot failed");
             return err_push(err, LIB_ERR_SLOT_ALLOC);
         }
         err = cnode_create_raw(cap, &cnode, ObjType_L2CNode, ca->nslots, NULL);
index 60a5202..5fbb6dc 100644 (file)
@@ -152,6 +152,7 @@ errval_t slot_alloc_basecn(void *inst, uint64_t nslots, struct capref *ret)
         struct capref cnode;
         err = slot_alloc_root(&cnode);
         if (err_is_fail(err)) {
+            DEBUG_ERR(err, "allocating root cnode slot");
             return err_push(err, LIB_ERR_SLOT_ALLOC);
         }