mTHP (multi-size THP)

๊ด€๋ จ ์†Œ์Šค: mm/huge_memory.c (4978์ค„), mm/khugepaged.c (2873์ค„), include/linux/huge_mm.h (807์ค„)
๊ด€๋ จ ๋ฌธ์„œ: Huge Pages / THP ยท VMA / mmap ยท Folio / Page Cache ยท Compaction ยท ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š”

๊ฐœ์š” (Overview)

Linux 6.8+์—์„œ ๋„์ž…๋œ mTHP (multi-size THP) ๋Š” ๊ธฐ์กด THP๊ฐ€ ์ง€์›ํ•˜๋˜ PMD ํฌ๊ธฐ(2MB)๋ฟ ์•„๋‹ˆ๋ผ, order-2(16KB)๋ถ€ํ„ฐ order-9(PMD ํฌ๊ธฐ)๊นŒ์ง€ ๋‹ค์–‘ํ•œ ํฌ๊ธฐ์˜ large folio๋ฅผ ์ต๋ช… ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. mTHP๋Š” huge_anon_orders_always, huge_anon_orders_madvise, huge_anon_orders_inherit ๋น„ํŠธ๋งต์„ ํ†ตํ•ด order๋ณ„๋กœ ๊ฐœ๋ณ„์ ์ธ ํ™œ์„ฑํ™” ์ •์ฑ…์„ ์ œ๊ณตํ•˜๋ฉฐ, sysfs ์ธํ„ฐํŽ˜์ด์Šค(/sys/kernel/mm/transparent_hugepage/hugepages-XkB/)๋ฅผ ํ†ตํ•ด order๋ณ„ ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

mTHP๋Š” ๊ธฐ์กด THP์˜ PMD_ORDER ์ „์šฉ ๊ฒฝ๋กœ์™€ ๋‹ฌ๋ฆฌ, thp_vma_allowable_orders() ํ•จ์ˆ˜๊ฐ€ ๋น„ํŠธ๋งˆ์Šคํฌ ๊ธฐ๋ฐ˜์œผ๋กœ ํ—ˆ์šฉ๋˜๋Š” order๋ฅผ ๊ฒฐ์ •ํ•˜๊ณ , ํŽ˜์ด์ง€ ํดํŠธ ์ฒ˜๋ฆฌ ๊ฒฝ๋กœ์—์„œ order๋ณ„ large folio๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. khugepaged ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ๋Š” ํ˜„์žฌ๊นŒ์ง€ PMD_ORDER(2MB) ์ „์šฉ์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ, sub-PMD order์˜ ๋ณ‘ํ•ฉ์€ ์•„์ง ๊ตฌํ˜„๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. mTHP๋Š” per-CPU ํ†ต๊ณ„(mthp_stat_item)๋ฅผ ํ†ตํ•ด order๋ณ„ ํ• ๋‹น/ํด๋ฐฑ/์Šค์™‘/์Šคํ”Œ๋ฆฟ ์ด๋ฒคํŠธ๋ฅผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.

์ผ์ƒ ๋น„์œ : ๊ธฐ์กด THP๋Š” ๋ชจ๋“  ํฐ ๊ธ€์”จ๋ฅผ 2MB ํฌ๊ธฐ์˜ ๋Œ€ํ˜• ์‚ฌ์ „์—๋งŒ ๋„ฃ์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค๋ฉด, mTHP๋Š” 16KB, 32KB, 64KB ๋“ฑ ๋‹ค์–‘ํ•œ ํฌ๊ธฐ์˜ ์ค‘๊ฐ„ ์‚ฌ์ „๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ž‘์€ ๋ฌธ์„œ๋Š” ์ค‘๊ฐ„ ์‚ฌ์ „์—, ํฐ ๋ฌธ์„œ๋Š” ๋Œ€ํ˜• ์‚ฌ์ „์— ๋„ฃ์–ด ์ฑ…์žฅ ๋„˜๊ธฐ๋Š” ํšŸ์ˆ˜(TLB ๋ฏธ์Šค)๋ฅผ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.
/* ์ฃผ์š” ์†Œ์Šค ํŒŒ์ผ ๊ฒฝ๋กœ */
mm/huge_memory.c          /* mTHP sysfs, order๋ณ„ ์ •์ฑ…, folio ๋ถ„ํ• , ํ†ต๊ณ„ */
mm/khugepaged.c           /* khugepaged ์Šค๋ ˆ๋“œ (PMD_ORDER ์ „์šฉ) */
include/linux/huge_mm.h   /* THP_ORDERS_ALL_* ๋งคํฌ๋กœ, mthp_stat_item, thpsize */
include/linux/page-flags.h /* PG_partially_mapped, PG_large_rmappable */
include/linux/mmzone.h    /* struct deferred_split, NR_PCP_THP */

mTHP Order ๊ด€๋ฆฌ ๊ตฌ์กฐ๋„

mTHP Order ๊ด€๋ฆฌ ๊ตฌ์กฐ๋„

mTHP ํŽ˜์ด์ง€ ํดํŠธ/ํ• ๋‹น ํ๋ฆ„

mTHP ํŽ˜์ด์ง€ ํดํŠธ/ํ• ๋‹น ํ๋ฆ„

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

# mTHP ์ง€์› order ํ™•์ธ (x86_64: order 2~9 = 16KB~2MB)
ls /sys/kernel/mm/transparent_hugepage/
# hugepages-16kB  hugepages-32kB  hugepages-64kB  hugepages-128kB
# hugepages-256kB  hugepages-512kB  hugepages-1024kB  hugepages-2048kB

# ํŠน์ • order์˜ ํ™œ์„ฑํ™” ์ •์ฑ… ํ™•์ธ (์˜ˆ: 64KB = order-4)
cat /sys/kernel/mm/transparent_hugepage/hugepages-64kB/enabled
# [always] inherit madvise never

# order๋ณ„ mTHP ํ†ต๊ณ„ ํ™•์ธ
cat /sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/anon_fault_alloc
cat /sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/anon_fault_fallback
cat /sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/split

