[Pintos] Project 3 - (4) Memory Mapped Files

해롱그·2023년 10월 23일
1

OS

목록 보기
12/12

왜 메모리 매핑을 할까?

우리는 디스크에 영구적으로 저장해놓은 데이터를 사용할 때 디스크에서 직접 작업하지 않는다.

왜일까?

파일 I/O 등의 작업을 디스크에서 직접 처리하면 일단 너무 느리다. 따라서 우리는 RAM과 같은 메인 메모리에 올린 후 매핑해서 사용하면 작업을 좀 더 빠르게 처리할 수 있다.

  • 그 외 다른 이유

이렇게 데이터를 사용하게 되면 고려해야 할 사항이 생긴다.

anonymous page 같은 경우 각 프로세스는 자신만의 독립적인 익명 메모리 공간을 가지며, 이 영역은 프로세스 간에 공유되지 않는다.

fild backed page는 주로 디스크에 저장된 파일의 내용을 매핑하므로 여러 프로세스가 하나의 파일 메모리 매핑을 공유할 수 있기에 동시에 읽고 쓰는 것이 가능하다.
파일 메모리를 수정하면 변경 사항이 원본 파일에도 적용되어야 한다. 따라서 여러 프로세스가 동시에 파일 메모리를 수정하면 모든 변경 사항이 동기화 되어야 한다.


mmap() 함수

void *mmap(void *addr, size_t length, int writable, int fd, off_t offset);

fd값에 있는 파일을 offset부터 length 까지 써준 후 남은 페이지를 0으로 채워준다.
하지만 우리는

이처럼 palloc을 받을 때 PAL_ZERO를 사용하여 0으로 초기화 된 페이지를 할당 받을 것이기 때문에 파일에 내용만 써주었다.

mmap을 system call로 호출하는데 위와 같은 예외처리를 해주었다.
addr과 offset이 page-aligned 인지 체크해주었다.
그리고 length의 타입이 size_t로 되어있는데 이는 unsigned long이라서 길이가 음수로 들어올 때 어마무시하게 큰 수로 입력 받아지는 것을 확인했다.
그래서 long으로 형변환을 해준 뒤 예외처리를 하니 이상한 length를 처리할 수 있었다.

예외처리를 무사히 넘기면 do_mmap 함수를 호출한다.

do_mmap() 함수

do_mmap 함수는 시스템 콜(mmap)에서 fd에 해당하는 파일을 찾아서 넘겨주기 때문에 인자로 fd 대신 file을 받는다.

매핑 과정에서 해당 파일이 닫힐 수 있기 때문에 안전하게 매핑이 완료될 수 있도록 mmap이 사용할 파일을 reopen 해주어야 한다.
나중에 파일이 매핑된 시작 주소를 반환해야하므로 origin_addr을 저장해주었다.
그리고 이 파일에 해당하는 페이지가 얼마나 연속되어있는지 알기 위해 인자로 받은 총 length (origin_length)를 따로 저장하여 페이지 수 (page_cnt)를 계산해주었다.

munmap 할 때 page_cnt 만큼 페이지를 찾아야하므로 꼭 필요!

우리는 lazy_loading을 구현해야하므로 실제 file을 읽을 때 필요한 정보를 load_segment의 aux와 같은 buffer에 담아준 후, vm_alloc_page_with_initializer() 를 호출한다.
이 때, FILE 페이지 타입에 맞는 초기화 함수인 lazy_load_file()을 만들어 파일을 읽을 수 있도록 했다.

lazy_load_file() 함수

받아온 buffer(aux) 에서 실제 파일의 정보를 꺼내 file_read_at()을 통해 kva에 내용을 기록한다.

munmap을 할 때, 파일이 수정되었을 경우 디스크에 반영해줘야 하므로 해당 페이지에 파일에 대한 정보를 저장해둔다.

이 과정이 완료되면 aux는 본인의 역할을 다 했으므로 free .. 메모리를 해제해준다.


do_munmap() 함수

mummap은 연결된 물리 프레임과의 연결을 끊어주는 함수로, mmap의 반대 함수로 생각하면 쉬울 것 같다.
mmap에서 메모리에 파일을 매핑한 후, 해당 페이지에 수정사항이 있을 경우 그 내용을 디스크에 있는 파일에 반영해줘야 한다.

dirty bit가 1이면 file_write_at()을 통해 디스크의 file에 write 해준다.
정석대로라면 pml4_set_dirty()를 사용해서 dirty bit를 0으로 돌려줘야하지만, 어차피 clear 될 녀석이므로 생략했다.

그 후, 페이지는 수정 여부와 관계없이 페이지 테이블에서 현재 페이지의 매핑을 제거하고 페이지 프레임을 할당 해제한다.
페이지 테이블과 관련된 해시 테이블에서 현재 페이지를 삭제하고, 할당된 메모리를 해제시키면 해당 페이지는 더 이상 메모리에 매핑되지 않게 된다.

profile
사랑아 컴퓨터해 ~

0개의 댓글