반응형
cow 개념
해결 방법
- 자식이 부모와 같은 물리메모리를 가리키게한다. (자식의 writable을 0으로 한다.)
- 자식이 write를 할 경우 pagefault를 발생시키고, 메모리를 새로 복사하여 할당 후 write를 수행한다.
(이 과정에서 원래(부모)의 writable을 확인하고, 새 메모리를 할당 후에는 기존(부모)의 writable로 writable을 바꿔준다.)
// 기존코드
bool supplemental_page_table_copy(struct supplemental_page_table *dst,
struct supplemental_page_table *src)
{
struct hash_iterator iter;
hash_first(&iter, &(src->spt));
while (hash_next(&iter))
{
struct page *tmp = hash_entry(hash_cur(&iter), struct page, page_elem);
struct page *cpy = NULL;
switch (VM_TYPE(tmp->operations->type))
{
case VM_UNINIT:
if (VM_TYPE(tmp->uninit.type) == VM_ANON)
{
struct load_segment_aux *info = (struct load_segment_aux *)malloc(sizeof(struct load_segment_aux));
memcpy(info, tmp->uninit.aux, sizeof(struct load_segment_aux));
info->file = file_duplicate(info->file);
vm_alloc_page_with_initializer(tmp->uninit.type, tmp->va, tmp->writable, tmp->uninit.init, (void *)info);
}
break;
case VM_ANON:
vm_alloc_page(tmp->operations->type, tmp->va, tmp->writable);
cpy = spt_find_page(dst, tmp->va);
if (cpy == NULL)
{
return false;
}
struct frame *cpy_frame = malloc(sizeof(struct frame));
cpy->frame = cpy_frame;
cpy_frame->page = cpy;
cpy_frame->kva = tmp->frame->kva;
if (vm_do_claim_page(cpy) == false)
{
return false;
}
// 복사
memcpy(cpy->frame->kva, tmp->frame->kva, PGSIZE);
break;
case VM_FILE:
break;
default:
break;
}
}
return true;
}
// cow 후 코드
case VM_ANON:
vm_alloc_page(tmp->operations->type, tmp->va, tmp->writable);
cpy = spt_find_page(dst, tmp->va);
if (cpy == NULL)
{
return false;
}
cpy->copy_writable = tmp->writable;
struct frame *cpy_frame = malloc(sizeof(struct frame));
cpy->frame = cpy_frame;
cpy_frame->page = cpy;
cpy_frame->kva = tmp->frame->kva;
struct thread *t = thread_current();
lock_acquire(&lru_lock);
list_push_back(&lru, &(cpy_frame->lru_elem));
lock_release(&lru_lock);
// 복사 안하고 pml4만 생성 -> writable을 0으로 초기화!
if (pml4_set_page(t->pml4, cpy->va, cpy_frame->kva, 0) == false)
{
return false;
}
break;
자식이 부모와 같은 메모리를 가리키게 변경 (+ 자식의 wirtable을 0으로 초기화)
bool vm_try_handle_fault(struct intr_frame *f, void *addr,
bool user, bool write, bool not_present)
{
struct supplemental_page_table *spt = &thread_current()->spt;
struct page *page = NULL;
/* TODO: Validate the fault */
/* TODO: Your code goes here */
if (is_kernel_vaddr(addr) && user)
return false;
page = spt_find_page(spt, addr);
// cow - 추가 write protection
if (write && !not_present && page->copy_writable && page)
{
return vm_handle_wp(page);
}
if (page == NULL)
{
struct thread *current_thread = thread_current();
void *stack_bottom = pg_round_down(thread_current()->user_rsp);
if (write && (addr >= pg_round_down(thread_current()->user_rsp - PGSIZE)) && (addr < USER_STACK))
{
vm_stack_growth(addr);
return true;
}
return false;
}
// cow - 추가 (예외처리)
if (write && !page->writable)
{
return false;
}
if (vm_do_claim_page(page))
return true;
return false;
}
write요청이 있을 시 기존의 writable을 확인하고 vm_handle_wp 함수 호출
/* Handle the fault on write_protected page */
static bool
vm_handle_wp(struct page *page)
{
void *parent_kva = page->frame->kva;
page->frame->kva = palloc_get_page(PAL_USER);
memcpy(page->frame->kva, parent_kva, PGSIZE);
pml4_set_page(thread_current()->pml4, page->va, page->frame->kva, page->copy_writable);
return true;
}
메모리를 복사하고 할당해줌
마주한 문제점
이유
// mmu.c
static void
pt_destroy(uint64_t *pt) {
for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t *); i++) {
uint64_t *pte = ptov((uint64_t *)pt[i]);
if (((uint64_t)pte) & PTE_P)
palloc_free_page((void *)PTE_ADDR(pte));
}
palloc_free_page((void *)pt);
}
static void
pgdir_destroy(uint64_t *pdp) {
for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t *); i++) {
uint64_t *pte = ptov((uint64_t *)pdp[i]);
if (((uint64_t)pte) & PTE_P)
pt_destroy(PTE_ADDR(pte));
}
palloc_free_page((void *)pdp);
}
static void
pdpe_destroy(uint64_t *pdpe) {
for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t *); i++) {
uint64_t *pde = ptov((uint64_t *)pdpe[i]);
if (((uint64_t)pde) & PTE_P)
pgdir_destroy((void *)PTE_ADDR(pde));
}
palloc_free_page((void *)pdpe);
}
/* Destroys pml4e, freeing all the pages it references. */
void pml4_destroy(uint64_t *pml4) {
if (pml4 == NULL)
return;
ASSERT(pml4 != base_pml4);
/* if PML4 (vaddr) >= 1, it's kernel space by define. */
uint64_t *pdpe = ptov((uint64_t *)pml4[0]);
if (((uint64_t)pdpe) & PTE_P)
pdpe_destroy((void *)PTE_ADDR(pdpe));
palloc_free_page((void *)pml4);
}
====================================================================
// palloc.c
/* Frees the page at PAGE. */
void palloc_free_page(void *page) {
palloc_free_multiple(page, 1);
}
void palloc_free_multiple(void *pages, size_t page_cnt) {
struct pool *pool;
size_t page_idx;
ASSERT(pg_ofs(pages) == 0);
if (pages == NULL || page_cnt == 0)
return;
if (page_from_pool(&kernel_pool, pages))
pool = &kernel_pool;
else if (page_from_pool(&user_pool, pages))
pool = &user_pool;
else
NOT_REACHED();
page_idx = pg_no(pages) - pg_no(pool->base);
#ifndef NDEBUG
// 👇 나쁜놈
memset(pages, 0xcc, PGSIZE * page_cnt);
#endif
ASSERT(bitmap_all(pool->used_map, page_idx, page_cnt));
bitmap_set_multiple(pool->used_map, page_idx, page_cnt, false);
}
memset(pages, 0xcc, PGSIZE * page_cnt); 이부분때문에 물리메모리가 없어진다고 추측
해결방법
destroy를 지우자 !!!!!!
static void
process_cleanup(void)
{
struct thread *curr = thread_current();
#ifdef VM
supplemental_page_table_kill(&curr->spt);
#endif
uint64_t *pml4;
pml4 = curr->pml4;
if (pml4 != NULL)
{
curr->pml4 = NULL;
pml4_activate(NULL);
pml4_destroy(pml4);
}
}
===================================cow 수정 후=====================================
static void
process_cleanup(void)
{
struct thread *curr = thread_current();
#ifdef VM
supplemental_page_table_kill(&curr->spt);
// 추가
return;
#endif
uint64_t *pml4;
pml4 = curr->pml4;
if (pml4 != NULL)
{
curr->pml4 = NULL;
pml4_activate(NULL);
pml4_destroy(pml4);
return;
}
}
오늘도 열코!
반응형
'SW정글사관학교' 카테고리의 다른 글
[SW 정글] 5/22 ~ 25 WIL - (feat, pintOS) (3) | 2022.05.26 |
---|---|
[SW 정글] 5/21 PintOS - alarm (0) | 2022.05.21 |
[SW 정글] 5/20 운영체제 - 스케쥴 (0) | 2022.05.20 |
[SW 정글] 5/19 운영체제 - 프로세스, 스레드, 스케쥴러 (0) | 2022.05.20 |
[SW 정글] 5/14 TIL - what is HTTP? (0) | 2022.05.17 |