# ์ „์ฒด mTHP ํ†ต๊ณ„ (๋ชจ๋“  order)
cat /proc/vmstat | grep -E 'thp_|khugepaged'

# THP ๊ด€๋ จ ์‚ฌ์šฉ๋Ÿ‰๊ณผ ํฐ ํŽ˜์ด์ง€ ์ง€ํ‘œ ํ™•์ธ
grep -E 'AnonHugePages|ShmemHugePages|FileHugePages|HugePages_' /proc/meminfo

# khugepaged ๊ด€๋ จ (PMD_ORDER ์ „์šฉ)
cat /sys/kernel/mm/transparent_hugepage/khugepaged/pages_to_scan
cat /sys/kernel/mm/transparent_hugepage/khugepaged/pages_collapsed

# THP ์ „์—ญ ํ™œ์„ฑํ™” ์ƒํƒœ
cat /sys/kernel/mm/transparent_hugepage/enabled

# ์ปค๋„ ๋ถ€ํŠธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ mTHP ์„ค์ • ํ™•์ธ
cat /proc/cmdline | grep -o 'thp_anon=[^ ]*'

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

1. `THP_ORDERS_ALL_ANON` (order ๋น„ํŠธ๋งˆ์Šคํฌ)

์ต๋ช… ๋ฉ”๋ชจ๋ฆฌ์— ํ—ˆ์šฉ๋˜๋Š” ๋ชจ๋“  mTHP order์˜ ๋น„ํŠธ๋งˆ์Šคํฌ์ž…๋‹ˆ๋‹ค. order-0๊ณผ order-1์€ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค.

/* include/linux/huge_mm.h:79 โ€” ์ต๋ช… mTHP ํ—ˆ์šฉ order ๋น„ํŠธ๋งต */
#define THP_ORDERS_ALL_ANON	((BIT(PMD_ORDER + 1) - 1) & ~(BIT(0) | BIT(1)))
/* include/linux/huge_mm.h:86-89 โ€” ํŠน์ˆ˜/file mTHP ํ—ˆ์šฉ order ๋น„ํŠธ๋งต */
#define THP_ORDERS_ALL_SPECIAL		\
	(BIT(PMD_ORDER) | BIT(PUD_ORDER))
#define THP_ORDERS_ALL_FILE_DEFAULT	\
	((BIT(MAX_PAGECACHE_ORDER + 1) - 1) & ~BIT(0))
/* include/linux/huge_mm.h:94-95 โ€” ์ „์ฒด THP ํ—ˆ์šฉ order ๋น„ํŠธ๋งต */
#define THP_ORDERS_ALL	\
	(THP_ORDERS_ALL_ANON | THP_ORDERS_ALL_SPECIAL | THP_ORDERS_ALL_FILE_DEFAULT)

2. `huge_anon_orders_*` (order๋ณ„ ์ •์ฑ… ๋น„ํŠธ๋งต)

order๋ณ„ THP ํ™œ์„ฑํ™” ์ •์ฑ…์„ ๋น„ํŠธ๋งต์œผ๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ๋น„ํŠธ๋Š” ํ•˜๋‚˜์˜ order๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

/* include/linux/huge_mm.h:181-183 โ€” order๋ณ„ ์ •์ฑ… ๋น„ํŠธ๋งต ์„ ์–ธ */
extern unsigned long huge_anon_orders_always;     /* ํ•ญ์ƒ ์‚ฌ์šฉ */
extern unsigned long huge_anon_orders_madvise;     /* madvise ์‹œ ์‚ฌ์šฉ */
extern unsigned long huge_anon_orders_inherit;     /* ์ƒ์† (๊ธฐ๋ณธ๊ฐ’: PMD_ORDER๋งŒ) */
/* mm/huge_memory.c:790-791 โ€” ๊ธฐ๋ณธ๊ฐ’: PMD_ORDER๋งŒ inherit */
huge_anon_orders_inherit = BIT(PMD_ORDER);

3. `enum mthp_stat_item` (mTHP ํ†ต๊ณ„ ํ•ญ๋ชฉ)

order๋ณ„๋กœ ์ถ”์ ๋˜๋Š” mTHP ์ด๋ฒคํŠธ ํ†ต๊ณ„ ํ•ญ๋ชฉ์ž…๋‹ˆ๋‹ค.

/* include/linux/huge_mm.h:127-146 โ€” mTHP ํ†ต๊ณ„ ํ•ญ๋ชฉ ์—ด๊ฑฐํ˜• */
enum mthp_stat_item {
	MTHP_STAT_ANON_FAULT_ALLOC,         /* ์ต๋ช… ํดํŠธ ์‹œ order๋ณ„ ํ• ๋‹น ์„ฑ๊ณต */
	MTHP_STAT_ANON_FAULT_FALLBACK,      /* ์ต๋ช… ํดํŠธ ์‹œ order๋ณ„ ํด๋ฐฑ */
	MTHP_STAT_ANON_FAULT_FALLBACK_CHARGE, /* ํด๋ฐฑ ํ›„ memcg ์ฒญ๊ตฌ ์‹คํŒจ */
	MTHP_STAT_ZSWPOUT,                  /* order๋ณ„ zswap out */
	MTHP_STAT_SWPIN,                    /* order๋ณ„ swap in */
	MTHP_STAT_SWPIN_FALLBACK,           /* swap in ํด๋ฐฑ */
	MTHP_STAT_SWPIN_FALLBACK_CHARGE,    /* swap in ํด๋ฐฑ ํ›„ ์ฒญ๊ตฌ ์‹คํŒจ */
	MTHP_STAT_SWPOUT,                   /* order๋ณ„ swap out */
	MTHP_STAT_SWPOUT_FALLBACK,          /* swap out ํด๋ฐฑ */
	MTHP_STAT_SHMEM_ALLOC,              /* shmem order๋ณ„ ํ• ๋‹น */
	MTHP_STAT_SHMEM_FALLBACK,           /* shmem ํด๋ฐฑ */
	MTHP_STAT_SHMEM_FALLBACK_CHARGE,    /* shmem ํด๋ฐฑ ํ›„ ์ฒญ๊ตฌ ์‹คํŒจ */
	MTHP_STAT_SPLIT,                    /* order๋ณ„ folio ๋ถ„ํ•  ์„ฑ๊ณต */
	MTHP_STAT_SPLIT_FAILED,             /* folio ๋ถ„ํ•  ์‹คํŒจ */
	MTHP_STAT_SPLIT_DEFERRED,           /* ์ง€์—ฐ ๋ถ„ํ•  */
	MTHP_STAT_NR_ANON,                  /* ํ˜„์žฌ order๋ณ„ ์ต๋ช… large folio ์ˆ˜ */
	MTHP_STAT_NR_ANON_PARTIALLY_MAPPED, /* ๋ถ€๋ถ„ ๋งคํ•‘๋œ ์ต๋ช… folio ์ˆ˜ */
	__MTHP_STAT_COUNT
};

