T266: Resizing root cnode enabled for libmm slot allocator
[barrelfish] / lib / mm / slot_alloc_2.c
1 /**
2  * \file
3  * \brief Slot management for the memory allocator.
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2016, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <barrelfish/barrelfish.h>
16 #include <mm/mm.h>
17 #include <mm/slot_alloc.h>
18 #include <stdio.h>
19
20 /// Allocate a new cnode if needed
21 errval_t slot_prealloc_refill_2(struct slot_prealloc_2 *this)
22 {
23     uint8_t refill = !this->current;
24     errval_t err;
25
26     if (this->meta[refill].free == L2_CNODE_SLOTS) {
27         return SYS_ERR_OK; // Nop
28     }
29
30     // Allocate a ram cap
31     struct capref ram_cap;
32     err = mm_alloc(this->mm, L2_CNODE_BITS + OBJBITS_CTE, &ram_cap, NULL);
33     if (err_is_fail(err)) {
34         return err_push(err, MM_ERR_SLOT_MM_ALLOC);
35     }
36
37     // Retype to and build the next cnode
38     struct capref cnode_cap;
39     err = slot_alloc_root(&cnode_cap);
40     if (err_no(err) == LIB_ERR_SLOT_ALLOC_NO_SPACE) {
41         // Root cnode full, resize it
42         uint8_t rootbits = log2ceil(this->rootcn_slots);
43         assert((1UL << rootbits) == this->rootcn_slots);
44         // Double size
45         struct capref root_ram, newroot_cap;
46         err = mm_alloc(this->mm, rootbits + 1 + OBJBITS_CTE, &root_ram, NULL);
47         if (err_is_fail(err)) {
48             return err_push(err, MM_ERR_SLOT_MM_ALLOC);
49         }
50         err = slot_alloc(&newroot_cap);
51         if (err_is_fail(err)) {
52             return err_push(err, LIB_ERR_SLOT_ALLOC);
53         }
54         err = cnode_create_from_mem(newroot_cap, root_ram, ObjType_L1CNode,
55                 NULL, this->rootcn_slots * 2);
56         if (err_is_fail(err)) {
57             return err_push(err, LIB_ERR_CNODE_CREATE_FROM_MEM);
58         }
59         // Delete RAM cap of new CNode
60         err = cap_delete(root_ram);
61         if (err_is_fail(err)) {
62             return err_push(err, LIB_ERR_CAP_DELETE);
63         }
64
65         // Resize rootcn
66         debug_printf("retslot: %"PRIxCADDR"\n", get_cap_addr(root_ram));
67         err = root_cnode_resize(newroot_cap, root_ram);
68         if (err_is_fail(err)) {
69             DEBUG_ERR(err, "resizing root cnode");
70             return err;
71         }
72
73         // Delete old Root CNode and free slot
74         err = cap_destroy(root_ram);
75         if (err_is_fail(err)) {
76             DEBUG_ERR(err, "deleting old root cnode");
77             return err_push(err, LIB_ERR_CAP_DESTROY);
78         }
79
80         // update root slot allocator size and our metadata
81         rootsa_update(this->rootcn_slots *= 2);
82
83         // retry slot_alloc_root
84         err = slot_alloc_root(&cnode_cap);
85     }
86     if (err_is_fail(err)) {
87         return err_push(err, LIB_ERR_SLOT_ALLOC);
88     }
89
90     err = cnode_create_from_mem(cnode_cap, ram_cap, ObjType_L2CNode,
91             &this->meta[refill].cap.cnode, L2_CNODE_SLOTS);
92     if (err_is_fail(err)) {
93         return err_push(err, LIB_ERR_CNODE_CREATE);
94     }
95
96     // Set the metadata
97     this->meta[refill].cap.slot  = 0;
98     this->meta[refill].free      = L2_CNODE_SLOTS;
99
100     return SYS_ERR_OK;
101 }
102
103 errval_t slot_alloc_prealloc_2(void *inst, uint64_t nslots, struct capref *ret)
104 {
105     struct slot_prealloc_2 *this = inst;
106     assert(nslots <= (1UL << this->maxslotbits));
107
108     /* Check if enough space */
109     if (this->meta[this->current].free < nslots) {
110         // Allocate from next cnode
111         this->current = !this->current;
112     }
113
114     if (this->meta[this->current].free < nslots) {
115         return MM_ERR_SLOT_NOSLOTS;
116     }
117
118     /* Return next slot and update */
119     *ret = this->meta[this->current].cap;
120     this->meta[this->current].cap.slot += nslots;
121     this->meta[this->current].free -= nslots;
122
123     return SYS_ERR_OK;
124 }
125
126 /**
127  * \brief Initialise preallocating slot allocator instance
128  *
129  * \param this Pointer to area for instance data
130  * \param maxslotbits Maximum size of each allocation (in bits)
131  * \param initial_cnode First cap in an empty cnode to start allocating from
132  * \param initial_space Number of slots free in initial cnode
133  * \param ram_mm Memory allocator to use for RAM caps when creating new CNodes
134  */
135 errval_t slot_prealloc_init_2(struct slot_prealloc_2 *this, uint8_t maxslotbits,
136                               struct capref initial_cnode, uint64_t initial_space,
137                               struct mm *ram_mm)
138 {
139     this->maxslotbits = maxslotbits;
140     this->mm = ram_mm;
141
142     assert(initial_space == L2_CNODE_SLOTS);
143     if (initial_space != L2_CNODE_SLOTS) {
144         debug_printf("Initial CNode for 2 level preallocating slot allocator needs to be 16kB");
145         return LIB_ERR_SLOT_ALLOC_INIT;
146     }
147
148     this->current = 0;
149     this->meta[0].cap       = initial_cnode;
150     this->meta[0].free      = initial_space;
151     this->meta[1].free      = 0;
152
153     // XXX: Do something like
154     // this->rootcn_slots = invoke_cnode_get_slots(cap_root);
155     this->rootcn_slots = L2_CNODE_SLOTS;
156
157     return SYS_ERR_OK;
158 }