๐Ÿ“Œ VMA / mmap

์ž‘์„ฑ์ผ: 2026-06-18 | ์ตœ์ข… ์ˆ˜์ •: 2026-06-19
๊ด€๋ จ ์†Œ์Šค: mm/mmap.c (1922์ค„), mm/memory.c (7493์ค„), mm/vma.c (3309์ค„), include/linux/mm_types.h (1941์ค„)
๋ณด์กฐ ์†Œ์Šค: mm/util.c, mm/gup.c, arch/x86/mm/fault.c, arch/x86/include/asm/pgtable_types.h
๊ด€๋ จ ๋ฌธ์„œ: Huge Pages / THP ยท Folio / Page Cache ยท Userfaultfd ยท ๋ฉ”๋ชจ๋ฆฌ Sealing ยท Secret Memory ยท ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š”

๊ฐœ์š” (Overview)

VMA(Virtual Memory Area)๋Š” ํ”„๋กœ์„ธ์Šค์˜ ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„์„ ๊ตฌ์„ฑํ•˜๋Š” ํ•ต์‹ฌ ์ž๋ฃŒ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ๊ฐ VMA๋Š” ์—ฐ์†๋œ ๊ฐ€์ƒ ์ฃผ์†Œ ๋ฒ”์œ„๋ฅผ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ๊ณต์œ ๋˜๋Š” ์†์„ฑ(์ฝ๊ธฐ/์“ฐ๊ธฐ/์‹คํ–‰ ๊ถŒํ•œ, ๋ฐฑ์—… ํŒŒ์ผ ๋“ฑ)์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ๋ฆฌ๋ˆ…์Šค ์ปค๋„์€ VMA๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Maple Tree๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, mmap() ์‹œ์Šคํ…œ ์ฝœ์„ ํ†ตํ•ด ํŒŒ์ผ์ด๋‚˜ ์žฅ์น˜๋ฅผ ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ์— ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.

์ผ์ƒ ๋น„์œ : ํ”„๋กœ์„ธ์Šค์˜ ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ๋Š” ์•„ํŒŒํŠธ ๋‹จ์ง€์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ฐ VMA๋Š” ํ•œ ๋™(ๆฃŸ)์— ํ•ด๋‹นํ•˜๋ฉฐ, mmap()์€ ์ƒˆ ๋™์„ ์ง“๋Š” ํ—ˆ๊ฐ€์ฆ์ž…๋‹ˆ๋‹ค. Page fault๋Š” ์ž…์ฃผ์ž๊ฐ€ "์ด ๋ฐฉ์— ์ฒ˜์Œ ๋“ค์–ด๊ฐˆ ๋•Œ" ๊ด€๋ฆฌ์‚ฌ๋ฌด์†Œ(MMU)๊ฐ€ ์—ด์‡ ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ณผ์ •๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. COW๋Š” ๋ถ€๋ชจ-์ž์‹์ด ๊ฐ™์€ ๋ฐฉ์„ ์“ฐ๋‹ค๊ฐ€ ๋ˆ„๊ตฐ๊ฐ€ ๊ฐ€๊ตฌ๋ฅผ ๋ฐ”๊ฟ€ ๋•Œ ๋น„๋กœ์†Œ ๋ฐฉ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Page fault ์ฒ˜๋ฆฌ๋Š” VMA์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ด€๋ฉ๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋งคํ•‘๋œ ์ฃผ์†Œ์— ์ฒ˜์Œ ์ ‘๊ทผํ•˜๋ฉด page fault๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ , ์ปค๋„์€ handle_mm_fault()๋ฅผ ํ†ตํ•ด ์ ์ ˆํ•œ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ํ•ญ๋ชฉ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ VMA์˜ ์†์„ฑ(์ต๋ช…/ํŒŒ์ผ ๊ธฐ๋ฐ˜, ๊ณต์œ /์‚ฌ์œ  ๋“ฑ)์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ฒ˜๋ฆฌ ๊ฒฝ๋กœ๊ฐ€ ์„ ํƒ๋ฉ๋‹ˆ๋‹ค.

ํŽ˜์ด์ง€ ํดํŠธ 3์ข…๋ฅ˜

์ข…๋ฅ˜์›์ธ์ฒ˜๋ฆฌI/O ๋ฐœ์ƒ
**minor fault (์†Œ ํดํŠธ)**๋ฌผ๋ฆฌ ํŽ˜์ด์ง€๋Š” ์žˆ์ง€๋งŒ PTE์— ์•„์ง ๋งคํ•‘ ์•ˆ ๋จ๊ธฐ์กด ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€๋ฅผ PTE์— ์—ฐ๊ฒฐ๋งŒ์—†์Œ (๋น ๋ฆ„)
**major fault (๋Œ€ ํดํŠธ)**๋ฌผ๋ฆฌ ํŽ˜์ด์ง€๊ฐ€ ์Šค์™‘/ํŒŒ์ผ์— ์žˆ์–ด ๋””์Šคํฌ I/O ํ•„์š”๋””์Šคํฌ์—์„œ ์ฝ์–ด์„œ ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€ ํ• ๋‹น ํ›„ PTE ์—ฐ๊ฒฐ์žˆ์Œ (๋А๋ฆผ)
**invalid access**VMA์— ์—†๋Š” ์ฃผ์†Œ, ๊ถŒํ•œ ์œ„๋ฐ˜ํ”„๋กœ์„ธ์Šค์— SIGSEGV ์‹œ๊ทธ๋„ ์ „๋‹ฌ์—†์Œ
์ฃผ์š” ์†Œ์Šค ํŒŒ์ผ:
- mm/mmap.c (1922์ค„) โ€” mmap ์‹œ์Šคํ…œ ์ฝœ, brk, VMA ์ƒ์„ฑ/์ œ๊ฑฐ
- mm/memory.c (7493์ค„) โ€” page fault ์ฒ˜๋ฆฌ, ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๊ด€๋ฆฌ
- mm/vma.c (3309์ค„) โ€” VMA ๋ณ‘ํ•ฉ, ๋ถ„ํ• , ๋งํฌ, __mmap_region()
- include/linux/mm_types.h (1941์ค„) โ€” vm_area_struct, mm_struct ์ •์˜

Demand Paging๊ณผ COW ๊ฐœ๋…

Demand Paging์€ ํ”„๋กœ์„ธ์Šค๊ฐ€ mmap()์ด๋‚˜ brk()๋กœ ๊ฐ€์ƒ ์ฃผ์†Œ๋ฅผ ์˜ˆ์•ฝํ–ˆ์„ ๋•Œ ์‹ค์ œ ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ์ฆ‰์‹œ ํ• ๋‹นํ•˜์ง€ ์•Š๊ณ , ์ฒ˜์Œ ์ ‘๊ทผํ•˜๋Š” ์ˆœ๊ฐ„์—๋งŒ ํŽ˜์ด์ง€๋ฅผ ํ• ๋‹นํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ํ”„๋กœ์„ธ์Šค์˜ VmSize(๊ฐ€์ƒ ํฌ๊ธฐ)์™€ VmRSS(์‹ค์ œ ๋ฌผ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰)๊ฐ€ ํฌ๊ฒŒ ๋‹ค๋ฅธ ์ด์œ ์ž…๋‹ˆ๋‹ค.