4. `struct mthp_stat` (per-CPU ํ†ต๊ณ„ ๊ตฌ์กฐ์ฒด)

per-CPU๋กœ ๊ด€๋ฆฌ๋˜๋Š” mTHP ํ†ต๊ณ„ ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค. ๊ฐ order๋ณ„๋กœ ๋ชจ๋“  ํ†ต๊ณ„ ํ•ญ๋ชฉ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

/* include/linux/huge_mm.h:149-151 โ€” per-CPU mTHP ํ†ต๊ณ„ ๊ตฌ์กฐ์ฒด */
struct mthp_stat {
	unsigned long stats[ilog2(MAX_PTRS_PER_PTE) + 1][__MTHP_STAT_COUNT];
};

DECLARE_PER_CPU(struct mthp_stat, mthp_stats);

5. `struct thpsize` (sysfs order๋ณ„ kobject)

sysfs์—์„œ ๊ฐ order์˜ THP ํฌ๊ธฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” kobject ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค.

/* include/linux/huge_mm.h:315-321 โ€” THP ํฌ๊ธฐ๋ณ„ sysfs kobject */
struct thpsize {
	struct kobject kobj;
	struct list_head node;
	int order;
};

#define to_thpsize(kobj) container_of(kobj, struct thpsize, kobj)

6. `struct deferred_split` (์ง€์—ฐ ๋ถ„ํ•  ํ)

large folio์˜ ์ง€์—ฐ ๋ถ„ํ• ์„ ๊ด€๋ฆฌํ•˜๋Š” ํ ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค.

/* include/linux/mmzone.h:1341-1345 โ€” ์ง€์—ฐ ๋ถ„ํ•  ํ */
struct deferred_split {
	spinlock_t split_queue_lock;
	struct list_head split_queue;
	unsigned long split_queue_len;
};

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

1. `__thp_vma_allowable_orders()` โ€” VMA๋ณ„ ํ—ˆ์šฉ order ๊ฒฐ์ •

์ง€์ •๋œ VMA์—์„œ ํ—ˆ์šฉ๋˜๋Š” hugepage order ๋น„ํŠธ๋งˆ์Šคํฌ๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ํ•ต์‹ฌ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

/* mm/huge_memory.c:103-211 โ€” VMA๋ณ„ ํ—ˆ์šฉ order ๋น„ํŠธ๋งˆ์Šคํฌ ๊ฒฐ์ • */
unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma,
vm_flags_t vm_flags,
enum tva_type type,
unsigned long orders)

๋ถ„๊ธฐ ๋กœ์ง:

1. VMA ์œ ํ˜•์— ๋”ฐ๋ผ ์ง€์› order ์„ธํŠธ ์„ ํƒ (์ต๋ช…: THP_ORDERS_ALL_ANON, ํŠน์ˆ˜: THP_ORDERS_ALL_SPECIAL, ํŒŒ์ผ: THP_ORDERS_ALL_FILE_DEFAULT)

2. ํ•˜๋“œ์›จ์–ด THP ๋น„ํ™œ์„ฑํ™” ํ™•์ธ

3. VMA ๋น„ํ™œ์„ฑํ™” ํ”Œ๋ž˜๊ทธ ๊ฒ€์‚ฌ (VM_NOHUGEPAGE, VM_DONTEXPAND)

4. DAX/PFNMAP ์ฒ˜๋ฆฌ

5. khugepaged ์ „์šฉ VMA ์ œ์™ธ

6. ์ •๋ ฌ/ํฌ๊ธฐ ์ ํ•ฉ์„ฑ ๊ฒ€์‚ฌ (thp_vma_suitable_order())

7. shmem ์ •์ฑ… ์ ์šฉ

8. ํŒŒ์ผ THP ์š”๊ตฌ์‚ฌํ•ญ ํ™•์ธ (๊ธ€๋กœ๋ฒŒ ํ™œ์„ฑํ™”, VM_HUGEPAGE ํ”Œ๋ž˜๊ทธ, huge_fault() ํ•ธ๋“ค๋Ÿฌ)

2. `setup_thp_anon()` โ€” ๋ถ€ํŠธ ํŒŒ๋ผ๋ฏธํ„ฐ order ์ •์ฑ… ์„ค์ •

์ปค๋„ ๋ถ€ํŠธ ํŒŒ๋ผ๋ฏธํ„ฐ thp_anon=๋ฅผ ํŒŒ์‹ฑํ•˜์—ฌ order๋ณ„ ์ •์ฑ…์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

/* mm/huge_memory.c:991-1074 โ€” thp_anon= ๋ถ€ํŠธ ํŒŒ๋ผ๋ฏธํ„ฐ ํŒŒ์„œ */
static int __init setup_thp_anon(char *str)

๋ถ„๊ธฐ ๋กœ์ง:

1. ํฌ๊ธฐ ๋ฌธ์ž์—ด์„ order๋กœ ๋ณ€ํ™˜ (get_order_from_str())

2. ์ •์ฑ… ๋ฌธ์ž์—ด ํŒŒ์‹ฑ (always, madvise, inherit, never)

