Pintos Project 3 — Memory‑Mapped Files 구현 흐름
2025. 6. 14. 16:40ㆍ개발
Memory Mapped Files란?
메모리 매핑 파일(Memory Mapped File)은 말 그대로 파일의 데이터를 메모리 공간에 매핑하는 기술입니다. 일반적으로 파일 입출력은 read()나 write() 시스템 콜을 사용하지만, mmap을 사용하면 파일 데이터를 프로세스의 가상 메모리 공간에 직접 연결할 수 있습니다.
이렇게 연결해 놓으면 사용자는 마치 배열처럼 데이터를 접근할 수 있고, 실제 파일 내용은 메모리에서 읽거나 쓸 수 있습니다. 즉, read() 없이 포인터 접근만으로도 파일 내용을 읽을 수 있으며, 수정 사항도 메모리상에서 이뤄지다 munmap 시에 실제 파일에 반영됩니다.
mmap의 동작 방식
- 파일과 가상 메모리 매핑
- 사용자가 mmap() 시스템 콜을 호출하면, 운영체제는 파일을 사용자의 가상 주소 공간에 매핑합니다. 이때 시작 주소(addr)는 페이지 단위로 정렬되어 있어야 하며, 매핑된 메모리 범위 역시 페이지 단위로 계산됩니다.
- 지연 할당 (Lazy Allocation)
- 매핑 직후에는 물리 메모리가 실제로 할당되지 않습니다. 해당 주소를 처음 읽거나 쓸 때 **페이지 폴트(Page Fault)**가 발생하고, 그 시점에 파일에서 데이터를 읽어와 메모리에 로딩합니다. 이 방식은 메모리를 아끼고 접근할 때만 데이터를 로딩함으로써 성능을 높입니다.
- 수정 내용 반영
- mmap으로 매핑된 주소를 통해 파일 내용을 수정한 경우, 해당 페이지는 dirty(수정됨) 상태가 됩니다. 이후 munmap() 시스템 콜을 통해 매핑이 해제되거나, 프로세스가 종료될 때 dirty 페이지의 내용을 실제 파일에 다시 기록합니다.
munmap의 동작 방식
- Dirty 페이지 확인 및 동기화
- 매핑된 페이지 중 수정(dirty) 상태인 페이지는, pml4_is_dirty()로 확인한 뒤, 파일에 **file_write_at()**을 이용해 내용을 다시 씁니다. 이는 파일과 메모리 간 데이터 불일치를 방지하기 위함입니다.
- 페이지 테이블에서 제거
- 이후 해당 페이지는 pml4_clear_page()를 통해 사용자 페이지 테이블에서 매핑이 제거됩니다.
- 물리 메모리 해제
- 매핑된 물리 메모리가 존재하면, palloc_free_page()와 free(frame)을 통해 메모리와 frame 구조체가 해제됩니다.
1. mmap/munmap 전체 시퀀스
- 사용자 공간 호출
void * addr = mmap(addr, length, prot, flags, fd, offset); - syscall_handler → sys_mmap()
인자 검증 (페이지 정렬, 권한, fd etc.) - do_mmap()
•mfile = file_reopen(fd)(독립 손잡이)
• length/offset → 페이지 단위 루프
• 매 페이지마다lazy_load_arg채우기 &vm_alloc_page_with_initializer(VM_FILE, …) - 접근 시 Fault In
•lazy_load_segment()→file_read_at(mfile, …)+ zero‑fill
• PTE 매핑 완료 - 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 반환
'개발' 카테고리의 다른 글
| 나만의 무기 1편: 개발 보다 더 어려운 기획 회의 (1) | 2025.07.30 |
|---|---|
| Pintos VM Project - merge-mm / stk / pa 테스트 트러블슈팅 정리 (0) | 2025.06.15 |
| Pintos Project 3 — Stack Growth 구현 흐름 & page_fault 분석 (0) | 2025.06.13 |
| Pintos Project 3: Anonymous Page 구현 흐름 집중 해부 (1) | 2025.06.12 |
| Pintos VM Project - lazy_load_segment & fork-read 디버그 (0) | 2025.06.05 |