! 오늘의 결과
! 오늘의 알게된 점
페이지와 물리메모리의 맵핑을 끊어줘야 한다는 것을 나는 page->frame에 대한 가시적인 처리를 하라는 얘기로 생각했다. 그래서 page->frame = NULL로 끊어줘보기도 했는데 계속 page->frame의 접근이 page fault가 발생했었다. 알고보니 직접적인 처리가 아니라 pml4_clear_page()를 통해 해당 페이지의 참조 비트와 물리 주소와의 관계를 clear 시키라는 얘기였다...아직 이해가 덜 되었나보다.
! 오늘의 실수 (트러블 슈팅)
1. reopen한 파일을 써야하는데 reopen 해놓고 기존 파일을 사용하고 있었다. 또 멍청이슈...
file.c의 do_mmap()에서는 process.c의 lode_segment와 거의 같은 흐름을 가져왔다.
lode_segment()과 다른 점은 anonymous가 아닌 file_backed 페이지로 할당한다는 점.
if (!vm_alloc_page_with_initializer(VM_FILE, addr, writable, lazy_load_segment, nec))
return NULL;
이때 보조 데이터로 사용하는 nec (우리는 necessary_info로 만들었다.)에 정보를 갱신해주는 과정에서 실수가 있었다.
파일을 열고 그에 대한 정보를 가져올 때, 기존의 파일을 가져다 작업을 하면 안 된다.
기존 파일은 외부에서 open된 파일이기 때문에 외부에서 닫힐 가능성이 있다. 이를 방지하기 위해 우리는 file_reopen()을 사용했다.
문제는 reopen()을 해놓고 새로 open한 파일이 아니라 기존의 파일을 사용하고 있었다...이것 때문에 mmap 테스트 케이스의 절반 가까이 통과가 되지 않았다. 왜 안 되는지 코드를 살펴보다가 reopen한 파일을 사용하지 않는 것을 발견하고 수정했다!
2. syscall.c에 있는 write()에 작성했던 버퍼의 쓰기 권한에 대한 exit()문을 삭제했다.
if (p && !p->writable)
exit(-1);
read할 버퍼의 쓰기 권한을 체크했기 때문에 write도 해줘야한다고 생각했는데 아니었다...
방금 쓰면서 깨달았다. write()에서 인자로 들어오는 buffer는 이 버퍼에 write를 하는게 아니라 버퍼에 쓰여 있는 데이터를 read만 하기 때문에 쓰기 권한을 체크할 필요가 없으며, 오히려 read-only일 때 내쫓아버리는 것이였다.
그렇다면 파일에 대한 쓰기 권한은 체크해야 하지 않을까? 하는 의문에 아래 코드를 추가했고, 테스트 케이스는 무사히 통과했다.
if (write_fd->file && write_fd->file->deny_write)
exit(-1);
3. hash_destroy() 함수를 process_exit()에 추가 & process_cleanup() 위치 변경
기존에는 hash table 전체를 삭제하는 코드가 없었고, process_cleanup() 을 exit 가장 마지막 순서로 두었다.
이때 mmap-exit 케이스가 통과하지 못 했다.
// 기존
file_close(t->running);
sema_up(&t->wait_sema);
sema_down(&t->exit_sema);
process_cleanup();
// 변경
file_close(t->running);
process_cleanup();
hash_destroy(&t->spt.hash_table,NULL);
sema_up(&t->wait_sema);
sema_down(&t->exit_sema);
hash_destroy()를 해야 전체적인 메모리 누수가 없을 것이라고 판단했고, 완전한 종료가 될 수 있다고 생각했다.
process_cleanup()에서 spt_kill에 대한 함수를 호출하며 hash에 접근하기 때문에 hash_destroy() 호출을 process_cleanup() 이후로 정했다.
이후 mmap-exit를 통과했다.
4. hash func 변경
우리는 swap table을 hash를 이용해서 구현했다. hash를 구현할 때는 hash_func이 두 개 필요한데, 처음에는 이전에 spt 테이블을 구현할 때 사용했던 함수를 조금만 수정해서 사용했었다.
↓ 변경 전 코드, slot에 저장하는 page->va를 사용했다. 기존에도 va를 사용했기 때문에...같은 정보를 활용했다.
unsigned anon_page_hash(const struct hash_elem *p_, void *aux UNUSED)
{
const struct slot *p = hash_entry(p_, struct slot, swap_elem);
return hash_bytes(&p->page->va, sizeof p->page->va);
}
위 코드를 사용하면 vm_anon_init -> hash_insert에서 TIMEOUT이 발생한다...
문제
우리는 init할 때 삽입하는 slot에 page를 NULL로 초기화했다. 그러다보니 hash_func에서 사용할 page가 존재하지 않았던 것.
↓ 변경 후 코드
unsigned anon_page_hash(const struct hash_elem *p_, void *aux UNUSED)
{
const struct slot *p = hash_entry(p_, struct slot, swap_elem);
return hash_bytes(&p->index, sizeof p->index);
}
함수에서 사용할 정보를 slot의 index로 변경해주어 통과했다!
각 slot의 index는 처음 할당된 이후에 변경되지 않으므로 사용하기 적절하다고 판단했다.
! 오늘 한 일
- 어제 마무리하지 못한 mmap 케이스를 모두 마무리
- swap in/out에 대한 함수 작성 - anon에 대한 함수만 작성
- swap을 위해 FIFO와 Clock 알고리즘 작성 - 두 알고리즘 모두 통과하나 Clock 알고리즘이 눈에 띄게 빠름
많지 않아보이지만 무려 테스트 케이스 14개 -> 2개를 만들었다. mmap은 구현보다는 오류 찾기 및 수정에 가깝지만 꽤 많은 내용을 수정해야 했고, swap 시스템은 처음부터 구현했기 때문에 Disk와 섹션 등에 대한 이해부터 해야했다.
그래도 왜 섹션을 저렇게 (8개로 나누어서 등등) 사용해야 하는지 이해했다. 굿~
내일은 남은 file_backed에 대한 swap과 WIL 작성, 시간이 된다면 extra인 cow까지 구현해볼 예정이다. 핀토스도 거의 다 왔다 파이팅
'TIL (Today I Learned)' 카테고리의 다른 글
4/10-4/14 WIL - 왜 나만 안 돼 JWT (0) | 2024.04.14 |
---|---|
4/3 (수) TIL - PintOs Project 3 마무리 (0) | 2024.04.03 |
4/1 (월) 오늘의 TIL - Stack glowth 성공 (0) | 2024.04.02 |
3/29 (금) TIL - fork 테스트케이스까지 모두 통과! (0) | 2024.03.30 |
3/28 (목) TIL - Project3 Anonymous Page 구현하기 (2) | 2024.03.29 |