Copy-on-Write(COW)๋Š” fork() ์‹œ ๋ถ€๋ชจ์™€ ์ž์‹์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ฆ‰์‹œ ๋ณต์‚ฌํ•˜์ง€ ์•Š๊ณ  ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๊ณต์œ ํ•˜๋‹ค๊ฐ€, ์‹ค์ œ๋กœ ์“ฐ๊ธฐ ์‹œ๋„ ์‹œ์—๋งŒ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ์ตœ์ ํ™”์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด fork()๊ฐ€ ์ฆ‰์‹œ ๋ฐ˜ํ™˜๋˜๊ณ , ์ž์‹์ด ์ฝ๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋กœ ์†Œ๋น„๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

malloc()์—์„œ ์ปค๋„๊นŒ์ง€ โ€” ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์˜ ์ „์ฒด ๊ฒฝ๋กœ

malloc(100) โ†’ ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€ ํ™•๋ณด๊นŒ์ง€ ์ „์ฒด ๊ฒฝ๋กœ

[์‚ฌ์šฉ์ž ๊ณต๊ฐ„]
malloc(100) โ€” glibc ๋‚ด๋ถ€ free ์ฒญํฌ ํ™•์ธ (ptmalloc ํž™ ๊ด€๋ฆฌ)
โ†“
์ฒญํฌ ์—†์œผ๋ฉด ์ปค๋„์— ์š”์ฒญ
โ†“
[์ปค๋„ ๊ณต๊ฐ„ (syscall)]
brk() ๋˜๋Š” mmap() ์‹œ์Šคํ…œ ์ฝœ
โ†“
brk(): ํž™ ๋ ์ฃผ์†Œ(brk) ์ด๋™ โ†’ do_brk_flags()
mmap(MAP_ANONYMOUS): ์ƒˆ VMA ์ƒ์„ฑ (128KB ์ด์ƒ) โ†’ mmap_region()
โ†“
VMA(vm_area_struct) ์ƒ์„ฑ โ€” ๊ฐ€์ƒ ์ฃผ์†Œ ๋ฒ”์œ„๋งŒ ์˜ˆ์•ฝ, ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€ ํ• ๋‹น ์—†์Œ
โ†“
[Page Fault ๋ฐœ์ƒ ์‹œ]
์‹ค์ œ ์ ‘๊ทผ ์‹œ Page Fault โ†’ handle_mm_fault()
โ†“
do_anonymous_page() โ€” minor fault โ†’ ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€ ํ• ๋‹น ํ›„ PTE ์—ฐ๊ฒฐ
โ†“
Buddy Allocator โ€” alloc_page(GFP_KERNEL | __GFP_ZERO)

mmap/brk ์•ž๋‹จ ์ฒ˜๋ฆฌ ๋ณด๊ฐ•

malloc()์ด ์ปค๋„๋กœ ๋‚ด๋ ค์˜ฌ ๋•Œ ์ž‘์€ ํž™ ํ™•์žฅ์€ ๋ณดํ†ต brk(), ํฐ ์ต๋ช… ์˜์—ญ์ด๋‚˜ ํŒŒ์ผ ๋งคํ•‘์€ mmap() ๊ฒฝ๋กœ๋ฅผ ํƒ‘๋‹ˆ๋‹ค. Linux 7.0์˜ vm_mmap_pgoff()๋Š” ๋ณด์•ˆ ํ›…๊ณผ fsnotify ๊ฒ€์‚ฌ๋ฅผ ๋จผ์ € ํ†ต๊ณผํ•œ ๋’ค do_mmap()์„ ํ˜ธ์ถœํ•˜๊ณ , MAP_POPULATE๋‚˜ MAP_LOCKED๋กœ ์ฆ‰์‹œ fault-in์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ mm_populate()๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

/* mm/util.c:575-586 */
ret = security_mmap_file(file, prot, flag);
if (!ret)
	ret = fsnotify_mmap_perm(file, prot, off, len);
if (!ret) {
	if (mmap_write_lock_killable(mm))
		return -EINTR;
	ret = do_mmap(file, addr, len, prot, flag, 0, pgoff, &populate,
		      &uf);
	mmap_write_unlock(mm);
	userfaultfd_unmap_complete(mm, &uf);
	if (populate)
		mm_populate(ret, populate);
}

brk() ๊ณ„์—ด์€ ์š”์ฒญ ํฌ๊ธฐ๋ฅผ ํŽ˜์ด์ง€ ๊ฒฝ๊ณ„๋กœ ์˜ฌ๋ฆผํ•œ ๋’ค ๊ธฐ์กด ๋ฒ”์œ„๋ฅผ ๋จผ์ € ๋น„์šฐ๊ณ , do_brk_flags()์—์„œ ๊ธฐ์กด brk VMA ํ™•์žฅ ๋˜๋Š” ์ƒˆ ์ต๋ช… VMA ์ƒ์„ฑ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

/* mm/mmap.c:1214-1241 */
len = PAGE_ALIGN(request);
if (len < request)
	return -ENOMEM;
if (!len)
	return 0;

ret = check_brk_limits(addr, len);
if (ret)
	goto limits_failed;

ret = do_vmi_munmap(&vmi, mm, addr, len, &uf, 0);
if (ret)
	goto munmap_failed;

vma = vma_prev(&vmi);
ret = do_brk_flags(&vmi, vma, addr, len, vm_flags);
populate = ((mm->def_flags & VM_LOCKED) != 0);
mmap_write_unlock(mm);
userfaultfd_unmap_complete(mm, &uf);
if (populate && !ret)
	mm_populate(addr, len);

๋น ๋ฅธ ์ ๊ฒ€ ๋ช…๋ น

# ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค์˜ VMA ๋ชฉ๋ก ํ™•์ธ
cat /proc/self/maps | head -20

# ํŠน์ • ํ”„๋กœ์„ธ์Šค์˜ VMA ์ƒ์„ธ ์ •๋ณด (RSS, PSS, ์Šค์™‘ ๋“ฑ)
cat /proc/<PID>/smaps | head -50

# ์‹œ์Šคํ…œ ์ „์ฒด VMA ๊ฐœ์ˆ˜ ํ™•์ธ
cat /proc/vmstat | grep nr_mapped

# mmap ์‹œ์Šคํ…œ ์ฝœ ํŠธ๋ ˆ์ด์‹ฑ
strace -e mmap,brk ls

# ํ˜„์žฌ ์‹œ์Šคํ…œ์˜ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ํฌ๊ธฐ ํ™•์ธ
cat /proc/meminfo | grep PageTables

