diff options
Diffstat (limited to 'kernel/vm/shadow.c')
-rw-r--r-- | kernel/vm/shadow.c | 188 |
1 files changed, 177 insertions, 11 deletions
diff --git a/kernel/vm/shadow.c b/kernel/vm/shadow.c index 312b32e..91b1fce 100644 --- a/kernel/vm/shadow.c +++ b/kernel/vm/shadow.c @@ -41,7 +41,8 @@ static mobj_ops_t shadow_mobj_ops = {.get_pframe = shadow_get_pframe, */ void shadow_init() { - NOT_YET_IMPLEMENTED("VM: shadow_init"); + // NOT_YET_IMPLEMENTED("VM: shadow_init"); + shadow_allocator = slab_allocator_create("shadow", sizeof(mobj_shadow_t)); } /* @@ -60,8 +61,37 @@ void shadow_init() */ mobj_t *shadow_create(mobj_t *shadowed) { - NOT_YET_IMPLEMENTED("VM: shadow_create"); - return NULL; + // NOT_YET_IMPLEMENTED("VM: shadow_create"); + + // create a new shadow object + mobj_shadow_t *so = (mobj_shadow_t *)slab_obj_alloc(shadow_allocator); + if (!so) + { + return NULL; + } + + // initialize the mobj_shadow_t + + // set the bottom_mobj based on the two cases + if (shadowed->mo_type == MOBJ_SHADOW) + { + so->bottom_mobj = MOBJ_TO_SO(so->shadowed)->bottom_mobj; + } + else + { + so->bottom_mobj = shadowed; + } + // init the other fields + so->shadowed = shadowed; + mobj_init(&so->mobj, MOBJ_SHADOW, &shadow_mobj_ops); + mobj_ref(so->shadowed); + mobj_ref(so->bottom_mobj); + + // lock the shadow object + mobj_lock(&so->mobj); + + // return the shadow object + return &so->mobj; } /* @@ -80,7 +110,52 @@ mobj_t *shadow_create(mobj_t *shadowed) */ void shadow_collapse(mobj_t *o) { - NOT_YET_IMPLEMENTED("VM: shadow_collapse"); + // NOT_YET_IMPLEMENTED("VM: shadow_collapse"); + + // get the mobj_shadow_t and it's mobj + mobj_shadow_t *so = MOBJ_TO_SO(o); + mobj_t *iter = so->shadowed; + // iterate through the shadow chain + while (iter && so->shadowed->mo_type == MOBJ_SHADOW) + { + // check to see if the refcount is not 1. if so, continue to next shadowed object + if (so->shadowed->mo_refcount != 1) + { + iter = so->shadowed; + continue; + } + // else, go over the shadowed object's pframes + + // iterate through the pframes + mobj_lock(&so->shadowed); + list_iterate(&so->shadowed->mo_pframes, pframe, pframe_t, pf_link) + { + // get the pframe from the shadow object + pframe_t *spf = NULL; + + mobj_lock(iter); // lock before getting the pframe + mobj_find_pframe(o, pframe->pf_pagenum, &spf); + mobj_unlock(iter); + + // check if the pframe is not in the shadow object when migrating + if (spf == NULL) + { + // if not, remove the pframe from the shadowed object + // and insert it into out iterated shadow object + list_remove(&pframe->pf_link); + list_insert_tail(&iter->mo_pframes, &pframe->pf_link); + } + else + { + // if it is, release the pframe we found + pframe_release(&spf); + } + } + + // put locked the shadowed object after iterating through it + mobj_put_locked(&so->shadowed); + // FIXME: this is probably wrong + } } /* @@ -111,8 +186,47 @@ void shadow_collapse(mobj_t *o) static long shadow_get_pframe(mobj_t *o, size_t pagenum, long forwrite, pframe_t **pfp) { - NOT_YET_IMPLEMENTED("VM: shadow_get_pframe"); - return 0; + // NOT_YET_IMPLEMENTED("VM: shadow_get_pframe"); + + // if forwrite is set, use mobj_default_get_pframe + if (forwrite) + { + return mobj_default_get_pframe(o, pagenum, forwrite, pfp); + } + + // else, check if the object already contains the desired frame + pframe_t *pf = NULL; + mobj_find_pframe(o, pagenum, &pf); + if (pf) + { + // if it does, return the pframe + *pfp = pf; + return 0; + } + + // iterate through the shadow chain to find the nearest shadow mobj that has the frame + mobj_shadow_t *so = MOBJ_TO_SO(o); + mobj_t *iter = so->shadowed; + while (iter && iter->mo_type == MOBJ_SHADOW) + { + mobj_lock(iter); + mobj_find_pframe(o, pagenum, &pf); + mobj_unlock(iter); + if (pf) + { + *pfp = pf; + return 0; + } + // update the iterator + iter = MOBJ_TO_SO(iter)->shadowed; + } + + // if no shadow objects have the page, call mobj_get_pframe() to get the page from the bottom object + // at this point, iter is the bottom object + mobj_lock(iter); + long ret = mobj_get_pframe(iter, pagenum, forwrite, pfp); + mobj_unlock(iter); + return ret; } /* @@ -138,8 +252,47 @@ static long shadow_get_pframe(mobj_t *o, size_t pagenum, long forwrite, */ static long shadow_fill_pframe(mobj_t *o, pframe_t *pf) { - NOT_YET_IMPLEMENTED("VM: shadow_fill_pframe"); - return -1; + // NOT_YET_IMPLEMENTED("VM: shadow_fill_pframe"); + + // get the mobj_shadow_t + mobj_shadow_t *so = MOBJ_TO_SO(o); + // iterate over the shadow chain + mobj_t *iter = so->shadowed; + while (iter && iter->mo_type == MOBJ_SHADOW) + { + // get the pframe from the shadow object + pframe_t *spf = NULL; + mobj_lock(iter); + mobj_find_pframe(o, pf->pf_pagenum, &spf); + mobj_unlock(iter); + + // if the pframe is found, copy the contents into pf + // then release the pframe + if (spf) + { + memcpy(pf->pf_addr, spf->pf_addr, PAGE_SIZE); + pframe_release(&spf); + return 0; + } + + // update the iterator + iter = MOBJ_TO_SO(iter)->shadowed; + } + + // if none of the shadow objects have a copy of the frame, use mobj_get_pframe on the bottom object + pframe_t *spf = NULL; + mobj_lock(iter); + long ret = mobj_get_pframe(iter, pf->pf_pagenum, 0, &spf); + mobj_unlock(iter); + // check if the operation was sucessful, memcpy the contents into pf + // and release the pframe + if (ret == 0) + { + memcpy(pf->pf_addr, pf->pf_addr, PAGE_SIZE); + pframe_release(&spf); + } + + return ret; } /* @@ -153,8 +306,8 @@ static long shadow_fill_pframe(mobj_t *o, pframe_t *pf) */ static long shadow_flush_pframe(mobj_t *o, pframe_t *pf) { - NOT_YET_IMPLEMENTED("VM: shadow_flush_pframe"); - return -1; + // NOT_YET_IMPLEMENTED("VM: shadow_flush_pframe"); + return 0; } /* @@ -169,5 +322,18 @@ static long shadow_flush_pframe(mobj_t *o, pframe_t *pf) */ static void shadow_destructor(mobj_t *o) { - NOT_YET_IMPLEMENTED("VM: shadow_destructor"); + // NOT_YET_IMPLEMENTED("VM: shadow_destructor"); + + // get the mobj_shadow_t + mobj_shadow_t *so = MOBJ_TO_SO(o); + + // call the default destructor + mobj_default_destructor(o); + + // put the shadow and bottom_mobj + mobj_put(&so->shadowed); + mobj_put(&so->bottom_mobj); + + // free the slab + slab_obj_free(shadow_allocator, so); } |