seven05
[PintOS] 정글 WEEK09 WIL. PROJECT 3: VIRTUAL MEMORY 본문
기간: 2024.10.08~2024.10.14
project2에서는 가장 기본적인 기능만 만들어져있는 가상메모리 시스템을 사용하다가 이번 프로젝트에 들어와서 가상메모리를 직접 만들게되었다. 일단 지금 mmap까지는 구현을 했고 munmap에서 문제가 생겨서 디버깅 중이였는데 WIL을 써야하는 시간이 되었기에 일단 멈추고 작성하게 되었다. 지금까지 진행하면서 겪은 문제와 나의 해결방법을 적어보려한다.
1. 페이지 폴트 핸들러가 참조해서 사용하는 spt를 만드는것이 과제의 시작이고 핸들러의 대부분의 함수들이 여기서 이 spt를 통해서 page를 찾아가야하는데 계속 spt를 통해서 va값이 일치하는 page를 찾아야 하는 부분에서 hash_find함수가 NULL을 뱉었다. 도저히 이유를 알수없었는데 범인은 va를 그대로 찾는것이였다. 넘겨받은 va를 pg_round_down을 해줘야했는데 pg_round_down은 하위 12비트를 모두 0으로 만들어주는 함수이다. 가상주소의 구조를 보면 하위 12비트는 offset인데 offset이 포함된 va로 page를 찾으려고하면 page 구조체에 들어있는 va값은 offset값이 모두 0인 상태이므로 찾을수없었던것이다.
struct page *
spt_find_page (struct supplemental_page_table *spt UNUSED, void *va UNUSED) {
/* TODO: Fill this function. */
struct page page;
page.va = pg_round_down(va);
struct hash_elem *e = hash_find(&spt->spt_hash, &page.elem);
if (e) {
return hash_entry(e, struct page, elem);
} else {
return NULL;
}
}
2. process.c에 있는 load_segment와 lazy_load_segment를 구현할때 문제가 생겼는데,일단 load_segment는 처음에 우리가 실행프로그램을 동작시킬때 process_exec가 실행되고 그안의 load부분을 거쳐서 ELF해더를 읽는부분에서 LOAD를 만나면 실행된다. 여기서 load_segment가 실행파일을 디스크에서 읽어들여 메모리에 적재하는 부분이라고 이해하였는데 문제는 메모리에 적재하기 위해서 페이지를 할당받는 vm_alloc_page_with_initializer를 호출할때 아래과 같이 VM_ANON
vm_alloc_page_with_initializer (VM_ANON, upage,writable, lazy_load_segment, container)
타입으로 페이지를 요청한다는것이였다. 처음에 이걸 접했을때는 실행파일도 파일이니깐 file_backed 여야 하는것 아닌가 생각이 들었고, 도무지 이해가 안되었다. 그러다가 생각해보니 내가 컴퓨터에서 파워포인트 프로그램을 실행해서 쓴다고 생각했을때 파워포인트 안에서 여는 파일들은 내가 수정할수있지만 파워포인트 실행파일 자체를 수정하면 안된다고 느껴졌다. 그렇게 대략적으로만 이해하고 넘어갔는데 질문채널에 나와같은 의문을 가진 친구(선미 굿)가 아주좋은 질문을 올려서 더 깔끔하게 이해할수있었다.
readelf -Wl 명령어를 통해서 elf 해더를 직접 확인할수있는데, 우리가 실행하는 실행파일에는 read-only인 데이터들이 LOAD section안에 존재하는것을 확인할수있다. 저런 데이터들을 우리가 접근해서 바꾸면 안되기때문에 file을 변경시킬수있는 VM_FILE 타입말고 VM_ANON을 쓰는것이였다. 여기서 더 나아가서 ro인 데이터들을 읽기만 할때는 fork를 할때 굳이 메모리를 더 쓰는 행동을 할필요가없기때문에 write가 발생하려고 할때만 해주는 copy-on-write가 필요한 이유도 엿볼수있었다.
3. Pintos의 테스트 코드를 맹신하지말자!
이번 과제를 하면서 제일 많은 시간을 쓴 이슈였지만 가장 인상적인 문제이기도했다. mmap을 다 구현하고 테스트 코드를 돌렸을때 make check를 통해서 pass fail를 보고있었는데 구현 하지도 않은 mmap-unmap이 통과가 되기에 이상함을 느껴서 테스트코드를 살펴보았는데...
CHECK ((handle = open ("sample.txt")) > 1, "open \"sample.txt\"");
CHECK ((map = mmap (ACTUAL, 0x2000, 0, handle, 0)) != MAP_FAILED, "mmap \"sample.txt\"");
msg ("memory is readable %d", *(int *) ACTUAL);
msg ("memory is readable %d", *(int *) ACTUAL + 0x1000);
munmap (map);
fail ("unmapped memory is readable (%d)", *(int *) (ACTUAL + 0x1000));
fail ("unmapped memory is readable (%d)", *(int *) (ACTUAL));
내가 생각한 테스트 코드의 의도는 sample.txt 라는 파일을 2page 크기로 할당하고 첫번째 페이지와 두번째 페이지의 시작주소로 접근해서 유효하게 할당했는지 체크하고 unmap을 진행한뒤에 다시 접근가능한지 확인해서 unmap이 정상적으로 이루어졌는지 확인하는 의도로 보였다. 하지만 mmap을 확인하는 부분과 unmap을 확인하는부분에서 ACTUAL+0x1000 부분이 괄호가 있고 없고로 일관성이 없게 작성되어있었다. 둘중 하나는 주소가 잘못 접근하고 있다는 생각이 들었고 주소값을 직접 찍어보니 위부분이 괄호가 필요하다는것을 알수있었다. 위에 괄호를 씌우고 나니 그제서야 fail이 올바르게 떳고 우리가 작성한 코드가 잘못된것도 알수있어서 열심히 디버깅을 진행했다. 그렇게 코드를 다 고치고 나서 테스트를 돌리는데 계속 fail이 뜨기에 이유를 알수없었는데..
pintos -v -k -T 60 -m 20 --fs-disk=10 -p tests/vm/mmap-unmap:mmap-unmap -p ../../tests/vm/sample.txt:sample.txt --swap-disk=4 -- -q -f run mmap-unmap < /dev/null 2> test
perl -I../.. ../../tests/vm/mmap-unmap.ck tests/vm/mmap-unmap tests/vm/mmap-unmap.result
FAIL tests/vm/mmap-unmap
Test output failed to match any acceptable form.
Acceptable output:
(mmap-unmap) begin
(mmap-unmap) open "sample.txt"
(mmap-unmap) mmap "sample.txt"
(mmap-unmap) memory is readable 540884285
(mmap-unmap) memory is readable 540888381
mmap-unmap: exit(-1)
Differences in `diff -u' format:
(mmap-unmap) begin
(mmap-unmap) open "sample.txt"
(mmap-unmap) mmap "sample.txt"
(mmap-unmap) memory is readable 540884285
- (mmap-unmap) memory is readable 540888381
+ (mmap-unmap) memory is readable 0
mmap-unmap: exit(-1)
make 테스트를 통한 결과 페이지가 이렇게 출력되기에 이상해서 왜 unmap이 아니라 할당된 페이지에 접근하는것을 확인 하는 부분에서 문제가 터지는것일까라는 생각이 들었고 2번째 할당된 페이지에 들어있는 데이터가 0이라는 부분이 이상해서 sample.txt를 확인해보게되었다. sample.txt는 794바이트짜리 텍스트파일이였고 이는 1페이지 크기만으로도 할당이 끝나서 2번째 페이지에는 0만이 있을수밖에없었던것이다. 결국 make를 통한 테스트는 mmap-unmap.ck 파일에 찍혀있는 출력값과 같은지를 확인하는 방식인데, 애초에 테스트 코드가 잘못되어있는 상태에서 그 결과를 기록해둔 ck 파일로 테스트 출력값을 검증하니 틀릴수밖에 없었던것이다. 결국 조교님한테 질문을 드려보니 테스트 코드의 문제와 ck파일의 문제임을 확인 받을수있었고 mmap-unmap 테스트를 올바르게 고치고 진행할수있었다.
'SW JUNGLE 9기 > Pintos' 카테고리의 다른 글
[PintOS] 정글 WEEK10 WIL. PROJECT 3: VIRTUAL MEMORY + PROJECT 4: FILE SYSTEM (0) | 2024.10.21 |
---|---|
[PintOS] 정글 WEEK08 WIL. PROJECT 2: USERPROGRAM (1) | 2024.10.07 |
[PintOS] 정글 WEEK07 WIL. PROJECT 1 : THREADS (0) | 2024.10.01 |