본문 바로가기

SW정글사관학교

[SW 정글] 6/7 ~ 21 WIL - (feat, pintOS VM - all pass)

반응형

 

ALL PASS !!!

 

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;
    }
}

 

 

 

 

 

 

 


 

좋은 건 다시 한번

오늘도 열코!

반응형