T266: Refactor rootcn resizing and use it in two-level slot allocator
authorSimon Gerber <simon.gerber@inf.ethz.ch>
Wed, 27 Jul 2016 09:59:35 +0000 (11:59 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Wed, 27 Jul 2016 11:28:23 +0000 (13:28 +0200)
Signed-off-by: Simon Gerber <simon.gerber@inf.ethz.ch>

errors/errno.fugu
include/barrelfish/slot_alloc.h
lib/barrelfish/slot_alloc/slot_alloc.c
lib/barrelfish/slot_alloc/twolevel_slot_alloc.c
lib/mm/slot_alloc_2.c

index 7a2d511..ed80ea9 100755 (executable)
@@ -240,6 +240,7 @@ errors libbarrelfish LIB_ERR_ {
     failure SLOT_ALLOC             "Failure in slot_alloc()",
     failure SLOT_FREE              "Failure in slot_free()",
     failure SLOT_UNALLOCATED       "slot_free() was called on an unallocated slot",
+    failure ROOTSA_RESIZE          "Failure while resizing root slot allocator",
 
     // vspace
     failure VSPACE_CURRENT_INIT "Failure in vspace_current_init()",
index e7c0248..c1b7e85 100644 (file)
@@ -61,6 +61,8 @@ struct multi_slot_allocator {
     struct slab_allocator slab;      ///< Slab backing the slot_allocator_list
 
     struct vspace_mmu_aware mmu_state;
+
+    cslot_t rootcn_slots;  ///<< Number of slots in root cnode
 };
 
 struct range_slot_allocator {
@@ -108,8 +110,13 @@ errval_t slot_alloc_init(void);
 errval_t slot_alloc_init_2(void);
 struct slot_allocator *get_default_slot_allocator(void);
 errval_t slot_alloc(struct capref *ret);
+
+/// Root slot allocator functions
 errval_t slot_alloc_root(struct capref *ret);
-errval_t rootsa_update(cslot_t newslotcount);
+typedef errval_t (*cn_ram_alloc_func_t)(void *st, uint8_t reqbits, struct capref *ret);
+errval_t root_slot_allocator_refill(cslot_t *nslots, cn_ram_alloc_func_t myalloc,
+                                    void *allocst);
+
 errval_t slot_free(struct capref ret);
 
 errval_t range_slot_alloc(struct range_slot_allocator *alloc, cslot_t nslots,
index 31949a3..83dde38 100644 (file)
@@ -59,11 +59,58 @@ errval_t slot_alloc_root(struct capref *ret)
     return ca->alloc(ca, ret);
 }
 
-errval_t rootsa_update(cslot_t newslotcount)
+typedef errval_t (*cn_ram_alloc_func_t)(void *st, uint8_t reqbits, struct capref *ret);
+
+errval_t root_slot_allocator_refill(cslot_t *nslots, cn_ram_alloc_func_t myalloc,
+                                    void *allocst)
 {
+    errval_t err;
+
+    uint8_t rootbits = log2ceil(*nslots);
+    assert((1UL << rootbits) == *nslots);
+
+    // Double size of root cnode
+    struct capref root_ram, newroot_cap;
+    err = myalloc(allocst, rootbits + 1 + OBJBITS_CTE, &root_ram);
+    if (err_is_fail(err)) {
+        return err_push(err, MM_ERR_SLOT_MM_ALLOC);
+    }
+    err = slot_alloc(&newroot_cap);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_SLOT_ALLOC);
+    }
+    err = cnode_create_from_mem(newroot_cap, root_ram, ObjType_L1CNode,
+            NULL, *nslots * 2);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_CNODE_CREATE_FROM_MEM);
+    }
+    // Delete RAM cap of new CNode
+    err = cap_delete(root_ram);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_CAP_DELETE);
+    }
+
+    // Resize rootcn
+    debug_printf("retslot: %"PRIxCADDR"\n", get_cap_addr(root_ram));
+    err = root_cnode_resize(newroot_cap, root_ram);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "resizing root cnode");
+        return err;
+    }
+
+    // Delete old Root CNode and free slot
+    err = cap_destroy(root_ram);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "deleting old root cnode");
+        return err_push(err, LIB_ERR_CAP_DESTROY);
+    }
+
+    // update root slot allocator size and our metadata
     struct slot_alloc_state *state = get_slot_alloc_state();
     struct single_slot_allocator *sca = &state->rootca;