# ํŽ˜์ด์ง€ ํดํŠธ ํ†ต๊ณ„ (minor/major)
cat /proc/vmstat | grep -E 'pgfault|pgmajfault'

# ํ”„๋กœ์„ธ์Šค๋ณ„ VmSize vs VmRSS ๋น„๊ต (demand paging ํ™•์ธ)
cat /proc/$$/status | grep -E 'VmSize|VmRSS'

# ์ปค๋„ VMA ํ†ต๊ณ„
cat /proc/meminfo | grep -i vm

์ถ”๊ฐ€ ์ ๊ฒ€ ๋ช…๋ น

# ๊ธฐ๋ณธ ํŽ˜์ด์ง€ ํฌ๊ธฐ ํ™•์ธ
getconf PAGE_SIZE

# ํ˜„์žฌ ์…ธ ํ”„๋กœ์„ธ์Šค์˜ minor/major fault ๋ˆ„์ ๊ฐ’
ps -o pid,minflt,majflt -p $$

# ํŠน์ • ๋ช…๋ น ์‹คํ–‰ ์ค‘ minor/major fault ๊ณ„์ธก
perf stat -e minor-faults,major-faults <command>

# ํŠน์ • ํ”„๋กœ์„ธ์Šค์˜ TLB miss ๊ด€์ฐฐ
perf stat -e dTLB-load-misses,dTLB-store-misses,iTLB-load-misses -p <PID> -- sleep 5

# ํ”„๋กœ์„ธ์Šค๋ณ„ page table ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰
grep VmPTE /proc/<PID>/status

# ASLR ํ™œ์„ฑํ™” ์ˆ˜์ค€ ํ™•์ธ (0=off, 1=conservative, 2=full)
cat /proc/sys/kernel/randomize_va_space

ํ•ต์‹ฌ ์ž๋ฃŒ๊ตฌ์กฐ

vm_area_struct (include/linux/mm_types.h:913)

ํ”„๋กœ์„ธ์Šค์˜ ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„ ํ•˜๋‚˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค.

/* include/linux/mm_types.h:913-1056 */
struct vm_area_struct {
/* ์ฒซ ๋ฒˆ์งธ ์บ์‹œ ๋ผ์ธ: VMA ํŠธ๋ฆฌ ์ˆœํšŒ ์ •๋ณด */
union {
struct {
unsigned long vm_start;    /* VMA ์‹œ์ž‘ ์ฃผ์†Œ */
unsigned long vm_end;      /* VMA ๋ ์ฃผ์†Œ (ํฌํ•จ ์•ˆ ๋จ) */
};
freeptr_t vm_freeptr;  /* SLAB_TYPESAFE_BY_RCU์šฉ ํฌ์ธํ„ฐ */
};

struct mm_struct *vm_mm;    /* ์†Œ์† ์ฃผ์†Œ ๊ณต๊ฐ„ */
pgprot_t vm_page_prot;      /* ์ด VMA์˜ ์ ‘๊ทผ ๊ถŒํ•œ */

union {
const vm_flags_t vm_flags;  /* VMA ํ”Œ๋ž˜๊ทธ (VM_READ, VM_WRITE ๋“ฑ) */
vma_flags_t flags;
};

/* ์ต๋ช… ๋งคํ•‘ ๊ด€๋ จ */
struct list_head anon_vma_chain;
struct anon_vma *anon_vma;

/* ํŒŒ์ผ ๋งคํ•‘ ๊ด€๋ จ */
const struct vm_operations_struct *vm_ops;  /* VMA ์—ฐ์‚ฐ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ */
unsigned long vm_pgoff;     /* ํŒŒ์ผ ๋‚ด ํŽ˜์ด์ง€ ์˜คํ”„์…‹ */
struct file *vm_file;       /* ๋งคํ•‘๋œ ํŒŒ์ผ (์ต๋ช…์ด๋ฉด NULL) */
void *vm_private_data;      /* ๋“œ๋ผ์ด๋ฒ„ ์ „์šฉ ๋ฐ์ดํ„ฐ */
};

