[TIL] [WEEK11-12] Pintos Project(3) Memory Mapped Files(2)

woo__j·2024년 8월 23일
0

Pintos Project

목록 보기
14/14

이번엔 Unmapping 관련 내용을 다뤄볼건데, 기본 내용은 이전 게시글과 같다.
그러니 munmap syscall & do_munmap에 관해서만 다루겠다.
그렇다 해도 unmapping 관련해서 수정/구현해야 할 내용이 훨씬 많다ㅎ...


munmap syscall

먼저 git book을 기반으로 한 내용들을 정리해보면 다음과 같다.

매핑을 해제할 때 고려해야 할 점이 있다.
만약 매핑이 진행된 후 수정사항이 있었다면 기존 파일에 수정사항을 반영해야 한다.
이 사실을 기억하고 있는 상태로 해당 파트를 진행해보겠다.

본격적으로 munmap syscall을 구현하려면 예전에 anon_page 관련 함수를 구현할 때도 슬쩍슬쩍 보였던 file_backed_page 관련 함수들을 먼저 구현해야 한다.


🛠️ file_backed_page 관련 함수 구현

위에서 작성한 것처럼 매핑을 해제할 때, 파일에 대한 수정사항이 있다면 기존 파일, 즉 disk의 파일에 수정사항을 기록해주어야 한다.
이를 위해선 파일에 대한 정보를 페이지가 갖고 있어야겠지?
그 후 수정사항을 기록한 이후 프로세스의 가상 페이지 목록에서 페이지를 제거함으로써 매핑을 해제하도록 한다.

근데 이 때, 페이지 구조체에 파일 정보를 담기 위해 file_page 구조체에 관련 멤버 변수 추가해주는 것을 잊지 말자!

1. file_page 구조체 멤버변수 추가

- include/vm/file.h

struct file_page {
 	struct file *file;
 	off_t ofs;
 	uint32_t read_bytes;
 	uint32_t zero_bytes;
 };

2. file_backed_initializer() 수정

수정사항을 파일에 기록하기 위해서는 매핑을 해제할 때 해당 페이지에 매핑된 파일에 대한 정보를 알아야 한다.
그러니 file_backed_page가 초기화될 때 파일에 대한 정보를 page 구조체에 추가해준다.

- vm/file.c

bool
 file_backed_initializer (struct page *page, enum vm_type type, void *kva) {
 	/* Set up the handler : page에 file_backed_page에 대한 핸들러 설정 */
 	page->operations = &file_ops;

 	struct file_page *file_page = &page->file;

 	/* 매핑을 해제할 때, 파일에 대한 수정사항을 기존 파일에 기록하기 위해 */
 	/* 파일에 대한 정보를 페이지에 저장해두어야 함*/

 	/* file_page에 파일에 대한 정보 추가 */
 	struct lazy_load_arg *lazy_load_arg = (struct lazy_load_arg *)page->uninit.aux;
 	file_page->file = lazy_load_arg->file;
 	file_page->ofs = lazy_load_arg->ofs;
 	file_page->read_bytes = lazy_load_arg->read_bytes;
 	file_page->zero_bytes = lazy_load_arg->zero_bytes;
 }

3. file_backed_destroy() 수정

프로세스가 종료될 때 매핑이 해제되어야 하므로 수정사항을 파일에 반영하고, 가상 페이지 목록에서 제거하기

- vm/file.c

static void
 file_backed_destroy (struct page *page) {
 	struct file_page *file_page UNUSED = &page->file;

 	/* 수정사항이 있었다면 file_write_at으로 반영하고 dirty를 0으로 수정 */
 	if (pml4_is_dirty(thread_current()->pml4, page->va))
 	{
 		file_write_at(file_page->file, page->va, file_page->read_bytes, file_page->ofs);
 		pml4_set_dirty(thread_current()->pml4, page->va, 0);
 	}

 	/* 가상페이지 목록에서 제거 */
 	pml4_clear_page(thread_current()->pml4, page->va);
 }

🛠️ syscall_handler() 수정

  • userprog/syscall.c
void syscall_handler(struct intr_frame *f)
{
	...
    case SYS_MUNMAP:
 		do_munmap(f->R.rdi);
 		break;
    ...
}

🛠️ do_munmap() 구현

같은 파일이 매핑된 여러 페이지들이 모두 해제될 수 있도록 매핑할 때 저장해둔 '매핑에 사용된 총 페이지 수'를 활용해 전부 해제하도록 한다.
page를 destroy함으로써 file_backed_destroy를 통해 파일의 수정사항을 기록하고 가상 페이지 목록에서 제거되도록 구현해야 한다.

