Pintos Project 3 — Memory‑Mapped Files 구현 흐름

2025. 6. 14. 16:40개발

Memory Mapped Files란?

메모리 매핑 파일(Memory Mapped File)은 말 그대로 파일의 데이터를 메모리 공간에 매핑하는 기술입니다. 일반적으로 파일 입출력은 read()나 write() 시스템 콜을 사용하지만, mmap을 사용하면 파일 데이터를 프로세스의 가상 메모리 공간에 직접 연결할 수 있습니다.

이렇게 연결해 놓으면 사용자는 마치 배열처럼 데이터를 접근할 수 있고, 실제 파일 내용은 메모리에서 읽거나 쓸 수 있습니다. 즉, read() 없이 포인터 접근만으로도 파일 내용을 읽을 수 있으며, 수정 사항도 메모리상에서 이뤄지다 munmap 시에 실제 파일에 반영됩니다.

 

mmap의 동작 방식

  1. 파일과 가상 메모리 매핑
    • 사용자가 mmap() 시스템 콜을 호출하면, 운영체제는 파일을 사용자의 가상 주소 공간에 매핑합니다. 이때 시작 주소(addr)는 페이지 단위로 정렬되어 있어야 하며, 매핑된 메모리 범위 역시 페이지 단위로 계산됩니다.
  2. 지연 할당 (Lazy Allocation)
    • 매핑 직후에는 물리 메모리가 실제로 할당되지 않습니다. 해당 주소를 처음 읽거나 쓸 때 **페이지 폴트(Page Fault)**가 발생하고, 그 시점에 파일에서 데이터를 읽어와 메모리에 로딩합니다. 이 방식은 메모리를 아끼고 접근할 때만 데이터를 로딩함으로써 성능을 높입니다.
  3. 수정 내용 반영
    • mmap으로 매핑된 주소를 통해 파일 내용을 수정한 경우, 해당 페이지는 dirty(수정됨) 상태가 됩니다. 이후 munmap() 시스템 콜을 통해 매핑이 해제되거나, 프로세스가 종료될 때 dirty 페이지의 내용을 실제 파일에 다시 기록합니다.

 

munmap의 동작 방식

  1. Dirty 페이지 확인 및 동기화
    • 매핑된 페이지 중 수정(dirty) 상태인 페이지는, pml4_is_dirty()로 확인한 뒤, 파일에 **file_write_at()**을 이용해 내용을 다시 씁니다. 이는 파일과 메모리 간 데이터 불일치를 방지하기 위함입니다.
  2. 페이지 테이블에서 제거
    • 이후 해당 페이지는 pml4_clear_page()를 통해 사용자 페이지 테이블에서 매핑이 제거됩니다.
  3. 물리 메모리 해제
    • 매핑된 물리 메모리가 존재하면, palloc_free_page()와 free(frame)을 통해 메모리와 frame 구조체가 해제됩니다.

1. mmap/munmap 전체 시퀀스

  1. 사용자 공간 호출
    void * addr = mmap(addr, length, prot, flags, fd, offset);
  2. syscall_handler → sys_mmap()
    인자 검증 (페이지 정렬, 권한, fd etc.)
  3. do_mmap()
    mfile = file_reopen(fd) (독립 손잡이)
    • length/offset → 페이지 단위 루프
       • 매 페이지마다 lazy_load_arg 채우기 & vm_alloc_page_with_initializer(VM_FILE, …)
  4. 접근 시 Fault In
    lazy_load_segment()file_read_at(mfile, …) + zero‑fill
    • PTE 매핑 완료
  5. munmap() 또는 process_exit()
    do_munmap(addr) : 매 페이지 dirty 검사 → file_write_at()
    supplemental_page_table_kill() 에서 destroy 호출 → file_backed_destroy()

2. 필수 함수 매핑

함수 역할 GitBook 섹션
sys_mmap() 사용자 인자 검증 후 do_mmap 호출 mmap API
do_mmap() 페이지 단위 예약 + file_reopen memory_mapped_files
lazy_load_segment() Fault In 시 파일 읽기 & 0‑fill vm_management
sys_munmap() user call → do_munmap memory_mapped_files
do_munmap() dirty 페이지 write‑back, frame 해제, SPT remove memory_mapped_files
file_backed_swap_out() Eviction 시 dirty write‑back vm_management

3. do_mmap() 핵심 코드 설명

struct file *mfile = file_reopen(file);  // 독립 핸들
size_t read_bytes = MIN(length, file_length(mfile));
size_t zero_bytes = PGSIZE - read_bytes % PGSIZE;
while (read_bytes > 0 || zero_bytes > 0) {
    size_t page_read = read_bytes >= PGSIZE ? PGSIZE : read_bytes;
    size_t page_zero = PGSIZE - page_read;
    aux = palloc_get_page(0);
    aux->file = mfile; aux->ofs = offset;
    aux->read_bytes = page_read; aux->zero_bytes = page_zero;
    vm_alloc_page_with_initializer(VM_FILE, addr, writable,
                                   lazy_load_segment, aux);
    addr += PGSIZE; offset += page_read;
    read_bytes -= page_read; zero_bytes -= page_zero;
}

포인트 : aux 에 mfile 과 (ofs, read, zero) 를 저장해 Fault In 루틴이 그대로 사용.

4. munmap → write‑back 흐름

/* do_munmap(addr) */
for (page = spt_find_page(addr); page_in_range; addr+=PGSIZE) {
    if (pml4_is_dirty(pml4, page->va)) {
        file_write_at(page->file.file, page->va,
                      page->file.read_bytes, page->file.ofs);
        pml4_clear_dirty(pml4, page->va);
    }
    pml4_clear_page(pml4, page->va);
    vm_dealloc_page(page);
}
file_close(page->file.file);  // 마지막 페이지에서 한 번만

5. 테스트 체크리스트

  • mmap-read : 파일 내용 올바르게 로드되는지
  • mmap-write : 메모리에서 수정 → munmap → 파일 내용 변경
  • mmap-close : fd close 후 mmap 영역 여전히 접근 가능
  • mmap-bad-fd : 잘못된 fd, 권한, 주소 전달 시 -1 반환