3. huge_anon_orders_always/madvise/inherit ๋น„ํŠธ๋งต ์—…๋ฐ์ดํŠธ

4. anon_orders_configured = true ์„ค์ •

3. `do_huge_pmd_anonymous_page()` โ€” PMD ์ˆ˜์ค€ ์ต๋ช… ํŽ˜์ด์ง€ ํดํŠธ ์ฒ˜๋ฆฌ

PMD ์ˆ˜์ค€์˜ ์ต๋ช… ํŽ˜์ด์ง€ ํดํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. zero page ์ตœ์ ํ™”์™€ ์ผ๋ฐ˜ ํ• ๋‹น ๊ฒฝ๋กœ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

/* mm/huge_memory.c:1461-1516 โ€” PMD ์ต๋ช… ํŽ˜์ด์ง€ ํดํŠธ ์ง„์ž…์  */
vm_fault_t do_huge_pmd_anonymous_page(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
unsigned long haddr = vmf->address & HPAGE_PMD_MASK;
vm_fault_t ret;

if (!thp_vma_suitable_order(vma, haddr, PMD_ORDER))
return VM_FAULT_FALLBACK;
ret = vmf_anon_prepare(vmf);
if (ret)
return ret;
khugepaged_enter_vma(vma, vma->vm_flags);

if (!(vmf->flags & FAULT_FLAG_WRITE) &&
!mm_forbids_zeropage(vma->vm_mm) &&
transparent_hugepage_use_zero_page()) {
pgtable_t pgtable;
struct folio *zero_folio;
vm_fault_t ret;

pgtable = pte_alloc_one(vma->vm_mm);
if (unlikely(!pgtable))
return VM_FAULT_OOM;
zero_folio = mm_get_huge_zero_folio(vma->vm_mm);
if (unlikely(!zero_folio)) {
pte_free(vma->vm_mm, pgtable);
count_vm_event(THP_FAULT_FALLBACK);
return VM_FAULT_FALLBACK;
}
vmf->ptl = pmd_lock(vma->vm_mm, vmf->pmd);
ret = 0;
if (pmd_none(*vmf->pmd)) {
ret = check_stable_address_space(vma->vm_mm);
if (ret) {
spin_unlock(vmf->ptl);
pte_free(vma->vm_mm, pgtable);
} else if (userfaultfd_missing(vma)) {
spin_unlock(vmf->ptl);
pte_free(vma->vm_mm, pgtable);
ret = handle_userfault(vmf, VM_UFFD_MISSING);
VM_BUG_ON(ret & VM_FAULT_FALLBACK);
} else {
set_huge_zero_folio(pgtable, vma->vm_mm, vma,
haddr, vmf->pmd, zero_folio);
update_mmu_cache_pmd(vma, vmf->address, vmf->pmd);
spin_unlock(vmf->ptl);
}
} else {
spin_unlock(vmf->ptl);
pte_free(vma->vm_mm, pgtable);
}
return ret;
}

return __do_huge_pmd_anonymous_page(vmf);
}

๋ถ„๊ธฐ ๋กœ์ง:

1. thp_vma_suitable_order()๋กœ VMA ์ •๋ ฌ/ํฌ๊ธฐ ๊ฒ€์‚ฌ

2. vmf_anon_prepare()๋กœ anon_vma ์ดˆ๊ธฐํ™”

3. khugepaged_enter_vma()๋กœ khugepaged ์Šค์บ” ๋Œ€์ƒ ๋“ฑ๋ก

4. ์ฝ๊ธฐ ์ „์šฉ + zero page ๊ฐ€๋Šฅ ์‹œ set_huge_zero_folio() ํ˜ธ์ถœ

5. ์ผ๋ฐ˜ ๊ฒฝ๋กœ: __do_huge_pmd_anonymous_page() ํ˜ธ์ถœ

4. `__do_huge_pmd_anonymous_page()` โ€” ์‹ค์ œ large folio ํ• ๋‹น ๋ฐ ๋งคํ•‘

PMD ์ˆ˜์ค€ large folio๋ฅผ ํ• ๋‹นํ•˜๊ณ  ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์— ๋งคํ•‘ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

/* mm/huge_memory.c:1323-1373 โ€” PMD large folio ํ• ๋‹น ๋ฐ ๋งคํ•‘ */
static vm_fault_t __do_huge_pmd_anonymous_page(struct vm_fault *vmf)
{
unsigned long haddr = vmf->address & HPAGE_PMD_MASK;
struct vm_area_struct *vma = vmf->vma;
struct folio *folio;
pgtable_t pgtable;
vm_fault_t ret = 0;

folio = vma_alloc_anon_folio_pmd(vma, vmf->address);
if (unlikely(!folio))
return VM_FAULT_FALLBACK;

pgtable = pte_alloc_one(vma->vm_mm);
if (unlikely(!pgtable)) {
ret = VM_FAULT_OOM;
goto release;
}

vmf->ptl = pmd_lock(vma->vm_mm, vmf->pmd);
if (unlikely(!pmd_none(*vmf->pmd))) {
goto unlock_release;
} else {
ret = check_stable_address_space(vma->vm_mm);
if (ret)
goto unlock_release;

/* ํŽ˜์ด์ง€ ํดํŠธ๋ฅผ ์‚ฌ์šฉ์ž ๊ณต๊ฐ„์— ์ „๋‹ฌ */
if (userfaultfd_missing(vma)) {
spin_unlock(vmf->ptl);
folio_put(folio);
pte_free(vma->vm_mm, pgtable);
ret = handle_userfault(vmf, VM_UFFD_MISSING);
VM_BUG_ON(ret & VM_FAULT_FALLBACK);
return ret;
}
pgtable_trans_huge_deposit(vma->vm_mm, vmf->pmd, pgtable);
map_anon_folio_pmd_pf(folio, vmf->pmd, vma, haddr);
mm_inc_nr_ptes(vma->vm_mm);
spin_unlock(vmf->ptl);
}

return 0;
unlock_release:
spin_unlock(vmf->ptl);
release:
if (pgtable)
pte_free(vma->vm_mm, pgtable);
folio_put(folio);
return ret;
}

