Fixed leaking of allocated stuff in paging (but not partially completed mapping)
This commit is contained in:
parent
347f3a1155
commit
07a861ea61
@ -40,8 +40,6 @@ typedef int paging_flags_t;
|
||||
|
||||
// NOTE rueegges: page table metadata used to create child mappings and unmap
|
||||
struct pt_t {
|
||||
// the level of the page table. since we abuse this struct also to track l3 entries we set it to 4 there.
|
||||
size_t level;
|
||||
// capref that holds this page table
|
||||
struct capref cap_pt;
|
||||
// capref that maps this page table in the higher level page table
|
||||
@ -67,7 +65,9 @@ struct paging_state {
|
||||
// NOTE rueegges: remember if we are refilling so we can skip the checks
|
||||
uint8_t refilling;
|
||||
|
||||
// TODO rueegges: use to track an allocated slot in failure conditions
|
||||
// NOTE rueegges: use to track an already allocated page table in failure conditions
|
||||
struct capref free_l1_vnode;
|
||||
struct capref free_l2_vnode;
|
||||
struct capref free_l3_vnode;
|
||||
|
||||
// TODO rueegges: implement more precisely?
|
||||
|
||||
230
lib/aos/paging.c
230
lib/aos/paging.c
@ -29,7 +29,6 @@ static struct paging_state current;
|
||||
#define PT_PT_SLAB_INITIAL_SPACE SLAB_STATIC_SIZE(PT_PT_SLAB_MIN_SPACE, sizeof(struct pt_t))
|
||||
#define PT_CHILDREN_SLAB_INITIAL_SPACE SLAB_STATIC_SIZE(PT_CHILDREN_SLAB_MIN_SPACE, BASE_PAGE_SIZE)
|
||||
|
||||
// NOTE rueegges: temporary (?) solution for initial slab space
|
||||
char pt_pt_slab_buf[PT_PT_SLAB_INITIAL_SPACE];
|
||||
char pt_children_slab_buf[PT_CHILDREN_SLAB_INITIAL_SPACE];
|
||||
|
||||
@ -102,20 +101,20 @@ void pt_print_state(struct paging_state *st) {
|
||||
// - this slab
|
||||
// - child slab
|
||||
// - mm slab
|
||||
static errval_t pt_ensure_slots_and_slabs(struct paging_state *st) {
|
||||
static errval_t pt_ensure_slabs(struct paging_state *st) {
|
||||
errval_t err;
|
||||
|
||||
// ensure there is enough space to refill the page tables at any time
|
||||
if(slab_freecount(&st->pt_slabs) <= PT_PT_SLAB_MIN_SPACE && !st->refilling) {
|
||||
// ASSESSMENT M1: show refilling
|
||||
// debug_printf("DEBUG rueegges: pt_ensure_slots_and_slabs - refilling pt_slab\n");
|
||||
// debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_slab\n");
|
||||
|
||||
st->refilling = 1;
|
||||
|
||||
err = slab_default_refill(&st->pt_slabs);
|
||||
|
||||
st->refilling = 0;
|
||||
// debug_printf("DEBUG rueegges: pt_ensure_slots_and_slabs - refilling pt_slab DONE\n");
|
||||
// debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_slab DONE\n");
|
||||
|
||||
if(err_is_fail(err)) {
|
||||
return err_push(err, LIB_ERR_SLAB_REFILL);
|
||||
@ -124,7 +123,7 @@ static errval_t pt_ensure_slots_and_slabs(struct paging_state *st) {
|
||||
|
||||
if(slab_freecount(&st->pt_children_slabs) <= PT_CHILDREN_SLAB_MIN_SPACE && !st->refilling) {
|
||||
// ASSESSMENT M1: show refilling
|
||||
// debug_printf("DEBUG rueegges: pt_ensure_slots_and_slabs - refilling pt_children_slabs\n");
|
||||
// debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_children_slabs\n");
|
||||
|
||||
st->refilling = 1;
|
||||
|
||||
@ -137,7 +136,7 @@ static errval_t pt_ensure_slots_and_slabs(struct paging_state *st) {
|
||||
err = slab_refill_no_pagefault(&st->pt_children_slabs, frame_cap, 10 * 4096);
|
||||
|
||||
st->refilling = 0;
|
||||
// debug_printf("DEBUG rueegges: pt_ensure_slots_and_slabs - refilling pt_children_slabs DONE\n");
|
||||
// debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_children_slabs DONE\n");
|
||||
|
||||
if(err_is_fail(err)) {
|
||||
return err_push(err, LIB_ERR_SLAB_REFILL);
|
||||
@ -147,53 +146,83 @@ static errval_t pt_ensure_slots_and_slabs(struct paging_state *st) {
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
// NOTE rueegges: ensures that a page table exists at the specified index in the parent page table and return it
|
||||
static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_t pt_index, struct pt_t **pt_ret){
|
||||
// debug_printf("DEBUG rueegges: pt_ensure l%u\n", pt_parent->level+1);
|
||||
|
||||
static errval_t pt_alloc_level(struct paging_state *st, struct capref *pt_cap, uint8_t level) {
|
||||
errval_t err;
|
||||
|
||||
// If this fails we got an l3 pt as the parent
|
||||
assert(pt_parent->children != NULL);
|
||||
assert(pt_parent->level < 3);
|
||||
|
||||
// MUST DO before check if table already exists since it might create it
|
||||
// make sure slot and slab refilling is performed in time
|
||||
err = pt_ensure_slots_and_slabs(st);
|
||||
if(err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "Could not restock slots and slabs");
|
||||
return err;
|
||||
}
|
||||
|
||||
// check if the page table already exists
|
||||
struct pt_t *res = (pt_parent->children)[pt_index];
|
||||
if (res != NULL) {
|
||||
*pt_ret = res;
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
// create the page table
|
||||
struct capref pt_cap;
|
||||
switch(pt_parent->level){
|
||||
case 0:
|
||||
err = pt_alloc_l1(st, &pt_cap);
|
||||
break;
|
||||
switch(level){
|
||||
case 1:
|
||||
err = pt_alloc_l2(st, &pt_cap);
|
||||
if(!capref_is_null(st->free_l1_vnode)){
|
||||
*pt_cap = st->free_l1_vnode;
|
||||
st->free_l1_vnode = NULL_CAP;
|
||||
err = SYS_ERR_OK;
|
||||
} else {
|
||||
err = pt_alloc_l1(st, pt_cap);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
err = pt_alloc_l3(st, &pt_cap);
|
||||
if(!capref_is_null(st->free_l2_vnode)){
|
||||
*pt_cap = st->free_l2_vnode;
|
||||
st->free_l2_vnode = NULL_CAP;
|
||||
err = SYS_ERR_OK;
|
||||
} else {
|
||||
err = pt_alloc_l2(st, pt_cap);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if(!capref_is_null(st->free_l3_vnode)){
|
||||
*pt_cap = st->free_l3_vnode;
|
||||
st->free_l3_vnode = NULL_CAP;
|
||||
err = SYS_ERR_OK;
|
||||
} else {
|
||||
err = pt_alloc_l3(st, pt_cap);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
err = ERR_INVALID_ARGS;
|
||||
break;
|
||||
}
|
||||
if (err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "Failed pt_alloc l%u", pt_parent->level + 1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void pt_save_allocation(struct paging_state *st, struct capref cap, uint8_t level) {
|
||||
switch(level){
|
||||
case 1:
|
||||
assert(capref_is_null(st->free_l1_vnode));
|
||||
st->free_l1_vnode = cap;
|
||||
break;
|
||||
case 2:
|
||||
assert(capref_is_null(st->free_l2_vnode));
|
||||
st->free_l2_vnode = cap;
|
||||
break;
|
||||
case 3:
|
||||
assert(capref_is_null(st->free_l3_vnode));
|
||||
st->free_l3_vnode = cap;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE rueegges: ensures that a page table exists at the specified index in the parent page table and return it
|
||||
static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_t pt_index, uint8_t level, struct pt_t **pt_ret){
|
||||
errval_t err;
|
||||
struct pt_t *res;
|
||||
|
||||
// debug_printf("DEBUG rueegges: pt_ensure l%u\n", pt_parent->level+1);
|
||||
|
||||
// If this fails we got an l3 pt as the parent
|
||||
assert(pt_parent->children != NULL);
|
||||
assert(level > 0 && level <= 3);
|
||||
|
||||
// MUST DO before check if table already exists since it might create it
|
||||
// make sure slot and slab refilling is performed in time
|
||||
err = pt_ensure_slabs(st);
|
||||
if(err_is_fail(err)) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// TODO rueegges: store the allocated pt
|
||||
// check if the page table already exists
|
||||
res = (pt_parent->children)[pt_index];
|
||||
if (res != NULL) {
|
||||
@ -201,77 +230,61 @@ static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
// debug_printf("DEBUG rueegges: allocated pt l%u\n", pt_parent->level+1);
|
||||
|
||||
// create new mapping
|
||||
struct capref pt_mapping;
|
||||
err = st->slot_alloc->alloc(st->slot_alloc, &pt_mapping);
|
||||
if (err_is_fail(err))
|
||||
{
|
||||
// NOTE rueegges: cannot free the pt allocated above since we do not have the ram cap
|
||||
|
||||
DEBUG_ERR(err, "Failed slot alloc for new pt mapping");
|
||||
// create the page table
|
||||
struct capref pt_cap;
|
||||
err = pt_alloc_level(st, &pt_cap, level);
|
||||
if (err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "Failed pt_alloc l%u", level);
|
||||
return err;
|
||||
}
|
||||
err = vnode_map(pt_parent->cap_pt, pt_cap, pt_index, 0, 0, 1, pt_mapping);
|
||||
if (err_is_fail(err))
|
||||
{
|
||||
// free the already allocated capref
|
||||
errval_t err_err = st->slot_alloc->free(st->slot_alloc, pt_mapping);
|
||||
if (err_is_fail(err_err)) {
|
||||
DEBUG_ERR(err_err, "Failed to free capability slot during error handling");
|
||||
}
|
||||
|
||||
// NOTE rueegges: cannot free the pt allocated above since we do not have the ram cap
|
||||
|
||||
DEBUG_ERR(err, "Failed vnode_map for pt l%u", pt_parent->level + 1);
|
||||
return err_push(err, LIB_ERR_VNODE_MAP);
|
||||
// check if the page table already exists
|
||||
res = (pt_parent->children)[pt_index];
|
||||
if (res != NULL) {
|
||||
*pt_ret = res;
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
// debug_printf("DEBUG rueegges: inserted mapping for pt l%u\n", pt_parent->level+1);
|
||||
|
||||
// allocate shadow page table space
|
||||
struct pt_t *pt_meta = (struct pt_t *) slab_alloc(&st->pt_slabs);
|
||||
if(pt_meta == NULL) {
|
||||
err = vnode_unmap(pt_cap, pt_mapping);
|
||||
if (err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "Failed to unmap pt during error handling");
|
||||
}
|
||||
|
||||
err = st->slot_alloc->free(st->slot_alloc, pt_mapping);
|
||||
if (err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "Failed to free capability slot during error handling");
|
||||
}
|
||||
|
||||
// NOTE rueegges: cannot free the pt allocated above since we do not have the ram cap
|
||||
|
||||
pt_save_allocation(st, pt_cap, level);
|
||||
return LIB_ERR_SLAB_ALLOC_FAIL;
|
||||
}
|
||||
|
||||
struct pt_t **pt_children = (struct pt_t **) slab_alloc(&st->pt_children_slabs);
|
||||
if(pt_children == NULL) {
|
||||
err = vnode_unmap(pt_cap, pt_mapping);
|
||||
if (err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "Failed to unmap pt during error handling");
|
||||
}
|
||||
slab_free(&st->pt_slabs, pt_meta);
|
||||
pt_save_allocation(st, pt_cap, level);
|
||||
return LIB_ERR_SLAB_ALLOC_FAIL;
|
||||
}
|
||||
|
||||
err = st->slot_alloc->free(st->slot_alloc, pt_mapping);
|
||||
if (err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "Failed to free capability slot during error handling");
|
||||
// create new mapping
|
||||
struct capref pt_mapping;
|
||||
err = st->slot_alloc->alloc(st->slot_alloc, &pt_mapping);
|
||||
if (err_is_fail(err)) {
|
||||
slab_free(&st->pt_slabs, pt_meta);
|
||||
slab_free(&st->pt_children_slabs, pt_children);
|
||||
pt_save_allocation(st, pt_cap, level);
|
||||
return err_push(err, LIB_ERR_SLOT_ALLOC);
|
||||
}
|
||||
err = vnode_map(pt_parent->cap_pt, pt_cap, pt_index, 0, 0, 1, pt_mapping);
|
||||
if (err_is_fail(err)) {
|
||||
errval_t err_err = st->slot_alloc->free(st->slot_alloc, pt_mapping);
|
||||
if (err_is_fail(err_err)) {
|
||||
DEBUG_ERR(err_err, "Failed to free capability slot during error handling");
|
||||
}
|
||||
|
||||
slab_free(&st->pt_slabs, pt_meta);
|
||||
|
||||
// NOTE rueegges: cannot free the pt allocated above since we do not have the ram cap
|
||||
|
||||
return LIB_ERR_SLAB_ALLOC_FAIL;
|
||||
slab_free(&st->pt_children_slabs, pt_children);
|
||||
pt_save_allocation(st, pt_cap, level);
|
||||
DEBUG_ERR(err, "Failed vnode_map for pt l%u", level);
|
||||
return err_push(err, LIB_ERR_VNODE_MAP);
|
||||
}
|
||||
|
||||
// save metadata
|
||||
// make sure all child pointers are initialized to NULL
|
||||
memset(pt_children, 0, st->pt_children_slabs.blocksize);
|
||||
|
||||
// debug_printf("DEBUG rueegges: completed shadow allocation for pt l%u\n", pt_parent->level+1);
|
||||
|
||||
pt_meta->level = pt_parent->level + 1;
|
||||
pt_meta->cap_pt = pt_cap;
|
||||
pt_meta->cap_mapping = pt_mapping;
|
||||
pt_meta->children = pt_children;
|
||||
@ -306,9 +319,6 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr,
|
||||
|
||||
assert(ca != NULL);
|
||||
|
||||
st->slot_alloc = ca;
|
||||
st->refilling = 0;
|
||||
|
||||
// initialize slab allocators
|
||||
// TODO rueegges: is this how we should initialize the slab allocators?
|
||||
slab_init(&st->pt_slabs, sizeof(struct pt_t), NULL);
|
||||
@ -331,11 +341,18 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr,
|
||||
// make sure all child pointers are initialized to NULL
|
||||
memset(l0_children, 0, st->pt_children_slabs.blocksize);
|
||||
|
||||
l0_pt->level = 0;
|
||||
l0_pt->cap_pt = pdir;
|
||||
l0_pt->cap_mapping = NULL_CAP;
|
||||
l0_pt->children = l0_children;
|
||||
|
||||
st->slot_alloc = ca;
|
||||
st->l0_pt = l0_pt;
|
||||
st->refilling = 0;
|
||||
|
||||
st->free_l1_vnode = NULL_CAP;
|
||||
st->free_l2_vnode = NULL_CAP;
|
||||
st->free_l3_vnode = NULL_CAP;
|
||||
|
||||
st->next_vaddr = start_vaddr;
|
||||
|
||||
return SYS_ERR_OK;
|
||||
@ -488,15 +505,13 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
|
||||
lvaddr_t end_vaddr = vaddr + bytes;
|
||||
assert(VADDR_OFFSET <= vaddr && vaddr < end_vaddr &&
|
||||
end_vaddr <= VADDR_OFFSET + PTABLE_ENTRIES * PTABLE_ENTRIES *PTABLE_ENTRIES * PTABLE_ENTRIES * BASE_PAGE_SIZE);
|
||||
|
||||
// consistentcy checks
|
||||
assert(st != NULL);
|
||||
assert(st->slot_alloc != NULL);
|
||||
assert(st->l0_pt->level == 0);
|
||||
|
||||
// debug_printf("DEBUG rueegges: paging_map_fixed_attr(%p, 0x%lx, cap, %lu, %d)\n", st, vaddr, bytes, flags);
|
||||
|
||||
// simple fix for now
|
||||
// TODO rueegges: nicefy simple fix for mapping over multiple l3?
|
||||
// TODO rueegges: cleanup partially completed mapping?
|
||||
for(lvaddr_t current_vaddr = vaddr; current_vaddr < vaddr + bytes; current_vaddr += BASE_PAGE_SIZE) {
|
||||
capaddr_t l0_index = VMSAv8_64_L0_INDEX(current_vaddr);
|
||||
capaddr_t l1_index = VMSAv8_64_L1_INDEX(current_vaddr);
|
||||
@ -508,36 +523,32 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
|
||||
|
||||
// get l1 page table
|
||||
struct pt_t *l1_pt;
|
||||
err = pt_ensure(st, st->l0_pt, l0_index, &l1_pt);
|
||||
err = pt_ensure(st, st->l0_pt, l0_index, 1, &l1_pt);
|
||||
if(err_is_fail(err)) {
|
||||
return err;
|
||||
}
|
||||
assert(l1_pt->level == 1);
|
||||
assert(l1_pt->children != NULL);
|
||||
|
||||
// get l2 page table
|
||||
struct pt_t *l2_pt;
|
||||
err = pt_ensure(st, l1_pt, l1_index, &l2_pt);
|
||||
err = pt_ensure(st, l1_pt, l1_index, 2, &l2_pt);
|
||||
if(err_is_fail(err)) {
|
||||
return err;
|
||||
}
|
||||
assert(l2_pt->level == 2);
|
||||
assert(l2_pt->children != NULL);
|
||||
|
||||
// get l3 page table
|
||||
struct pt_t *l3_pt;
|
||||
err = pt_ensure(st, l2_pt, l2_index, &l3_pt);
|
||||
err = pt_ensure(st, l2_pt, l2_index, 3, &l3_pt);
|
||||
if(err_is_fail(err)) {
|
||||
return err;
|
||||
}
|
||||
assert(l3_pt->level == 3);
|
||||
assert(l3_pt->children != NULL);
|
||||
|
||||
// make sure we have enough slot and slab space left
|
||||
err = pt_ensure_slots_and_slabs(st);
|
||||
err = pt_ensure_slabs(st);
|
||||
if(err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "Could not ensure presence of sufficient slabs and slots");
|
||||
return err;
|
||||
return err_push(err, LIB_ERR_SLAB_REFILL);
|
||||
}
|
||||
|
||||
// debug_printf("DEBUG rueegges: paging_map_fixed_attr - allocate mapping meta\n");
|
||||
@ -550,9 +561,6 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
|
||||
|
||||
// set to null to indicate it is a frame mapping and not a page table mapping
|
||||
pt_entry->children = NULL;
|
||||
// NOTE rueegges: we set this to 4 to indicate its an entry not a map to another
|
||||
// table even though for superpages the level would be 3
|
||||
pt_entry->level = 4;
|
||||
// allocate the new mapping
|
||||
err = st->slot_alloc->alloc(st->slot_alloc, &pt_entry->cap_mapping);
|
||||
if (err_is_fail(err)) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user