fork‐read.c 테스트 오류 - sihyun10/pintos-lab-vm GitHub Wiki
fork-read.c
테스트 코드 Fail
해결
이 테스트의 핵심은
부모가 open
한 파일을, fork
로 생성된 자식이 동일한 fd
로 이어서 읽을 수 있는가?이다.
- 자식은
fork
이후에도handle
을 가지고 있고 - 자식이 해당
fd
로read()
를 수행하는 것 read()
가 제대로 동작하고, 부모와 자식이 동일한 파일을 독립적으로 공유할 수 있어야 테스트가 통과된다.
supplemental_page_table_copy()
함수 수정
supplemental_page_table_copy()
함수는 __do_fork()
에서 호출된다.
static void
__do_fork(void *aux)
{
/* ... */
#ifdef VM
supplemental_page_table_init(¤t->spt);
if (!supplemental_page_table_copy(¤t->spt, &parent->spt))
goto error;
supplemental_page_table_copy()
함수는 부모의 spt
를 자식에게 복사하려는 것이다.
bool supplemental_page_table_copy(struct supplemental_page_table *dst UNUSED,
struct supplemental_page_table *src UNUSED)
{
struct hash_iterator i;
hash_first(&i, &src->spt_hash);
while (hash_next(&i))
{
struct page *src_page = hash_entry(hash_cur(&i), struct page, hash_elem);
enum vm_type type = src_page->operations->type;
void *upage = src_page->va;
bool writable = src_page->writable;
if (type == VM_UNINIT)
{
vm_initializer *init = src_page->uninit.init;
void *aux_copy = src_page->uninit.aux;
if (!vm_alloc_page_with_initializer(src_page->uninit.type, upage, writable, init, aux_copy))
return false;
}
else
{
if (!vm_alloc_page_with_initializer(src_page->operations->type, upage, writable, NULL, NULL))
return false;
if (!vm_claim_page(upage))
return false;
struct page *page = spt_find_page(dst, upage);
memcpy(page->frame->kva, src_page->frame->kva, PGSIZE);
}
}
return true;
}
부모 프로세스의 메모리는 두 가지 타입으로 나뉘어져 있다.
페이지 타입 | 의미 |
---|---|
VM_UNINIT |
아직 실제 물리 메모리를 할당받지 않은 lazy loading 상태의 페이지 |
그 외 | 실제로 메모리에 올라간 페이지들 |
따라서 복사 방식이 다르다.
VM_UNINIT
인 경우
1) 아직 물리 메모리를 할당받지 않은 lazy loading 상태의 페이지이다.
페이지 접근 전까지는 메모리를 할당하면 안되므로,
부모 페이지의 init
, aux
만 그대로 복사한다.
즉, 페이지 접근 전까지 메모리 할당을 미루기 위해 lazy loading
상태 그대로 복사한다.
if (type == VM_UNINIT) {
vm_initializer *init = src_page->uninit.init;
void *aux_copy = src_page->uninit.aux;
if (!vm_alloc_page_with_initializer(src_page->uninit.type, upage, writable, init, aux_copy))
return false;
}
2) 이미 메모리에 올라온 경우
else
{
if (!vm_alloc_page_with_initializer(src_page->operations->type, upage, writable, NULL, NULL))
return false;
if (!vm_claim_page(upage))
return false;
struct page *page = spt_find_page(dst, upage);
memcpy(page->frame->kva, src_page->frame->kva, PGSIZE);
}
이미 부모에서 물리 메모리 할당되어있다면, 자식도 페이지를 만들고 claim
한 후에
frame
내용을 그대로 복사(memcpy
)해야 한다.
왜 이렇게 해야 할까?
- 복사해서 독립적인 메모리를 확보해야함
- 부모와 자식이 같은 주소 공간을 갖지만, 독립적인 프레임을 가져야한다.
Lazy Loading
유지VM_UNINIT
페이지는 복사해서 즉시 물리 메모리를 할당하지 않는다.- 여전히
page fault
시점에 로딩 될 수 있도록 해야한다.
aux
를 free
하면 안된다!!!!
주의점 - | userprog/process.c
파일에서의 lazy_load_segment()
함수
static bool
lazy_load_segment(struct page *page, void *aux)
{
/* TODO: Load the segment from the file */
/* TODO: This called when the first page fault occurs on address VA. */
/* TODO: VA is available when calling this function. */
struct load_info *info = (struct load_info *)aux;
struct file *file = info->file;
off_t ofs = info->ofs;
size_t page_read_bytes = info->read_bytes;
size_t page_zero_bytes = info->zero_bytes;
// 실제 프레임의 커널 가상 주소 얻기
uint8_t *kva = page->frame->kva;
// 파일에서 필요한 만큼 읽기
if (file_read_at(file, kva, page_read_bytes, ofs) != (int)page_read_bytes)
{
free(info);
return false;
}
// 남은 영역은 0으로 채우기
memset(kva + page_read_bytes, 0, page_zero_bytes);
// free(info); ➔ 이렇게 해주면 안된다!!
return true;
}
free(info)
를 해주면 안되는걸까?
Q. 왜 아직 해당 페이지가 접근되지 않아서, lazy_load_segment()
실행 시, 정보가 필요하다.
실제로 페이지에 접근해서 lazy_load_segment()
가 성공할 때까지 필요하다.
상황 : 부모, 자식이 레고를 맞추고있는 중
- 부모 프로세스는 레고를 맞추려고 레고 설명서(
aux
) 를 들고 있다.
설명서에는 어떻게 레고를 조립하고, 어떤 레고를 사용하는지 적혀있다. - 그런데 부모가 "어렵다. 나중에 조립하자~"하고
레고 상자만 냅두고 간거야. (lazy loading
상태) - 그리고 자식 프로세스가 생겼고, 자식도 똑같이 레고를 조립하려면
레고 설명서(aux
) 를 복사해서 가져가야한다.
하지만, 부모가 레고를 조립하기 전에 설명서를 찢어서 버렸다면?
- 자식은 레고를 조립할 때 설명서가 없으니까 어떻게 조립할지 모른다.
- 그래서 자식이 레고를 조립하려고 시도하다가 실패(프로세스 종료)를 해버린다.
따라서 테스트가 실패했었던 것이다.
해결한 후에 테스트 결과는 33 of 141 tests failed
로 줄어들었다.
pass tests/userprog/args-none
pass tests/userprog/args-single
pass tests/userprog/args-multiple
pass tests/userprog/args-many
pass tests/userprog/args-dbl-space
pass tests/userprog/halt
pass tests/userprog/exit
pass tests/userprog/create-normal
pass tests/userprog/create-empty
pass tests/userprog/create-null
pass tests/userprog/create-bad-ptr
pass tests/userprog/create-long
pass tests/userprog/create-exists
pass tests/userprog/create-bound
pass tests/userprog/open-normal
pass tests/userprog/open-missing
pass tests/userprog/open-boundary
pass tests/userprog/open-empty
pass tests/userprog/open-null
pass tests/userprog/open-bad-ptr
pass tests/userprog/open-twice
pass tests/userprog/close-normal
pass tests/userprog/close-twice
pass tests/userprog/close-bad-fd
pass tests/userprog/read-normal
pass tests/userprog/read-bad-ptr
pass tests/userprog/read-boundary
pass tests/userprog/read-zero
pass tests/userprog/read-stdout
pass tests/userprog/read-bad-fd
pass tests/userprog/write-normal
pass tests/userprog/write-bad-ptr
pass tests/userprog/write-boundary
pass tests/userprog/write-zero
pass tests/userprog/write-stdin
pass tests/userprog/write-bad-fd
pass tests/userprog/fork-once
pass tests/userprog/fork-multiple
pass tests/userprog/fork-recursive
pass tests/userprog/fork-read
pass tests/userprog/fork-close
pass tests/userprog/fork-boundary
pass tests/userprog/exec-once
pass tests/userprog/exec-arg
pass tests/userprog/exec-boundary
pass tests/userprog/exec-missing
pass tests/userprog/exec-bad-ptr
pass tests/userprog/exec-read
pass tests/userprog/wait-simple
pass tests/userprog/wait-twice
pass tests/userprog/wait-killed
pass tests/userprog/wait-bad-pid
pass tests/userprog/multi-recurse
pass tests/userprog/multi-child-fd
pass tests/userprog/rox-simple
pass tests/userprog/rox-child
pass tests/userprog/rox-multichild
pass tests/userprog/bad-read
pass tests/userprog/bad-write
pass tests/userprog/bad-read2
pass tests/userprog/bad-write2
pass tests/userprog/bad-jump
pass tests/userprog/bad-jump2
pass tests/vm/pt-grow-stack
pass tests/vm/pt-grow-bad
pass tests/vm/pt-big-stk-obj
pass tests/vm/pt-bad-addr
pass tests/vm/pt-bad-read
pass tests/vm/pt-write-code
pass tests/vm/pt-write-code2
pass tests/vm/pt-grow-stk-sc
pass tests/vm/page-linear
pass tests/vm/page-parallel
pass tests/vm/page-merge-seq
FAIL tests/vm/page-merge-par
FAIL tests/vm/page-merge-stk
FAIL tests/vm/page-merge-mm
pass tests/vm/page-shuffle
FAIL tests/vm/mmap-read
FAIL tests/vm/mmap-close
FAIL tests/vm/mmap-unmap
FAIL tests/vm/mmap-overlap
FAIL tests/vm/mmap-twice
FAIL tests/vm/mmap-write
FAIL tests/vm/mmap-ro
FAIL tests/vm/mmap-exit
FAIL tests/vm/mmap-shuffle
FAIL tests/vm/mmap-bad-fd
FAIL tests/vm/mmap-clean
FAIL tests/vm/mmap-inherit
FAIL tests/vm/mmap-misalign
FAIL tests/vm/mmap-null
FAIL tests/vm/mmap-over-code
FAIL tests/vm/mmap-over-data
FAIL tests/vm/mmap-over-stk
FAIL tests/vm/mmap-remove
FAIL tests/vm/mmap-zero
FAIL tests/vm/mmap-bad-fd2
FAIL tests/vm/mmap-bad-fd3
FAIL tests/vm/mmap-zero-len
FAIL tests/vm/mmap-off
FAIL tests/vm/mmap-bad-off
FAIL tests/vm/mmap-kernel
FAIL tests/vm/lazy-file
pass tests/vm/lazy-anon
FAIL tests/vm/swap-file
FAIL tests/vm/swap-anon
FAIL tests/vm/swap-iter
pass tests/vm/swap-fork
pass tests/filesys/base/lg-create
pass tests/filesys/base/lg-full
pass tests/filesys/base/lg-random
pass tests/filesys/base/lg-seq-block
pass tests/filesys/base/lg-seq-random
pass tests/filesys/base/sm-create
pass tests/filesys/base/sm-full
pass tests/filesys/base/sm-random
pass tests/filesys/base/sm-seq-block
pass tests/filesys/base/sm-seq-random
pass tests/filesys/base/syn-read
pass tests/filesys/base/syn-remove
pass tests/filesys/base/syn-write
pass tests/threads/alarm-single
pass tests/threads/alarm-multiple
pass tests/threads/alarm-simultaneous
pass tests/threads/alarm-priority
pass tests/threads/alarm-zero
pass tests/threads/alarm-negative
pass tests/threads/priority-change
pass tests/threads/priority-donate-one
pass tests/threads/priority-donate-multiple
pass tests/threads/priority-donate-multiple2
pass tests/threads/priority-donate-nest
pass tests/threads/priority-donate-sema
pass tests/threads/priority-donate-lower
pass tests/threads/priority-fifo
pass tests/threads/priority-preempt
pass tests/threads/priority-sema
pass tests/threads/priority-condvar
pass tests/threads/priority-donate-chain
FAIL tests/vm/cow/cow-simple
33 of 141 tests failed.
../../tests/Make.tests:28: recipe for target 'check' failed
make: *** [check] Error 1