๋ถ„๊ธฐ ๋กœ์ง:

1. vma_alloc_anon_folio_pmd()๋กœ order๋ณ„ large folio ํ• ๋‹น

2. pte_alloc_one()์œผ๋กœ ํ•˜์œ„ PTE ํ…Œ์ด๋ธ” ํ• ๋‹น

3. PMD ๋ฝ ํš๋“ ํ›„ pmd_none() ๊ฒ€์‚ฌ

4. check_stable_address_space()์œผ๋กœ ์•ˆ์ •์  ์ฃผ์†Œ ๊ณต๊ฐ„ ํ™•์ธ

5. userfaultfd_missing() ์‹œ userfaultfd ํ•ธ๋“ค๋Ÿฌ ํ˜ธ์ถœ

6. pgtable_trans_huge_deposit() + map_anon_folio_pmd_pf()๋กœ ๋งคํ•‘

5. `do_huge_pmd_wp_page()` โ€” PMD ์ˆ˜์ค€ COW (Copy-on-Write) ์ฒ˜๋ฆฌ

PMD ์ˆ˜์ค€ large folio์˜ COW๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

/* mm/huge_memory.c:2060-2152 โ€” PMD COW ์ฒ˜๋ฆฌ */
vm_fault_t do_huge_pmd_wp_page(struct vm_fault *vmf)
{
const bool unshare = vmf->flags & FAULT_FLAG_UNSHARE;
struct vm_area_struct *vma = vmf->vma;
struct page *page;
struct folio *folio;
unsigned long haddr = vmf->address & HPAGE_PMD_MASK;
pmd_t orig_pmd = vmf->orig_pmd;

vmf->ptl = pmd_lockptr(vma->vm_mm, vmf->pmd);
VM_BUG_ON_VMA(!vma->anon_vma, vma);

if (is_huge_zero_pmd(orig_pmd)) {
vm_fault_t ret = do_huge_zero_wp_pmd(vmf);

if (!(ret & VM_FAULT_FALLBACK))
return ret;

/* THP๋ฅผ ํ• ๋‹นํ•  ์ˆ˜ ์—†์œผ๋ฉด PMD ๋ถ„ํ• ๋กœ ํด๋ฐฑ */
goto fallback;
}

spin_lock(vmf->ptl);

if (unlikely(!pmd_same(*vmf->pmd, orig_pmd))) {
spin_unlock(vmf->ptl);
return 0;
}

page = pmd_page(orig_pmd);
folio = page_folio(page);
VM_BUG_ON_PAGE(!PageHead(page), page);

/* PT ๋ฝ๋งŒ ์žก์•˜์„ ๋•Œ์˜ ์กฐ๊ธฐ ๊ฒ€์‚ฌ */
if (PageAnonExclusive(page))
goto reuse;

if (!folio_trylock(folio)) {
folio_get(folio);
spin_unlock(vmf->ptl);
folio_lock(folio);
spin_lock(vmf->ptl);
if (unlikely(!pmd_same(*vmf->pmd, orig_pmd))) {
spin_unlock(vmf->ptl);
folio_unlock(folio);
folio_put(folio);
return 0;
}
folio_put(folio);
}

/* ์ž ๊น PT ๋ฝ์„ ๋‚ด๋ ค๋†“์€ ๋’ค ๋‹ค์‹œ ๊ฒ€์‚ฌ */
if (PageAnonExclusive(page)) {
folio_unlock(folio);
goto reuse;
}

/* do_wp_page()์ฒ˜๋Ÿผ ์ถ”๊ฐ€ ์ฐธ์กฐ๊ฐ€ ์—†์„ ๋•Œ๋งŒ ๋…์  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ */
if (folio_ref_count(folio) >
1 + folio_test_swapcache(folio) * folio_nr_pages(folio))
goto unlock_fallback;
if (folio_test_swapcache(folio))
folio_free_swap(folio);
if (folio_ref_count(folio) == 1) {
pmd_t entry;

folio_move_anon_rmap(folio, vma);
SetPageAnonExclusive(page);
folio_unlock(folio);
reuse:
if (unlikely(unshare)) {
spin_unlock(vmf->ptl);
return 0;
}
entry = pmd_mkyoung(orig_pmd);
entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
if (pmdp_set_access_flags(vma, haddr, vmf->pmd, entry, 1))
update_mmu_cache_pmd(vma, vmf->address, vmf->pmd);
spin_unlock(vmf->ptl);
return 0;
}

unlock_fallback:
folio_unlock(folio);
spin_unlock(vmf->ptl);
fallback:
/* PMD๋ฅผ 4KB PTE๋กœ ๋ถ„ํ•  ํ›„ ํด๋ฐฑ */
__split_huge_pmd(vma, vmf->pmd, vmf->address, false);
return VM_FAULT_FALLBACK;
}

๋ถ„๊ธฐ ๋กœ์ง:

1. is_huge_zero_pmd()๋กœ zero PMD ๊ฒ€์‚ฌ

2. PageAnonExclusive()๋กœ exclusive ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ ํ™•์ธ

3. folio_ref_count()๋กœ ์ฐธ์กฐ ์นด์šดํŠธ ๊ฒ€์‚ฌ (1์ด๋ฉด exclusive)

4. exclusive ๊ฐ€๋Šฅ ์‹œ pmd_mkyoung() + maybe_pmd_mkwrite()๋กœ ์ ‘๊ทผ/์“ฐ๊ธฐ ํ”Œ๋ž˜๊ทธ ์—…๋ฐ์ดํŠธ

5. ๋ถˆ๊ฐ€๋Šฅ ์‹œ __split_huge_pmd()๋กœ PMD ๋ถ„ํ•  ํ›„ VM_FAULT_FALLBACK ๋ฐ˜ํ™˜

6. `anon_enabled_show()` / `anon_enabled_store()` โ€” sysfs order๋ณ„ ์ •์ฑ… ์ œ์–ด

