정글에서 온 개발자

정글 pintOS project3 - mmap. file_reopen 잡아주기 본문

TIL

정글 pintOS project3 - mmap. file_reopen 잡아주기

dev-diver 2023. 12. 26. 10:42

기존 mmap 코드

void *
do_mmap (void *addr, size_t length, int writable,
		int fd, off_t ofs) {
	
    //에러 처리
	void *va = pg_round_down(addr);
	if(length == 0 || addr == 0 || va != addr 
		|| fd == 0 || fd == 1){
		return NULL;
	}

	struct file *file = thread_current()->fdt[fd]; //이 부분
	off_t read_bytes = file_length(file);

	if(read_bytes <= 0 || read_bytes - ofs <= 0){
		return NULL;
	}
	read_bytes-=ofs;
    
   //가상주소가 잡혀있는 페이지인지 확인
	int pages = read_bytes % PGSIZE +1 ;
	for(int i = 0; i < pages; i++){
		if(spt_find_page(&thread_current()->spt, va + i*PGSIZE) != NULL){
			return NULL;
		}
	}

	//페이지들에 맵핑(lazy load)
	while (read_bytes > 0) {
		/* Do calculate how to fill this page.
		 * We will read PAGE_READ_BYTES bytes from FILE
		 * and zero the final PAGE_ZERO_BYTES bytes. */
		size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
		size_t page_zero_bytes = PGSIZE - page_read_bytes;

		/* TODO: Set up aux to pass information to the lazy_load_segment. */
		struct seg_arg *args = calloc(1, sizeof(struct seg_arg));
		if(args == NULL){
			PANIC("Memory allocation failed\n");
			return false;
		}

		args->file = file;
		args->ofs = ofs;
		args->page_read_bytes = page_read_bytes;
		args->page_zero_bytes = page_zero_bytes;
		args->total_page = pages;  //munmap을 위해 카운트
		void *aux = args;
		if(!vm_alloc_page_with_initializer(VM_FILE, va, writable, lazy_load, aux)){
			exit(-1);
		}

		read_bytes -= page_read_bytes;
		va += PGSIZE;
		ofs += page_read_bytes;
	}
	return addr;
}
  • 깃북에 나온 각종 에러처리를 한다.
  • 기존에 잡혀있는 페이지들인지 supplement_page_table을 검사해 확인한다.
  • 기존  load_segment 함수를 참고하여 lazy_load하도록 로직을 짰다.

기존 결과

  • mmap-read 테스트는 잘 통과한다.
  • mmap-close 는 통과하지 못한다.

원인 분석

  • 위 파일을 가져오는 부분 코드에 따르면 ,mmap한 주소에는 fd가 가리키고 있는 파일이 맵핑되어있다.
  • mmap명령어를 쓰더라도, lazy load이기 때문에 아직 해당 페이지가 있는 물리주소에는 파일의 내용이 써있지 않은 상태다.
  • lazy load가 되기 전에 file close를 해버리면,  추후 lazy load시 참고해야할 file이 사라져 버린다.
  • 그래서 memcmp시,  비교를 하려고 lazy load를 하면 읽을 file이 없어 exit(-1) 한다.

해결 방법

  • 깃북 munmap 파트에 file_reopen을 활용하라고 써 있다.

Closing or removing a file does not unmap any of its mappings. Once created, a mapping is valid until munmap is called or the process exits, following the Unix convention. See Removing an Open File for more information. You should use the file_reopen function to obtain a separate and independent reference to the file for each of its mappings.

  • 코드를 다음과 같이 바꾸면 패스한다.
//에러처리
void *va = pg_round_down(addr);
if(length == 0 || addr == 0 || va != addr 
    || fd == 0 || fd == 1){
    return NULL;
}

struct file *file = file_reopen(thread_current()->fdt[fd]); //close해도 file 살아있게
off_t read_bytes = file_length(file);

if(read_bytes <= 0 || read_bytes - ofs <= 0){
    return NULL;
}
read_bytes-=ofs;