-    return single_slot_alloc_resize(sca, newslotcount);
+    return single_slot_alloc_resize(sca, *nslots *= 2);
+
+    return SYS_ERR_OK;
 }
 
 /**
index bdd1e53..6bb889a 100644 (file)
 #include <barrelfish/barrelfish.h>
 #include "internal.h"
 
+static errval_t rootcn_alloc(void *st, uint8_t reqbits, struct capref *ret)
+{
+    return ram_alloc(ret, reqbits);
+}
+
 /**
  * \brief slot allocator
  *
@@ -57,13 +62,21 @@ errval_t two_level_alloc(struct slot_allocator *ca, struct capref *ret)
         struct capref cap;
         struct cnoderef cnode;
         err = slot_alloc_root(&cap);
+        thread_mutex_unlock(&ca->mutex);
+        // 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) {
+            debug_printf("root CNode allocator out of slots; refilling\n");
+            // resize root slot allocator (and rootcn)
+            err = root_slot_allocator_refill(&mca->rootcn_slots, rootcn_alloc, NULL);
+            if (err_is_fail(err)) {
+                return err_push(err, LIB_ERR_ROOTSA_RESIZE);
+            }
+            err = slot_alloc_root(&cap);
+        }
         if (err_is_fail(err)) {
-            thread_mutex_unlock(&ca->mutex);
-            debug_printf("root CNode allocator out of slots; can't refill\n");
             return err_push(err, LIB_ERR_SLOT_ALLOC);
         }
-        thread_mutex_unlock(&ca->mutex); // cnode_create_raw uses ram_alloc
-                                         // which may call slot_alloc
         err = cnode_create_raw(cap, &cnode, ObjType_L2CNode, ca->nslots, NULL);
         if (err_is_fail(err)) {
             return err_push(err, LIB_ERR_CNODE_CREATE);
index ba878e4..4142abd 100644 (file)
 #include <mm/slot_alloc.h>
 #include <stdio.h>
 
+static errval_t rootcn_alloc(void *st, uint8_t reqbits, struct capref *ret)
+{
+    return mm_alloc(st, reqbits, ret, NULL);
+}
+
 /// Allocate a new cnode if needed
 errval_t slot_prealloc_refill_2(struct slot_prealloc_2 *this)
 {
@@ -38,48 +43,11 @@ errval_t slot_prealloc_refill_2(struct slot_prealloc_2 *this)
     struct capref cnode_cap;
     err = slot_alloc_root(&cnode_cap);
     if (err_no(err) == LIB_ERR_SLOT_ALLOC_NO_SPACE) {
-        // Root cnode full, resize it
-        uint8_t rootbits = log2ceil(this->rootcn_slots);
-        assert((1UL << rootbits) == this->rootcn_slots);
-        // Double size
-        struct capref root_ram, newroot_cap;
-        err = mm_alloc(this->mm, rootbits + 1 + OBJBITS_CTE, &root_ram, NULL);
-        if (err_is_fail(err)) {
-            return err_push(err, MM_ERR_SLOT_MM_ALLOC);
-        }
-        err = slot_alloc(&newroot_cap);
-        if (err_is_fail(err)) {
-            return err_push(err, LIB_ERR_SLOT_ALLOC);
-        }
-        err = cnode_create_from_mem(newroot_cap, root_ram, ObjType_L1CNode,
-                NULL, this->rootcn_slots * 2);
-        if (err_is_fail(err)) {
-            return err_push(err, LIB_ERR_CNODE_CREATE_FROM_MEM);
-        }
-        // Delete RAM cap of new CNode
-        err = cap_delete(root_ram);
+        // resize root slot allocator (and rootcn)
+        err = root_slot_allocator_refill(&this->rootcn_slots, rootcn_alloc, this->mm);
         if (err_is_fail(err)) {
-            return err_push(err, LIB_ERR_CAP_DELETE);
+            return err_push(err, LIB_ERR_ROOTSA_RESIZE);
         }
-
-        // Resize rootcn
-        debug_printf("retslot: %"PRIxCADDR"\n", get_cap_addr(root_ram));
-        err = root_cnode_resize(newroot_cap, root_ram);
-        if (err_is_fail(err)) {
-            DEBUG_ERR(err, "resizing root cnode");
-            return err;
-        }
-
-        // Delete old Root CNode and free slot
-        err = cap_destroy(root_ram);
-        if (err_is_fail(err)) {
-            DEBUG_ERR(err, "deleting old root cnode");
-            return err_push(err, LIB_ERR_CAP_DESTROY);
-        }
-
-        // update root slot allocator size and our metadata
-        rootsa_update(this->rootcn_slots *= 2);
-
         // retry slot_alloc_root
         err = slot_alloc_root(&cnode_cap);
     }