sysfs ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด order๋ณ„ THP ํ™œ์„ฑํ™” ์ •์ฑ…์„ ์ฝ๊ณ  ์”๋‹ˆ๋‹ค.

/* mm/huge_memory.c:500-563 โ€” sysfs order๋ณ„ enabled ์ œ์–ด */
static ssize_t anon_enabled_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t anon_enabled_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count);

๋™์ž‘:

  • show: [always], [inherit], [madvise], [never] ์ค‘ ํ˜„์žฌ ์ •์ฑ… ๋ฐ˜ํ™˜
  • store: ์ •์ฑ… ๋ฌธ์ž์—ด ํŒŒ์‹ฑ ํ›„ huge_anon_orders_always/madvise/inherit ๋น„ํŠธ๋งต ์—…๋ฐ์ดํŠธ, start_stop_khugepaged() ํ˜ธ์ถœ
  • 4. `deferred_split_folio()` โ€” large folio ์ง€์—ฐ ๋ถ„ํ•  ํ ๋“ฑ๋ก

    large folio๋ฅผ ์ง€์—ฐ ๋ถ„ํ•  ํ์— ๋“ฑ๋กํ•˜์—ฌ ์ดํ›„ shrinker์— ์˜ํ•ด ๋ถ„ํ• ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

    /* mm/huge_memory.c:4315-4365 โ€” ์ง€์—ฐ ๋ถ„ํ•  ํ ๋“ฑ๋ก */
    void deferred_split_folio(struct folio *folio, bool partially_mapped)

    ๋ถ„๊ธฐ ๋กœ์ง:

    1. order โ‰ค 1 folio๋Š” ํ์— ๋„ฃ์ง€ ์•Š์Œ (๊ณต๊ฐ„ ๋ถ€์กฑ)

    2. folio_test_large() ๊ฒ€์‚ฌ

    3. partially_mapped ํ”Œ๋ž˜๊ทธ ์„ค์ • ์‹œ MTHP_STAT_NR_ANON_PARTIALLY_MAPPED ์ฆ๊ฐ€

    4. MTHP_STAT_SPLIT_DEFERRED ํ†ต๊ณ„ ์—…๋ฐ์ดํŠธ

    5. `folio_check_splittable()` โ€” folio ๋ถ„ํ•  ๊ฐ€๋Šฅ ๊ฒ€์‚ฌ

    folio๊ฐ€ ์ง€์ •๋œ order๋กœ ๋ถ„ํ•  ๊ฐ€๋Šฅํ•œ์ง€ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.

    /* mm/huge_memory.c:3708-3769 โ€” folio ๋ถ„ํ•  ๊ฐ€๋Šฅ์„ฑ ๊ฒ€์‚ฌ */
    int folio_check_splittable(struct folio *folio, unsigned int new_order,
    enum split_type split_type)

    ๋ถ„๊ธฐ ๋กœ์ง:

    1. order-1 ์ต๋ช… folio ๋ถ„ํ•  ๊ฑฐ๋ถ€ (-EINVAL)

    2. ํŒŒ์ผ ๊ธฐ๋ฐ˜ folio: mapping_large_folio_support() ๊ฒ€์‚ฌ

    3. swapcache folio: non-zero order ๋ถ„ํ•  ๊ฑฐ๋ถ€

    4. non-uniform ๋ถ„ํ•  ์‹œ ์ถ”๊ฐ€ ๊ฒ€์‚ฌ


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

    mTHP ํŽ˜์ด์ง€ ํดํŠธ ๊ฒฝ๋กœ

    ์‚ฌ์šฉ์ž ํŽ˜์ด์ง€ ํดํŠธ (PMD ์ˆ˜์ค€)
    โ†’ handle_mm_fault()
    โ†’ __handle_mm_fault()
    โ†’ handle_pte_fault()
    โ†’ do_anonymous_page()
    โ†’ vma_alloc_anon_folio()  โ† order ์„ ํƒ
    โ†’ thp_vma_allowable_orders()  โ† ํ—ˆ์šฉ order ๋น„ํŠธ๋งˆ์Šคํฌ ๊ฒฐ์ •
    โ†’ __thp_vma_allowable_orders()  โ† VMA๋ณ„ ํ•„ํ„ฐ๋ง
    โ†’ alloc_folio(gfp, order)  โ† order๋ณ„ large folio ํ• ๋‹น
    โ†’ finish_fault()
    โ†’ do_set_pte()  โ† PTE ์„ค์ •
    
    ์‚ฌ์šฉ์ž ํŽ˜์ด์ง€ ํดํŠธ (PMD ์ˆ˜์ค€ large folio)
    โ†’ handle_mm_fault()
    โ†’ __handle_mm_fault()
    โ†’ handle_pte_fault()
    โ†’ do_huge_pmd_anonymous_page()  โ† PMD ์ง„์ž…์  (huge_memory.c:1461)
    โ†’ thp_vma_suitable_order()  โ† VMA ์ •๋ ฌ/ํฌ๊ธฐ ๊ฒ€์‚ฌ
    โ†’ vmf_anon_prepare()  โ† anon_vma ์ดˆ๊ธฐํ™”
    โ†’ khugepaged_enter_vma()  โ† khugepaged ์Šค์บ” ๋Œ€์ƒ ๋“ฑ๋ก
    โ†’ __do_huge_pmd_anonymous_page()  โ† ์‹ค์ œ ํ• ๋‹น (huge_memory.c:1323)
    โ†’ vma_alloc_anon_folio_pmd()  โ† order๋ณ„ large folio ํ• ๋‹น
    โ†’ pte_alloc_one()  โ† ํ•˜์œ„ PTE ํ…Œ์ด๋ธ” ํ• ๋‹น
    โ†’ pmd_lock()  โ† PMD ๋ฝ
    โ†’ check_stable_address_space()  โ† ์•ˆ์ •์  ์ฃผ์†Œ ๊ณต๊ฐ„ ํ™•์ธ
    โ†’ pgtable_trans_huge_deposit()  โ† PTE ํ…Œ์ด๋ธ” ๋ฐฐํฌ
    โ†’ map_anon_folio_pmd_pf()  โ† PMD์— large folio ๋งคํ•‘
    
    ์‚ฌ์šฉ์ž COW ํดํŠธ (PMD ์ˆ˜์ค€)
    โ†’ handle_mm_fault()
    โ†’ __handle_mm_fault()
    โ†’ handle_pte_fault()
    โ†’ do_wp_page()
    โ†’ do_huge_pmd_wp_page()  โ† PMD COW ์ฒ˜๋ฆฌ (huge_memory.c:2060)
    โ†’ is_huge_zero_pmd()  โ† zero PMD ๊ฒ€์‚ฌ
    โ†’ PageAnonExclusive()  โ† exclusive ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ ํ™•์ธ
    โ†’ folio_ref_count()  โ† ์ฐธ์กฐ ์นด์šดํŠธ ๊ฒ€์‚ฌ
    โ†’ pmd_mkyoung() + maybe_pmd_mkwrite()  โ† ์ ‘๊ทผ/์“ฐ๊ธฐ ํ”Œ๋ž˜๊ทธ
    โ†’ __split_huge_pmd()  โ† PMD ๋ถ„ํ•  (๋ถˆ๊ฐ€๋Šฅ ์‹œ)

    mTHP sysfs ์ œ์–ด ๊ฒฝ๋กœ

    ์‚ฌ์šฉ์ž: echo always > /sys/kernel/mm/transparent_hugepage/hugepages-64kB/enabled
    โ†’ anon_enabled_store()
    โ†’ parsing: "always"
    โ†’ set_bit(order, &huge_anon_orders_always)
    โ†’ clear_bit(order, &huge_anon_orders_madvise)
    โ†’ clear_bit(order, &huge_anon_orders_inherit)
    โ†’ start_stop_khugepaged()  โ† khugepaged ์‹œ์ž‘/์ค‘์ง€

    mTHP folio ๋ถ„ํ•  ๊ฒฝ๋กœ

    large folio ๋ถ„ํ•  ํ•„์š”
    โ†’ deferred_split_folio()
    โ†’ list_add(&folio->deferred_list, &nm->deferred_split_queue)
    โ†’ count_mthp_stat(order, MTHP_STAT_SPLIT_DEFERRED)
    
    shrinker ์Šค์บ” ์‹œ
    โ†’ deferred_split_scan()
    โ†’ folio_split() / split_folio_to_order()
    โ†’ __folio_split()
    โ†’ __folio_freeze_and_split_unmapped()
    โ†’ __split_unmapped_folio()
    โ†’ __split_folio_to_order()  โ† ์‹ค์ œ ๋ถ„ํ• 

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

    mTHP vs ๊ธฐ์กด THP ๋น„๊ต

    ํ•ญ๋ชฉ๊ธฐ์กด THPmTHP
    ์ง€์› orderPMD_ORDER (9)๋งŒorder 2~9 (16KB~2MB)
    ๊ธฐ๋ณธ ํ™œ์„ฑํ™”global always/madviseorder๋ณ„ ๊ฐœ๋ณ„ ์ •์ฑ…
    sysfs ์ธํ„ฐํŽ˜์ด์Šค`/sys/kernel/mm/transparent_hugepage/enabled``/sys/kernel/mm/transparent_hugepage/hugepages-XkB/enabled`
    khugepaged ๋ณ‘ํ•ฉPMD_ORDER ์ „์šฉPMD_ORDER๋งŒ ์ง€์› (sub-PMD ๋ฏธ๊ตฌํ˜„)
    per-CPU ํ†ต๊ณ„์—†์Œorder๋ณ„ 17์ข… ํ†ต๊ณ„
    ์ง€์—ฐ ๋ถ„ํ• PMD folio๋งŒorder 2+ ๋ชจ๋“  large folio
    TLB ํšจ์œจ2MB ํ•˜๋‚˜๋กœ ๋งคํ•‘ํฌ๊ธฐ๋ณ„ ์ตœ์  ๋งคํ•‘

    order๋ณ„ ํฌ๊ธฐ ๋ฐ ํŠน์„ฑ ๋น„๊ต

    orderํฌ๊ธฐx86_64 PTE ์ˆ˜sysfs ์ด๋ฆ„์ฃผ์š” ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค
    216KB4hugepages-16kB์†Œ๊ทœ๋ชจ large folio, ์ปจํ…Œ์ด๋„ˆ
    332KB8hugepages-32kB์ค‘๊ฐ„ ํฌ๊ธฐ I/O ์ตœ์ ํ™”
    464KB16hugepages-64kB์ผ๋ฐ˜์ ์ธ mTHP ์‚ฌ์šฉ
    5128KB32hugepages-128kB๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
    6256KB64hugepages-256kB๋Œ€๊ทœ๋ชจ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ
    7512KB128hugepages-512kB๋งค์šฐ ํฐ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ
    81MB256hugepages-1024kBTHP ๊ทผ์‚ฌ
    92MB512hugepages-2048kBclassic THP (PMD ํฌ๊ธฐ)

    mTHP ์ •์ฑ… ๋ชจ๋“œ ๋น„๊ต

    ์ •์ฑ…๋™์ž‘๋น„ํŠธ๋งต์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค
    `always`๋ชจ๋“  ํดํŠธ์—์„œ ํ•ด๋‹น order ์‚ฌ์šฉ`huge_anon_orders_always`์„ฑ๋Šฅ ์šฐ์„ , ๋ฉ”๋ชจ๋ฆฌ ์—ฌ์œ  ์‹œ
    `madvise``MADV_HUGEPAGE` ์ ์šฉ ์‹œ์—๋งŒ ์‚ฌ์šฉ`huge_anon_orders_madvise`ํŠน์ • ํ”„๋กœ์„ธ์Šค๋งŒ ์ตœ์ ํ™”
    `inherit`VMA ํ”Œ๋ž˜๊ทธ ์ƒ์†`huge_anon_orders_inherit`๊ธฐ๋ณธ๊ฐ’ (PMD๋งŒ ์ƒ์†)
    `never`ํ•ด๋‹น order ์‚ฌ์šฉ ์•ˆ ํ•จ๋น„ํŠธ๋งต์—์„œ ์ œ์™ธ๋ฉ”๋ชจ๋ฆฌ ์ ˆ์•ฝ, ์ถฉ๋Œ ํšŒํ”ผ

    mTHP vs HugeTLB vs shmem THP ๋น„๊ต

    ํ•ญ๋ชฉmTHPHugeTLBshmem THP
    ํ• ๋‹น ์‹œ์ ํดํŠธ ์‹œ ๋™์ ๋ถ€ํŒ… ์‹œ ์‚ฌ์ „ ์˜ˆ์•ฝํดํŠธ ์‹œ ๋™์ 
    ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋น„ํ•„์š” ์‹œ๋งŒ์‚ฌ์ „ ์˜ˆ์•ฝํ•„์š” ์‹œ๋งŒ
    ์Šค์™‘ ๊ฐ€๋Šฅ๊ฐ€๋Šฅ๋ถˆ๊ฐ€๊ฐ€๋Šฅ
    ํŒŒ์ผ ๋งคํ•‘๋ถˆ๊ฐ€๊ฐ€๋Šฅtmpfs ์ „์šฉ
    ์ปจํ…Œ์ด๋„ˆ ์ง€์›์ข‹์Œ์ œํ•œ์ ์ข‹์Œ
    TLB ํšจ์œจ์ค‘๊ฐ„~๋†’์Œ๋†’์Œ์ค‘๊ฐ„~๋†’์Œ

    mTHP ํ™œ์„ฑํ™” ๋ฐฉ๋ฒ•

    1. ๋ถ€ํŠธ ํŒŒ๋ผ๋ฏธํ„ฐ

    # ๋ชจ๋“  order๋ฅผ always๋กœ ํ™œ์„ฑํ™”
    thp_anon=always:all
    
    # ํŠน์ • order๋งŒ madvise๋กœ ํ™œ์„ฑํ™” (64KB, 128KB)
    thp_anon=madvise:64k,128k
    
    # PMD๋งŒ always, ๋‚˜๋จธ์ง€ never
    thp_anon=always:2m

    2. sysfs ๋™์  ์„ค์ •

    # 64KB mTHP๋ฅผ always๋กœ ํ™œ์„ฑํ™”
    echo always > /sys/kernel/mm/transparent_hugepage/hugepages-64kB/enabled
    
    # 128KB mTHP๋ฅผ madvise๋กœ ์„ค์ •
    echo madvise > /sys/kernel/mm/transparent_hugepage/hugepages-128kB/enabled
    
    # ๋ชจ๋“  sub-PMD order๋ฅผ never๋กœ ๋น„ํ™œ์„ฑํ™”
    for sz in 16kB 32kB 64kB 128kB 256kB 512kB 1024kB; do
    echo never > /sys/kernel/mm/transparent_hugepage/hugepages-${sz}/enabled
    done

    3. ํ”„๋กœ์„ธ์Šค๋ณ„ madvise

    /* ํŠน์ • VMA์— mTHP ์ ์šฉ */
    madvise(addr, length, MADV_HUGEPAGE);  /* allow๋œ order ๋ชจ๋‘ ์‚ฌ์šฉ */
    
    /* mTHP ๋น„ํ™œ์„ฑํ™” */
    madvise(addr, length, MADV_NOHUGEPAGE);

    mTHP ํ†ต๊ณ„ ํ•ด์„

    ํ†ต๊ณ„ ํ•ญ๋ชฉ์„ค๋ช…๋†’์€ ๊ฐ’์˜ ์˜๋ฏธ
    `anon_fault_alloc`order๋ณ„ ํ• ๋‹น ์„ฑ๊ณต ์ˆ˜ํ•ด๋‹น order๊ฐ€ ํ™œ๋ฐœํ•˜๊ฒŒ ์‚ฌ์šฉ๋จ
    `anon_fault_fallback`smaller order๋กœ ํด๋ฐฑ ์ˆ˜ํฐ order ํ• ๋‹น ์‹คํŒจ ๋นˆ๋ฒˆ
    `anon_fault_fallback_charge`ํด๋ฐฑ ํ›„ memcg ์ฒญ๊ตฌ ์‹คํŒจ๋ฉ”๋ชจ๋ฆฌ ์••๋ฐ•
    `split`๋ถ„ํ•  ์„ฑ๊ณต ์ˆ˜large folio๊ฐ€ ์ชผ๊ฐœ์ง€๋Š” ๋นˆ๋„
    `split_deferred`์ง€์—ฐ ๋ถ„ํ•  ํ ๋“ฑ๋ก ์ˆ˜partially-mapped folio ์ฆ๊ฐ€
    `nr_anon`ํ˜„์žฌ order๋ณ„ large folio ์ˆ˜๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ ํŒจํ„ด
    `nr_anon_partially_mapped`๋ถ€๋ถ„ ๋งคํ•‘ folio ์ˆ˜๋ถ„ํ•  ํ•„์š”์„ฑ ์ง€ํ‘œ

    ๊ด€๋ จ ๋ฌธ์„œ

  • Huge Pages / THP โ€” classic THP ๋ฐ khugepaged ์ƒ์„ธ
  • VMA / mmap โ€” ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ ๊ด€๋ฆฌ
  • Folio / Page Cache โ€” folio ์ถ”์ƒํ™” ๋ฐ ํŽ˜์ด์ง€ ์บ์‹œ
  • Compaction โ€” ๋ฉ”๋ชจ๋ฆฌ ๋‹จํŽธํ™” ํ•ด์†Œ
  • ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š” โ€” ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์กฐ๊ฐ๋„
  • Page Reclaim โ€” ํŽ˜์ด์ง€ ํšŒ์ˆ˜ ๋ฐ kswapd
  • Memory Cgroup โ€” ๋ฉ”๋ชจ๋ฆฌ ์ œ์–ด ๊ทธ๋ฃน