ํ•ต์‹ฌ ํ•„๋“œ ์„ค๋ช…:

  • vm_start/vm_end: VMA๊ฐ€ ์ฐจ์ง€ํ•˜๋Š” ๊ฐ€์ƒ ์ฃผ์†Œ ๋ฒ”์œ„ [vm_start, vm_end)
  • vm_flags: ์ฝ๊ธฐ/์“ฐ๊ธฐ/์‹คํ–‰ ๊ถŒํ•œ, ๊ณต์œ /์‚ฌ์œ  ๋งคํ•‘ ์—ฌ๋ถ€ ๋“ฑ
  • vm_file: ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋งคํ•‘์ด๋ฉด ํŒŒ์ผ ๊ฐ์ฒด, ์ต๋ช… ๋งคํ•‘์ด๋ฉด NULL
  • vm_ops: page fault ์ฒ˜๋ฆฌ ๋“ฑ VMA ๊ด€๋ จ ์—ฐ์‚ฐ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ
  • anon_vma: ์ต๋ช… ํŽ˜์ด์ง€์˜ reverse mapping์„ ์œ„ํ•œ ๊ตฌ์กฐ์ฒด
  • mm_struct (include/linux/mm_types.h:1123)

    ํ”„๋กœ์„ธ์Šค์˜ ์ „์ฒด ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค.

    /* include/linux/mm_types.h:1123-1319 (์ผ๋ถ€) */
    struct mm_struct {
    struct {
    struct maple_tree mm_mt;     /* VMA๋ฅผ ์ €์žฅํ•˜๋Š” Maple Tree */
    unsigned long mmap_base;     /* mmap ์˜์—ญ ์‹œ์ž‘ ์ฃผ์†Œ */
    unsigned long task_size;     /* ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„ ํฌ๊ธฐ */
    pgd_t *pgd;                  /* ํŽ˜์ด์ง€ ๊ธ€๋กœ๋ฒŒ ๋””๋ ‰ํ† ๋ฆฌ */
    atomic_t mm_users;           /* ์‚ฌ์šฉ์ž ์ˆ˜ */
    atomic_t mm_count;           /* ์ฐธ์กฐ ์นด์šดํŠธ */
    int map_count;               /* VMA ๊ฐœ์ˆ˜ */
    struct rw_semaphore mmap_lock;  /* mmap ์ž ๊ธˆ */
    unsigned long total_vm;      /* ์ „์ฒด ํŽ˜์ด์ง€ ์ˆ˜ */
    unsigned long locked_vm;     /* ์ž ๊ธด ํŽ˜์ด์ง€ ์ˆ˜ */
    unsigned long start_code, end_code;  /* ์ฝ”๋“œ ์˜์—ญ */
    unsigned long start_data, end_data;  /* ๋ฐ์ดํ„ฐ ์˜์—ญ */
    unsigned long start_brk, brk;        /* ํž™ ์˜์—ญ */
    unsigned long start_stack;           /* ์Šคํƒ ์‹œ์ž‘ */
    };
    };

    mmap_state (mm/vma.c:10)

    mmap ์‹œ Operation ์ƒํƒœ๋ฅผ ์ถ”์ ํ•˜๋Š” ๋‚ด๋ถ€ ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค.

    /* mm/vma.c:10-45 */
    struct mmap_state {
    struct mm_struct *mm;
    struct vma_iterator *vmi;
    unsigned long addr;
    unsigned long end;
    pgoff_t pgoff;
    unsigned long pglen;
    union {
    vm_flags_t vm_flags;
    vma_flags_t vma_flags;
    };
    struct file *file;
    pgprot_t page_prot;
    const struct vm_operations_struct *vm_ops;
    void *vm_private_data;
    unsigned long charged;
    struct vm_area_struct *prev;
    struct vm_area_struct *next;
    /* ๋งคํ•‘ ํ•ด์ œ ์ƒํƒœ */
    struct vma_munmap_struct vms;
    struct ma_state mas_detach;
    struct maple_tree mt_detach;
    bool check_ksm_early :1;
    bool hold_file_rmap_lock :1;
    bool file_doesnt_need_get :1;
    };

    vm_area_desc (include/linux/mm_types.h:880)

    mmap ์‹œ ๋“œ๋ผ์ด๋ฒ„๊ฐ€ VMA ์†์„ฑ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์ค‘๊ฐ„ ์„ค๋ช… ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค.

    /* include/linux/mm_types.h:880-899 */
    struct vm_area_desc {
    /* ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€ ์ƒํƒœ */
    const struct mm_struct *const mm;
    struct file *const file;
    unsigned long start;
    unsigned long end;
    /* ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ํ•„๋“œ */
    pgoff_t pgoff;
    struct file *vm_file;
    vma_flags_t vma_flags;
    pgprot_t page_prot;
    /* ์“ฐ๊ธฐ ์ „์šฉ ํ•„๋“œ */
    const struct vm_operations_struct *vm_ops;
    void *private_data;
    struct mmap_action action;
    };
    VMA/mmap ํ˜ธ์ถœ ํ๋ฆ„
    VMA/mmap ์ž๋ฃŒ๊ตฌ์กฐ ๊ด€๊ณ„๋„

    ํ•ต์‹ฌ ํ•จ์ˆ˜

    1. do_mmap() โ€” mmap ์‹œ์Šคํ…œ ์ฝœ์˜ ํ•ต์‹ฌ ๋กœ์ง

    /* mm/mmap.c:335-339 */
    unsigned long do_mmap(struct file *file, unsigned long addr,
    unsigned long len, unsigned long prot,
    unsigned long flags, vm_flags_t vm_flags,
    unsigned long pgoff, unsigned long *populate,
    struct list_head *uf)

    ์—ญํ• : ์‚ฌ์šฉ์ž ๊ณต๊ฐ„์˜ mmap() ์‹œ์Šคํ…œ ์ฝœ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•ต์‹ฌ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๋งคํ•‘ ์š”์ฒญ์„ ๊ฒ€์ฆํ•˜๊ณ , ์ ์ ˆํ•œ ๊ฐ€์ƒ ์ฃผ์†Œ๋ฅผ ์ฐพ์•„์„œ mmap_region()์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

    ์ฃผ์š” ๋ถ„๊ธฐ ๋กœ์ง:

  • MAP_FIXED ํ”Œ๋ž˜๊ทธ: ์ง€์ •๋œ ์ฃผ์†Œ์— ๊ฐ•์ œ ๋งคํ•‘
  • MAP_SHARED vs MAP_PRIVATE: ๊ณต์œ /์‚ฌ์œ  ๋งคํ•‘ ๊ฒฐ์ •
  • ํŒŒ์ผ ๋งคํ•‘ ์‹œ: file->f_op->mmap ํ˜ธ์ถœ ์—ฌ๋ถ€ ๊ฒฐ์ •
  • populate: ๋งคํ•‘ ์ฆ‰์‹œ ํŽ˜์ด์ง€ ํ• ๋‹น ์—ฌ๋ถ€ (prefault)
  • 2. mmap_region() โ€” VMA ์ƒ์„ฑ/๋ณ‘ํ•ฉ ์ˆ˜ํ–‰

    /* mm/vma.c:2818-2820 */
    unsigned long mmap_region(struct file *file, unsigned long addr,
    unsigned long len, vm_flags_t vm_flags, unsigned long pgoff,
    struct list_head *uf)

    ์—ญํ• : ์‹ค์ œ VMA ์ƒ์„ฑ ๋˜๋Š” ๊ธฐ์กด VMA์™€์˜ ๋ณ‘ํ•ฉ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. __mmap_region()์„ ํ˜ธ์ถœํ•˜์—ฌ ํ•ต์‹ฌ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

    ์ƒ์„ธ ํ๋ฆ„ (mm/vma.c:2720-2793):

    __mmap_region()
    โ”œโ”€ __mmap_setup() โ€” mmap_state ์ดˆ๊ธฐํ™”, ์ฃผ์†Œ ๊ฒ€์ฆ
    โ”œโ”€ call_mmap_prepare() โ€” ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ .mmap_prepare ํ›… ํ˜ธ์ถœ
    โ”œโ”€ update_ksm_flags() โ€” KSM ํ”Œ๋ž˜๊ทธ ์„ค์ • (check_ksm_early)
    โ”œโ”€ vma_merge_new_range() โ€” ์ธ์ ‘ VMA ๋ณ‘ํ•ฉ ์‹œ๋„
    โ”‚   โ”œโ”€ ๋ณ‘ํ•ฉ ์„ฑ๊ณต: ๊ธฐ์กด VMA ํ™•์žฅ
    โ”‚   โ””โ”€ ๋ณ‘ํ•ฉ ์‹คํŒจ: __mmap_new_vma() โ†’ ์ƒˆ VMA ํ• ๋‹น
    โ”œโ”€ __mmap_complete() โ€” VMA ์„ค์ • ์™„๋ฃŒ
    โ””โ”€ call_action_complete() โ€” .mmap_prepare ํ›„์† ์•ก์…˜ ์‹คํ–‰

    ์ฃผ์š” ๋ถ„๊ธฐ ๋กœ์ง:

  • map_deny_write_exec(): MDWE(Memory Deny Write Exec) ๊ฒ€์‚ฌ
  • arch_validate_flags(): ์•„ํ‚คํ…์ฒ˜๋ณ„ vm_flags ๊ฒ€์ฆ
  • mapping_map_writable(): ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ํŒŒ์ผ ๋งคํ•‘ ์‹œ ๋ฉ”๋ชจ๋ฆฌ ํšŒ๊ณ„
  • 3. handle_mm_fault() โ€” Page Fault ์ฒ˜๋ฆฌ ์ง„์ž…์ 

    /* mm/memory.c:6589-6591 */
    vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address,
    unsigned int flags, struct pt_regs *regs)

    ์—ญํ• : ํ•˜๋“œ์›จ์–ด page fault ์ธํ„ฐ๋ŸฝํŠธ์—์„œ ํ˜ธ์ถœ๋˜๋Š” ์ง„์ž… ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. VMA ๊ถŒํ•œ ๊ฒ€์ฆ ํ›„ __handle_mm_fault()๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

    ์ฃผ์š” ๋ถ„๊ธฐ ๋กœ์ง:

  • hugetlb_fault(): HugePage ๋งคํ•‘ ์‹œ ๋ณ„๋„ ์ฒ˜๋ฆฌ
  • VM_DROPPABLE: ๋“œ๋กญ ๊ฐ€๋Šฅํ•œ ๋งคํ•‘์˜ OOM ์—๋Ÿฌ ๋ฌด์‹œ
  • mem_cgroup_enter_user_fault(): ๋ฉ”๋ชจ๋ฆฌ cgroup OOM ์ฒ˜๋ฆฌ
  • 4. __handle_mm_fault() โ€” 4๋‹จ๊ณ„ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์ˆœํšŒ

    /* mm/memory.c:6355-6357 */
    static vm_fault_t __handle_mm_fault(struct vm_area_struct *vma,
    unsigned long address, unsigned int flags)

    ์—ญํ• : PGD โ†’ P4D โ†’ PUD โ†’ PMD โ†’ PTE ์ˆœ์œผ๋กœ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์„ ์ˆœํšŒํ•˜๋ฉฐ ์—†์œผ๋ฉด ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

    ์ฃผ์š” ๋ถ„๊ธฐ ๋กœ์ง:

  • create_huge_pud()/create_huge_pmd(): HugePage PUD/PMD ์ƒ์„ฑ ์‹œ๋„
  • wp_huge_pud()/wp_huge_pmd(): HugePage ์“ฐ๊ธฐ ๊ฐ€๋Šฅ ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ
  • handle_pte_fault(): ์ผ๋ฐ˜ PTE ๋ ˆ๋ฒจ fault ์ฒ˜๋ฆฌ๋กœ fallback
  • 5. handle_pte_fault() โ€” PTE ๋ ˆ๋ฒจ fault ๋ถ„๊ธฐ

    /* mm/memory.c:6273-6275 */
    static vm_fault_t handle_pte_fault(struct vm_fault *vmf)

    ์—ญํ• : PTE ํ•ญ๋ชฉ์˜ ์ƒํƒœ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ fault ํ•ธ๋“ค๋Ÿฌ๋กœ ๋ถ„๊ธฐํ•ฉ๋‹ˆ๋‹ค.

    ์ฃผ์š” ๋ถ„๊ธฐ ๋กœ์ง:

    handle_pte_fault()
    โ”œโ”€ pmd_none() โ†’ vmf->pte = NULL
    โ”œโ”€ pte_none(orig_pte) โ†’ vmf->pte = NULL (ptomap ํ•ด์ œ)
    โ”‚
    โ”œโ”€ vmf->pte == NULL (PTE ์—†์Œ)
    โ”‚   โ””โ”€ do_pte_missing()
    โ”‚       โ”œโ”€ vma_is_anonymous() โ†’ do_anonymous_page()  โ† ์ต๋ช… ๋งคํ•‘
    โ”‚       โ””โ”€ else โ†’ do_fault()                         โ† ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋งคํ•‘
    โ”‚
    โ”œโ”€ !pte_present(orig_pte) โ†’ do_swap_page()            โ† ์Šค์™‘์—์„œ ๋ณต๊ตฌ
    โ”‚
    โ”œโ”€ pte_protnone() && vma_is_accessible() โ†’ do_numa_page()  โ† NUMA ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜
    โ”‚
    โ””โ”€ PTE ์กด์žฌ, ์ ‘๊ทผ ๊ฐ€๋Šฅ
    โ”œโ”€ FAULT_FLAG_WRITE && !pte_write() โ†’ do_wp_page()     โ† COW ์ฒ˜๋ฆฌ
    โ”œโ”€ FAULT_FLAG_WRITE โ†’ pte_mkdirty()                    โ† ์“ฐ๊ธฐ ์ ‘๊ทผ
    โ””โ”€ pte_mkyoung()                                       โ† ์ ‘๊ทผ ๋น„ํŠธ ์„ค์ •

    6. do_anonymous_page() โ€” ์ต๋ช… ํŽ˜์ด์ง€ ํ• ๋‹น (minor fault)

    /* mm/memory.c โ€” static vm_fault_t do_anonymous_page(struct vm_fault *vmf) */

    ์—ญํ• : PTE๊ฐ€ ์—†๋Š” ์ต๋ช… ๋งคํ•‘ ์˜์—ญ์— ๋Œ€ํ•œ ์ตœ์ดˆ ์ ‘๊ทผ ์‹œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์ƒˆ ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ํ• ๋‹นํ•˜๊ณ  PTE์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

    ํ๋ฆ„:

  • alloc_anon_folio() โ€” THP(mTHP) ์ง€์› ํฌํ•จ folio ํ• ๋‹น
  • mem_cgroup_charge() โ€” ๋ฉ”๋ชจ๋ฆฌ cgroup ์ถฉ์ „
  • folio_add_new_anon_rmap() โ€” anon_vma์— RMAP ๋“ฑ๋ก
  • set_pte_at() โ€” PTE ์„ค์ •
  • 7. do_wp_page() โ€” Copy-on-Write ์ฒ˜๋ฆฌ

    /* mm/memory.c โ€” static vm_fault_t do_wp_page(struct vm_fault *vmf) */

    ์—ญํ• : ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋งคํ•‘๋œ ํŽ˜์ด์ง€์— ์“ฐ๊ธฐ ์‹œ๋„ ์‹œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์ฐธ์กฐ ์นด์šดํŠธ๊ฐ€ 1์ด๋ฉด wp_page_reuse()๋กœ PTE ์“ฐ๊ธฐ ๊ถŒํ•œ๋งŒ ํ™œ์„ฑํ™”ํ•˜๊ณ , ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๊ณต์œ  ์ค‘์ด๋ฉด wp_page_copy()๋กœ ์ƒˆ ํŽ˜์ด์ง€๋ฅผ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค.

    /* COW ํ•ต์‹ฌ ๋ถ„๊ธฐ (mm/memory.c) */
    static vm_fault_t do_wp_page(struct vm_fault *vmf)
    {
    struct page *old_page = vm_normal_page(vmf->vma, vmf->address, vmf->orig_pte);
    if (page_count(old_page) == 1)
    return wp_page_reuse(vmf);   /* ์ด ํ”„๋กœ์„ธ์Šค๋งŒ ์‚ฌ์šฉ โ†’ ๋ณต์‚ฌ ๋ถˆํ•„์š” */
    return wp_page_copy(vmf);        /* ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค ๊ณต์œ  โ†’ ์ƒˆ ํŽ˜์ด์ง€ ๋ณต์‚ฌ */
    }

    Linux 7.0 ์‹ค์ œ COW ๋ถ„๊ธฐ

    Linux 7.0 ์‹ค์ œ do_wp_page()๋Š” page_count(old_page) == 1๋งŒ ๋ณด์ง€ ์•Š๊ณ , ๊ณต์œ  ๋งคํ•‘ ์—ฌ๋ถ€์™€ ์ต๋ช… folio์˜ exclusive ์ƒํƒœ๋ฅผ ๊ธฐ์ค€์œผ๋กœ wp_page_reuse() ๋˜๋Š” wp_page_copy()๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

    /* mm/memory.c:4197-4241 */
    if (vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) {
    	if (!vmf->page || is_fsdax_page(vmf->page)) {
    		vmf->page = NULL;
    		return wp_pfn_shared(vmf);
    	}
    	return wp_page_shared(vmf, folio);
    }
    
    if (folio && folio_test_anon(folio) &&
    	    (PageAnonExclusive(vmf->page) || wp_can_reuse_anon_folio(folio, vma))) {
    	if (!PageAnonExclusive(vmf->page))
    		SetPageAnonExclusive(vmf->page);
    	if (unlikely(unshare)) {
    		pte_unmap_unlock(vmf->pte, vmf->ptl);
    		return 0;
    	}
    	wp_page_reuse(vmf, folio);
    	return 0;
    }
    
    if (folio)
    	folio_get(folio);
    
    pte_unmap_unlock(vmf->pte, vmf->ptl);
    #ifdef CONFIG_KSM
    if (folio && folio_test_ksm(folio))
    	count_vm_event(COW_KSM);
    #endif
    return wp_page_copy(vmf);

    ํŒŒ์ผ ๋งคํ•‘ fault ์„ธ๋ถ€ ๋ถ„๊ธฐ

    PTE๊ฐ€ ๋น„์–ด ์žˆ์„ ๋•Œ do_pte_missing()์€ VMA๊ฐ€ ์ต๋ช… ๋งคํ•‘์ด๋ฉด do_anonymous_page(), ํŒŒ์ผ ๊ธฐ๋ฐ˜์ด๋ฉด do_fault()๋กœ ๋‚˜๋ˆ•๋‹ˆ๋‹ค.

    /* mm/memory.c:4472-4478 */
    static vm_fault_t do_pte_missing(struct vm_fault *vmf)
    {
    	if (vma_is_anonymous(vmf->vma))
    		return do_anonymous_page(vmf);
    	else
    		return do_fault(vmf);
    }

    ํŒŒ์ผ ๊ธฐ๋ฐ˜ do_fault()๋Š” ์ฝ๊ธฐ fault, private COW fault, shared write fault๋ฅผ ๋‹ค์‹œ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ถ„๊ธฐ๊ฐ€ minzkn์˜ do_read_fault() / do_cow_fault() / do_shared_fault() ํ๋ฆ„์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

    /* mm/memory.c:5903-5945 */
    static vm_fault_t do_fault(struct vm_fault *vmf)
    {
    	struct vm_area_struct *vma = vmf->vma;
    	struct mm_struct *vm_mm = vma->vm_mm;
    	vm_fault_t ret;
    
    	if (!vma->vm_ops->fault) {
    		vmf->pte = pte_offset_map_lock(vmf->vma->vm_mm, vmf->pmd,
    					       vmf->address, &vmf->ptl);
    		if (unlikely(!vmf->pte))
    			ret = VM_FAULT_SIGBUS;
    		else {
    			if (unlikely(pte_none(ptep_get(vmf->pte))))
    				ret = VM_FAULT_SIGBUS;
    			else
    				ret = VM_FAULT_NOPAGE;
    
    			pte_unmap_unlock(vmf->pte, vmf->ptl);
    		}
    	} else if (!(vmf->flags & FAULT_FLAG_WRITE))
    		ret = do_read_fault(vmf);
    	else if (!(vma->vm_flags & VM_SHARED))
    		ret = do_cow_fault(vmf);
    	else
    		ret = do_shared_fault(vmf);
    
    	/* preallocated pagetable is unused: free it */
    	if (vmf->prealloc_pte) {
    		pte_free(vm_mm, vmf->prealloc_pte);
    		vmf->prealloc_pte = NULL;
    	}
    	return ret;
    }

    ํ˜ธ์ถœ ํ๋ฆ„

    [์‚ฌ์šฉ์ž ๊ณต๊ฐ„]
    mmap() ์‹œ์Šคํ…œ ์ฝœ
    โ†“
    [์ปค๋„]
    sys_mmap() โ†’ do_mmap()
    โ†“
    mmap_region() โ†’ __mmap_region()
    โ†“
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚ VMA ๋ณ‘ํ•ฉ ์‹œ๋„: vma_merge_new_range()โ”‚
    โ”‚   - ๋ณ‘ํ•ฉ ์„ฑ๊ณต: ๊ธฐ์กด VMA ํ™•์žฅ        โ”‚
    โ”‚   - ๋ณ‘ํ•ฉ ์‹คํŒจ: __mmap_new_vma()     โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
    โ†“
    __mmap_complete() โ†’ VMA ์„ค์ • ์™„๋ฃŒ
    โ†“
    [Page Fault ๋ฐœ์ƒ ์‹œ]
    handle_mm_fault()
    โ†“
    __handle_mm_fault()
    โ†“
    PGD โ†’ P4D โ†’ PUD โ†’ PMD โ†’ PTE ์ˆœํšŒ
    โ†“
    handle_pte_fault()
    โ†“
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚ PTE ์—†์Œ: do_anonymous_page()       โ”‚
    โ”‚ PTE ์—†์Œ(ํŒŒ์ผ): do_fault()          โ”‚
    โ”‚ ์Šค์™‘: do_swap_page()                โ”‚
    โ”‚ COW: do_wp_page()                   โ”‚
    โ”‚ NUMA: do_numa_page()                โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

    x86_64 Page Fault ์•ž๋‹จ

    handle_mm_fault()๋Š” MM ๊ณตํ†ต ์ง„์ž…์ ์ด๊ณ , x86_64์—์„œ๋Š” ๊ทธ ์•ž์— ์•„ํ‚คํ…์ฒ˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๊ฒฝ๋กœ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. exc_page_fault()๊ฐ€ CR2 fault ์ฃผ์†Œ๋ฅผ ์ฝ๊ณ  handle_page_fault()๋กœ ์ „๋‹ฌํ•˜๋ฉด, ์‚ฌ์šฉ์ž ์ฃผ์†Œ๋Š” do_user_addr_fault()์—์„œ VMA ํƒ์ƒ‰๊ณผ ๊ถŒํ•œ ๊ฒ€์‚ฌ๋ฅผ ๊ฑฐ์นœ ๋’ค handle_mm_fault()๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

    /* arch/x86/mm/fault.c:1470-1475 */
    if (unlikely(fault_in_kernel_space(address))) {
    	do_kern_addr_fault(regs, error_code, address);
    } else {
    	do_user_addr_fault(regs, error_code, address);
    }
    /* arch/x86/mm/fault.c:1325-1335 */
    vma = lock_vma_under_rcu(mm, address);
    if (!vma)
    	goto lock_mmap;
    
    if (unlikely(access_error(error_code, vma))) {
    	bad_area_access_error(regs, error_code, address, NULL, vma);
    	count_vm_vma_lock_event(VMA_LOCK_SUCCESS);
    	return;
    }
    fault = handle_mm_fault(vma, address, flags | FAULT_FLAG_VMA_LOCK, regs);

    RCU VMA lock fast path๊ฐ€ ์‹คํŒจํ•˜๊ฑฐ๋‚˜ retry๊ฐ€ ํ•„์š”ํ•˜๋ฉด lock_mm_and_find_vma()๋กœ mmap lock ๊ธฐ๋ฐ˜ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

    /* arch/x86/mm/fault.c:1357-1385 */
    vma = lock_mm_and_find_vma(mm, address, regs);
    if (unlikely(!vma)) {
    	bad_area_nosemaphore(regs, error_code, address);
    	return;
    }
    
    if (unlikely(access_error(error_code, vma))) {
    	bad_area_access_error(regs, error_code, address, mm, vma);
    	return;
    }
    
    fault = handle_mm_fault(vma, address, flags, regs);

    ์กฐ๊ฑด๋ณ„ ๋น„๊ต

    ์กฐ๊ฑด์ฒ˜๋ฆฌ ํ•จ์ˆ˜์„ค๋ช…
    ์ต๋ช… ๋งคํ•‘ (์ตœ์ดˆ ์ ‘๊ทผ)`do_anonymous_page()`์ƒˆ ํŽ˜์ด์ง€ ํ• ๋‹น, zero-fill
    ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋งคํ•‘ (์ตœ์ดˆ ์ ‘๊ทผ)`do_fault()`ํŒŒ์ผ์—์„œ ํŽ˜์ด์ง€ ์ฝ๊ธฐ
    COW (์“ฐ๊ธฐ fault)`do_wp_page()`ํŽ˜์ด์ง€ ๋ณต์‚ฌ ํ›„ ๋…๋ฆฝ ์‚ฌ์šฉ
    ์Šค์™‘๋œ ํŽ˜์ด์ง€ ์ ‘๊ทผ`do_swap_page()`์Šค์™‘์—์„œ ํŽ˜์ด์ง€ ๋ณต๊ตฌ
    NUMA ํ”„๋กœํ…์…˜ fault`do_numa_page()`NUMA ๋…ธ๋“œ ๊ฐ„ ํŽ˜์ด์ง€ ์ด๋™
    HugePage ๋งคํ•‘`hugetlb_fault()`HugePage ์ „์šฉ ์ฒ˜๋ฆฌ
    MAP_FIXED ๋งคํ•‘๊ธฐ์กด VMA ์ œ๊ฑฐ ํ›„ ์ƒˆ ๋งคํ•‘์ง€์ •๋œ ์ฃผ์†Œ์— ๊ฐ•์ œ ๋งคํ•‘
    MAP_SHARED๊ณต์œ  VMA, ํŒŒ์ผ backed`anon_vma` ๋Œ€์‹  `i_mmap` ์‚ฌ์šฉ
    MAP_PRIVATE์‚ฌ์œ  VMA, COW ์ง€์›`anon_vma` ์‚ฌ์šฉ

    mmap ํ”Œ๋ž˜๊ทธ ๋น„๊ต

    ํ”Œ๋ž˜๊ทธLinux 7.0 ์ฒ˜๋ฆฌ ํฌ์ธํŠธ์†Œ์Šค ๊ทผ๊ฑฐ
    `MAP_SHARED`ํŒŒ์ผ ๋งคํ•‘์ด๋ฉด ์“ฐ๊ธฐ ๊ถŒํ•œ๊ณผ append-only/seal์„ ๊ฒ€์‚ฌํ•˜๊ณ  `VM_SHARED \VM_MAYSHARE` ์„ค์ •`mm/mmap.c:435-464`
    `MAP_PRIVATE`ํŒŒ์ผ ๋งคํ•‘์€ ์ฝ๊ธฐ ๊ฐ€๋Šฅ ์—ฌ๋ถ€์™€ noexec๋ฅผ ๊ฒ€์‚ฌํ•˜๊ณ , ์ต๋ช… ๋งคํ•‘์€ `pgoff = addr >> PAGE_SHIFT` ์„ค์ •`mm/mmap.c:467-539`
    `MAP_ANONYMOUS``file == NULL` ๊ฒฝ๋กœ๋กœ ๋“ค์–ด๊ฐ€๋ฉฐ private ์ต๋ช… VMA๋Š” ํŒŒ์ผ ์—†์ด demand paging์œผ๋กœ ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ๋’ค๋Šฆ๊ฒŒ ํ™•๋ณด`mm/mmap.c:493-539`
    `MAP_FIXED_NOREPLACE``MAP_FIXED` ์ฒ˜๋ฆฌ๋กœ ๋„˜๊ธฐ๋˜ ๊ธฐ์กด VMA์™€ ๊ต์ฐจํ•˜๋ฉด `-EEXIST` ๋ฐ˜ํ™˜`mm/mmap.c:361-413`
    `MAP_POPULATE``do_mmap()` ๋’ค `populate` ๊ธธ์ด๋ฅผ ์„ค์ •ํ•˜๊ณ , ์ƒ์œ„ `vm_mmap_pgoff()`์—์„œ `mm_populate()` ํ˜ธ์ถœ`mm/mmap.c:559-563`, `mm/util.c:585-586`
    `MAP_LOCKED``can_do_mlock()`์™€ `mlock_future_ok()`๋ฅผ ๊ฒ€์‚ฌํ•˜๊ณ , populate ์กฐ๊ฑด์—๋„ ํฌํ•จ`mm/mmap.c:416-421`, `mm/mmap.c:559-563`
    `MAP_HUGETLB``ksys_mmap_pgoff()`์—์„œ HugeTLB ํŒŒ์ผ ์„ค์ • ๋˜๋Š” ํŒŒ์ผ HugeTLB ๊ธธ์ด ์ •๋ ฌ์„ ์ˆ˜ํ–‰`mm/mmap.c:579-603`

    MAP_POPULATE์™€ MAP_LOCKED์˜ ์‹ค์ œ fault-in์€ __mm_populate()๊ฐ€ VMA ๋ฒ”์œ„๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ populate_vma_page_range()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

    /* mm/gup.c:1918-1925 */
    /*
    * __mm_populate - populate and/or mlock pages within a range of address space.
    *
    * This is used to implement mlock() and the MAP_POPULATE / MAP_LOCKED mmap
    * flags. VMAs must be already marked with the desired vm_flags, and
    * mmap_lock must not be held.
    */
    int __mm_populate(unsigned long start, unsigned long len, int ignore_errors)

    PTE ํ”Œ๋ž˜๊ทธ์™€ TLB ๊ด€์ 

    VMA๋Š” ์ฃผ์†Œ ๋ฒ”์œ„์™€ ์ •์ฑ…์„ ์„ค๋ช…ํ•˜์ง€๋งŒ, ์‹ค์ œ ์ ‘๊ทผ ํ—ˆ์šฉ ์—ฌ๋ถ€๋Š” ์ตœ์ข…์ ์œผ๋กœ PTE ํ”Œ๋ž˜๊ทธ์™€ TLB ์บ์‹œ์— ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. x86_64 ๊ธฐ์ค€ PTE ์ฃผ์š” ๋น„ํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    PTE ๋น„ํŠธ์˜๋ฏธ์†Œ์Šค ๊ทผ๊ฑฐ
    `_PAGE_PRESENT` bit 0๋ฌผ๋ฆฌ ํŽ˜์ด์ง€๊ฐ€ ํ˜„์žฌ ๋งคํ•‘๋˜์–ด ์žˆ์Œ`arch/x86/include/asm/pgtable_types.h:10,51`
    `_PAGE_RW` bit 1์“ฐ๊ธฐ ๊ฐ€๋Šฅ`arch/x86/include/asm/pgtable_types.h:11,52`
    `_PAGE_USER` bit 2์‚ฌ์šฉ์ž ๊ณต๊ฐ„ ์ ‘๊ทผ ๊ฐ€๋Šฅ`arch/x86/include/asm/pgtable_types.h:12,53`
    `_PAGE_ACCESSED` bit 5CPU๊ฐ€ ์ ‘๊ทผ ๋น„ํŠธ๋ฅผ ์„ธ์›€`arch/x86/include/asm/pgtable_types.h:15,56`
    `_PAGE_DIRTY` bit 6CPU๊ฐ€ ์“ฐ๊ธฐ ๋ฐœ์ƒ์„ ๊ธฐ๋ก`arch/x86/include/asm/pgtable_types.h:16,57`
    `_PAGE_NX` bit 63์‹คํ–‰ ๊ธˆ์ง€(No Execute)`arch/x86/include/asm/pgtable_types.h:30,121-125`

    TLB๋Š” ์ตœ๊ทผ ๊ฐ€์ƒ์ฃผ์†Œโ†’๋ฌผ๋ฆฌ์ฃผ์†Œ ๋ณ€ํ™˜ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•ฉ๋‹ˆ๋‹ค. VMA ๋ณ€๊ฒฝ, PTE ๊ถŒํ•œ ๋ณ€๊ฒฝ, COW ๋ณต์‚ฌ ํ›„ PTE ๊ต์ฒด์ฒ˜๋Ÿผ ๋ณ€ํ™˜ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ”๋€Œ๋Š” ์ž‘์—…์€ ํ•„์š” ์‹œ TLB invalidation/shootdown์„ ๋™๋ฐ˜ํ•˜๋ฉฐ, ์‹คํ–‰ ์ค‘ ์ง€์—ฐ์€ perf stat -e dTLB-load-misses,dTLB-store-misses,iTLB-load-misses๋กœ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    VMA ๋ณ‘ํ•ฉ ์กฐ๊ฑด

    VMA ๋ณ‘ํ•ฉ์€ ์ธ์ ‘ํ•œ VMA๋ฅผ ํ•˜๋‚˜๋กœ ํ•ฉ์น˜๋Š” ์ตœ์ ํ™”์ž…๋‹ˆ๋‹ค. ๋ณ‘ํ•ฉ ์กฐ๊ฑด์€ vma.c์—์„œ ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค:

    /* mm/vma.c:86-101 โ€” ๋ณ‘ํ•ฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ๊ฒ€์‚ฌ */
    static inline bool is_mergeable_vma(struct vma_merge_struct *vmg, bool merge_next)
    {
    struct vm_area_struct *vma = merge_next ? vmg->next : vmg->prev;
    if (!mpol_equal(vmg->policy, vma_policy(vma)))  // NUMA ์ •์ฑ… ์ผ์น˜
    return false;
    if ((vma->vm_flags ^ vmg->vm_flags) & ~VM_IGNORE_MERGE)  // ํ”Œ๋ž˜๊ทธ ์ผ์น˜
    return false;
    if (vma->vm_file != vmg->file)  // ๊ฐ™์€ ํŒŒ์ผ
    return false;
    if (!is_mergeable_vm_userfaultfd_ctx(vma, vmg->uffd_ctx))  // userfaultfd ์ปจํ…์ŠคํŠธ
    return false;
    if (!anon_vma_name_eq(anon_vma_name(vma), vmg->anon_name))  // anon_vma ์ด๋ฆ„
    return false;
    return true;
    }

    ๋ณ‘ํ•ฉ ๋ถˆ๊ฐ€ ์กฐ๊ฑด:

  • ์„œ๋กœ ๋‹ค๋ฅธ NUMA ์ •์ฑ…
  • vm_flags ๋ถˆ์ผ์น˜ (VM_READ, VM_WRITE, VM_EXEC ๋“ฑ)
  • ๋‹ค๋ฅธ ํŒŒ์ผ ๋งคํ•‘
  • ๋‹ค๋ฅธ userfaultfd ์ปจํ…์ŠคํŠธ
  • ์„œ๋กœ ๋‹ค๋ฅธ anon_vma ์ด๋ฆ„
  • ๊ด€๋ จ ๋ฌธ์„œ

  • ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š” โ€” ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์•„ํ‚คํ…์ฒ˜
  • Buddy Allocator โ€” ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€ ํ• ๋‹น
  • SLUB ํ• ๋‹น์ž โ€” ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ์ตœ์ ํ™”
  • Huge Pages / THP โ€” ๋Œ€ํ˜• ํŽ˜์ด์ง€ ์ง€์›
  • Folio / Page Cache โ€” ํŒŒ์ผ ์บ์‹œ ๊ด€๋ฆฌ
  • Userfaultfd โ€” ์‚ฌ์šฉ์ž ๊ณต๊ฐ„ fault ์ฒ˜๋ฆฌ
  • ๋ฉ”๋ชจ๋ฆฌ Sealing โ€” ๋ฉ”๋ชจ๋ฆฌ ๋ณดํ˜ธ
  • Secret Memory โ€” ๋น„๋ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