void
 do_munmap (void *addr) {
 	struct supplemental_page_table *spt = &thread_current()->spt;
 	struct page *p = spt_find_page(spt, addr);
 	/* 같은 파일이 매핑된 페이지가 모두 해제되도록 총 매핑된 페이지 수를 가져와 전부 해제 */
 	/* destroy 호출로 file_backed_destroy에서 파일의 수정사항을 기록하고 가상 페이지 목록에서 해당 페이지가 제거되도록 함 */
 	int mapped_pages = p->mapped_page_cnt;

 	for (int i = 0; i < mapped_pages; i++)
 	{
 		if (p)
 		{
 			destroy(p);
 		}
 		addr += PGSIZE;
 		p = spt_find_page(spt, addr);
 	}
 }

여기서 추가로 supplemental_page_table_copy()를 수정해줘야 한다.


🛠️ supplemental_page_table_copy() 수정

page type이 VM_FILE(=file_backed_page)일 경우, 자식 페이지가 부모 프레임과 매핑될 수 있도록 분기점을 추가하도록 한다.

/* 자식 프로세스 생성할 때 spt 복사하는 함수 */
/* src를 dst에 복사 */
bool supplemental_page_table_copy(struct supplemental_page_table *dst UNUSED, struct supplemental_page_table *src UNUSED)
{
		...
 		/* page가 file_backed type이라면  */
 		if (type == VM_FILE)
 		{
 			struct lazy_load_arg *file_aux = malloc(sizeof(struct lazy_load_arg));
 			file_aux->file = src_page->file.file;
 			file_aux->ofs = src_page->file.ofs;
 			file_aux->read_bytes = src_page->file.read_bytes;
 			file_aux->zero_bytes = src_page->file.zero_bytes;

 			if (!vm_alloc_page_with_initializer(type, upage, writable, NULL, file_aux))
 			{
 				return false;
 			}

 			struct page *file_page = spt_find_page(dst, upage);
 			file_backed_initializer(file_page, type, NULL);
 			file_page->frame = src_page->frame;

 			pml4_set_page(thread_current()->pml4, file_page->va, src_page->frame->kva, src_page->writable);
 			continue;
 		}

 		/* page가 anon type이라면 */
 		...
}

이렇게 했을 때 나는 11/141 passed가 떴다.
pt-write-code2 tc가 통과되지 않았었는데, sys_read를 수정해서 10/141 passed로 이번 파트를 마무리 지었다.

이는 pt-write-code2를 pass하기 위해 수정한 목록이다.

1. in userprog/syscall.c

int read(int fd, void *buffer, unsigned size)
 {
 	/* read 시스템 콜은 파일에서 데이터를 읽어와 메모리 버퍼에 저장하는 함수인데 */
 	/* spt_find_page를 통해서 buffer 주소에 대한 page를 얻어왔을 때 */
 	/* 해당 페이지가 not writable한다면, 즉 buffer에 읽어온 데이터를 쓸 수 없다면, exit */
 	struct page *page = spt_find_page(&thread_current()->spt, buffer);
 	if (page){
 		if (!page->writable) {
 			exit(-1);
 		}
 	}

 	if (!is_user_vaddr(buffer) || buffer == NULL){
 		exit(-1);
 	}
    ...   
}

void check_address(void *addr)
 {
 	struct thread *current = thread_current();

 	if (addr == NULL || is_kernel_vaddr(addr) || pml4_get_page(current->pml4, addr) == NULL)
 		exit(-1);
 }

2. in vm/vm.c

void vm_init(void)
{
	...
    // list_init(&frame_table);
 	// lock_init(&frame_table_lock);
}

vm_get_frame(void)
{
	...
    // lock_acquire(&frame_table_lock);
 	// list_push_back(&frame_table, &frame->frame_elem);
 	// lock_release(&frame_table_lock);
    ...
}

해당 부분까지 수정하게 되면 10/141 passed가 뜬다.
이렇게 하면 memory mapped files 파트도 끝이 난다.

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
pass tests/vm/mmap-read
pass tests/vm/mmap-close
pass tests/vm/mmap-unmap
pass tests/vm/mmap-overlap
pass tests/vm/mmap-twice
pass tests/vm/mmap-write
pass tests/vm/mmap-ro
pass tests/vm/mmap-exit
pass tests/vm/mmap-shuffle
pass tests/vm/mmap-bad-fd
pass tests/vm/mmap-clean
pass tests/vm/mmap-inherit
pass tests/vm/mmap-misalign
pass tests/vm/mmap-null
pass tests/vm/mmap-over-code
pass tests/vm/mmap-over-data
pass tests/vm/mmap-over-stk
pass tests/vm/mmap-remove
pass tests/vm/mmap-zero
pass tests/vm/mmap-bad-fd2
pass tests/vm/mmap-bad-fd3
pass tests/vm/mmap-zero-len
pass tests/vm/mmap-off
pass tests/vm/mmap-bad-off
pass tests/vm/mmap-kernel
pass tests/vm/lazy-file
pass tests/vm/lazy-anon
FAIL tests/vm/swap-file
FAIL tests/vm/swap-anon
FAIL tests/vm/swap-iter
FAIL 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
FAIL tests/filesys/base/syn-read
pass tests/filesys/base/syn-remove
FAIL 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
10 of 141 tests failed.

0개의 댓글

관련 채용 정보