๏ปฟ# Page Table Walk ๐ถ
๊ด๋ จ ์์ค:mm/pagewalk.c,include/linux/pagewalk.h,mm/internal.h
๊ฐ์ (Overview)
Linux ์ปค๋์ Page Table Walk๋ ๊ฐ์ ์ฃผ์ ๊ณต๊ฐ์ ์ํํ๋ฉด์ ๊ฐ ํ์ด์ง ํ
์ด๋ธ ์ํธ๋ฆฌ(PGD, P4D, PUD, PMD, PTE)์ ๋ํด ์ฝ๋ฐฑ์ ํธ์ถํ๋ ํ๋ ์์ํฌ์
๋๋ค. walk_page_range()๋ฅผ ํตํด ํธ์ถ์๋ ์ง์ ๋ ๊ฐ์ ์ฃผ์ ๋ฒ์ ๋ด ๋ชจ๋ ํ์ด์ง ํ
์ด๋ธ ๋ ๋ฒจ์ ์ํํ๋ฉด์ ๊ฐ ์ํธ๋ฆฌ๋ง๋ค pte_entry, pmd_entry, pud_entry ๊ฐ์ ์ฝ๋ฐฑ์ ์คํํ ์ ์์ต๋๋ค. ์ด ํ๋ ์์ํฌ๋ mlock, madvise, mincore, mprotect, KSM, DAMON, memory-failure ๋ฑ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ์๋ธ์์คํ
์ ๋ฐ์์ ์ฌ์ฉ๋ฉ๋๋ค.
ํ์ด์ง ํ
์ด๋ธ ๊ตฌ์กฐ๋ ์ํคํ
์ฒ์ ๋ฐ๋ผ 4๋จ๊ณ(PGDโPUDโPMDโPTE) ๋๋ 5๋จ๊ณ(PGDโP4DโPUDโPMDโPTE)๋ก ๊ตฌ์ฑ๋๋ฉฐ, p4d/pud ์์ค์ ์ํคํ
์ฒ์ ๋ฐ๋ผ fold๋ ์ ์์ต๋๋ค. pagewalk ํ๋ ์์ํฌ๋ real_depth() ํจ์๋ฅผ ํตํด fold๋ ๋ ๋ฒจ์ ๋ณด์ ํ์ฌ ์ ํํ ๊น์ด ์ ๋ณด๋ฅผ ์ฝ๋ฐฑ์ ์ ๋ฌํฉ๋๋ค. ๋์๊ด์ผ๋ก ๋น์ ํ๋ฉด, ์ด ํ๋ ์์ํฌ๋ ์๊ฐ ๋ฒํธ๋ฅผ ํ๋์ฉ ๋ฐ๋ผ๊ฐ๋ฉฐ ์ฑ
์ด ์๋ ์นธ๋ง ํ์ธํ๋ ์ฌ์์ ๋น์ทํฉ๋๋ค. Linux 7.0์์๋ folio_walk_start() API๊ฐ ์ถ๊ฐ๋์ด, ๋จ์ผ ๊ฐ์ ์ฃผ์์์ ํด๋นํ๋ folio๋ฅผ ์ง์ ์ฐพ์ PTL(PTE Lock)์ ํ๋ํ๋ ๊ฐ๊ฒฐํ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค. ํ์ด์ง ํดํธ ์ฒ๋ฆฌ๊ธฐ์ ๊ฐ์ ๊ฒฝ๋ก๋ฅผ ์ง์ ๋์ฒดํ๋ ๊ฒ์ ์๋๊ณ , ์ด๋ฏธ ๋ง๋ค์ด์ง ๋งคํ์ ๋ค๋ฅธ ์๋ธ์์คํ
์ด ์์ ํ๊ฒ ํ๊ฑฐ๋ ์กฐ์ ํ ๋ ์ฃผ๋ก ์ฐ์
๋๋ค.
์์ค ํ์ผ ๊ฒฝ๋ก
mm/pagewalk.c โ ๋ฉ์ธ ๊ตฌํ (1050์ค)
include/linux/pagewalk.h โ API ์ ์ (207์ค)
mm/internal.h โ _unsafe() ํจ์ ์ ์ธ
include/linux/leafops.h โ softleaf ํ์
/ํ๋๊ทธ
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
# 1. pagewalk ๊ด๋ จ ์ปค๋ ์ฌ๋ณผ ํ์ธ
cat /proc/kallsyms | grep -E "walk_page|folio_walk"
# 2. ์ปค๋ ํ์ด์ง ํ
์ด๋ธ ๊ตฌ์กฐ (x86_64 4-level)
ls /sys/kernel/mm/page_tables/
# 3. pagewalk์ด ์ฌ์ฉ๋ ๋ชจ๋/API ํธ์ถ๋ถ grep
grep -rn "walk_page_range\|walk_page_vma\|folio_walk_start" mm/
# 4. ํ์ฌ ํ๋ก์ธ์ค์ ํ์ด์ง ํ
์ด๋ธ ๋ ๋ฒจ ํ์ธ (x86_64)
cat /proc/cpuinfo | grep "page table" || echo "4-level" # ๊ธฐ๋ณธ 4-level
# 5. pte_offset_map_lock ๋ฑ ํ์ด์ง ํ
์ด๋ธ ์ก์ธ์ค ํจ์ ์ฌ์ฉ ํ์ธ
grep -rn "pte_offset_map\|pmd_offset\|pud_offset\|pgd_offset" mm/
# 6. CONFIG_PGTABLE_HAS_HUGE_LEAVES ํ์ฑํ ์ฌ๋ถ
grep "PGTABLE_HAS_HUGE_LEAVES" /boot/config-$(uname -r) 2>/dev/null
# 7. pagewalk ๊ด๋ จ ํธ์ถ๋ถ ์ ์ฒด ํ์ธ
grep -rn "walk_page_range\|walk_page_range_vma\|walk_page_mapping\|folio_walk_start" mm/
# 8. ์ปค๋ ํ์ด์ง ํ
์ด๋ธ ๋คํ ํ์ธ
cat /sys/kernel/debug/kernel_page_tables 2>/dev/null | head -40
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
struct mm_walk_ops
์ฝ๋ฐฑ ํจ์ ํฌ์ธํฐ ํ ์ด๋ธ โ ํธ์ถ์๊ฐ ์ํ ๋์์ ์ปค์คํฐ๋ง์ด์งํฉ๋๋ค.
// include/linux/pagewalk.h:70-94
struct mm_walk_ops {
int (*pgd_entry)(pgd_t *pgd, unsigned long addr,
unsigned long next, struct mm_walk *walk);
int (*p4d_entry)(p4d_t *p4d, unsigned long addr,
unsigned long next, struct mm_walk *walk);
int (*pud_entry)(pud_t *pud, unsigned long addr,
unsigned long next, struct mm_walk *walk);
int (*pmd_entry)(pmd_t *pmd, unsigned long addr,
unsigned long next, struct mm_walk *walk);
int (*pte_entry)(pte_t *pte, unsigned long addr,
unsigned long next, struct mm_walk *walk);
int (*pte_hole)(unsigned long addr, unsigned long next,
int depth, struct mm_walk *walk);
int (*hugetlb_entry)(pte_t *pte, unsigned long hmask,
unsigned long addr, unsigned long next,
struct mm_walk *walk);
int (*test_walk)(unsigned long addr, unsigned long next,
struct mm_walk *walk);
int (*pre_vma)(unsigned long start, unsigned long end,
struct mm_walk *walk);
void (*post_vma)(struct mm_walk *walk);
int (*install_pte)(unsigned long addr, unsigned long next,
pte_t *ptep, struct mm_walk *walk);
enum page_walk_lock walk_lock;
};
| ํ๋ | ์ญํ |
|---|---|
| `pgd_entry` | ๊ฐ non-empty PGD ์ํธ๋ฆฌ์์ ํธ์ถ |
| `p4d_entry` | ๊ฐ non-empty P4D ์ํธ๋ฆฌ์์ ํธ์ถ |
| `pud_entry` | ๊ฐ non-empty PUD ์ํธ๋ฆฌ์์ ํธ์ถ |
| `pmd_entry` | ๊ฐ non-empty PMD ์ํธ๋ฆฌ์์ ํธ์ถ (huge page ์ฒ๋ฆฌ ํ์) |
| `pte_entry` | ๊ฐ PTE ์ํธ๋ฆฌ์์ ํธ์ถ (install_pte ์ค์ ์ ๊ธฐ์กด PTE๋ง) |
| `pte_hole` | hole ์ํธ๋ฆฌ์์ ํธ์ถ, depth: -1(๋ชจ๋ฆ), 0:PGD~3:PMD |
| `hugetlb_entry` | HugeTLB ์ํธ๋ฆฌ์์ ํธ์ถ (VMA lock ์ ์ง) |
| `test_walk` | VMA ์ํ ์ ํ ์คํธ, 0:์งํ, >0:์คํต, <0:์ค๋จ |
| `pre_vma` / `post_vma` | VMA ์ํ ์ ํ ์ฝ๋ฐฑ |
| `install_pte` | ๋๋ฝ๋ PTE ์๋ ์ค์น (๋ด๋ถ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ์ ์ฉ) |
| `walk_lock` | mmap_lock ์ ๊ธ ๋ชจ๋ (RDLOCK/WRLOCK ๋ฑ) |
struct mm_walk
์ํ ์ํ๋ฅผ ๋ด๋นํ๋ ๊ตฌ์กฐ์ฒด โ ์ฝ๋ฐฑ ๊ฐ ๊ณต์ ๋ฉ๋๋ค.
// include/linux/pagewalk.h:121-129
struct mm_walk {
const struct mm_walk_ops *ops; // ์ฝ๋ฐฑ ํ
์ด๋ธ
struct mm_struct *mm; // ๋์ ํ๋ก์ธ์ค mm
pgd_t *pgd; // ์ปค๋ ํ
์ด๋ธ ์ํ ์ PGD ํฌ์ธํฐ
struct vm_area_struct *vma; // ํ์ฌ ์ํ ์ค์ธ VMA
enum page_walk_action action; // ๋ค์ ๋์ (SUBTREE/CONTINUE/AGAIN)
bool no_vma; // VMA ๋ฌด์ ๋ชจ๋
void *private; // ์ฝ๋ฐฑ์ฉ ์ฌ์ฉ์ ๋ฐ์ดํฐ
};
enum page_walk_action
pmd_entry/pud_entry ์ฝ๋ฐฑ์ด ๋ฐํํ๋ ๋์ ์ ์ด ๊ฐ:
// include/linux/pagewalk.h:100-107
enum page_walk_action {
ACTION_SUBTREE = 0, // ํ์ ๋ ๋ฒจ๋ก ๋ด๋ ค๊ฐ (THP ๋ถํ ํฌํจ)
ACTION_CONTINUE = 1, // ๊ฐ์ ๋ ๋ฒจ์ ๋ค์ ์ํธ๋ฆฌ๋ก ์ด๋
ACTION_AGAIN = 2 // ํ์ฌ ์ํธ๋ฆฌ๋ฅผ ๋ค์ ์ฒ๋ฆฌ
};
enum page_walk_lock
์ ๊ธ ๋ชจ๋ โ VMA ์ฒ๋ฆฌ ์ mmap_lock ์ ๊ธ ์์ค์ ์ง์ ํฉ๋๋ค:
// include/linux/pagewalk.h:10-19
enum page_walk_lock {
PGWALK_RDLOCK = 0, // mmap_lock ์ฝ๊ธฐ ์ ๊ธ
PGWALK_WRLOCK = 1, // VMA ์ฐ๊ธฐ ์ ๊ธ ํ๋
PGWALK_WRLOCK_VERIFY = 2, // VMA ์ฐ๊ธฐ ์ ๊ธ ์ด๋ฏธ ํ๋๋จ (๊ฒ์ฆ๋ง)
PGWALK_VMA_RDLOCK_VERIFY = 3, // VMA ์ฝ๊ธฐ ์ ๊ธ ์ด๋ฏธ ํ๋๋จ (๊ฒ์ฆ๋ง)
};
struct folio_walk
folio_walk_start() / folio_walk_end() API์ ๋ฐํ/์ํ ๊ตฌ์กฐ์ฒด:
// include/linux/pagewalk.h:177-194
struct folio_walk {
/* public */
struct page *page; // ์ฐธ์กฐ๋ ์ ํํ ํ์ด์ง
enum folio_walk_level level; // PTE/PMD/PUD ์ค ์ํธ๋ฆฌ ๋ ๋ฒจ
union {
pte_t *ptep; // PTE ํฌ์ธํฐ (FW_LEVEL_PTE)
pud_t *pudp; // PUD ํฌ์ธํฐ (FW_LEVEL_PUD)
pmd_t *pmdp; // PMD ํฌ์ธํฐ (FW_LEVEL_PMD)
};
union {
pte_t pte; // PTE ๊ฐ
pud_t pud; // PUD ๊ฐ
pmd_t pmd; // PMD ๊ฐ
};
/* private */
struct vm_area_struct *vma; // ๋์ VMA
spinlock_t *ptl; // ํ์ด์ง ํ
์ด๋ธ ์ ๊ธ
};
folio_walk ํ๋๊ทธ
// include/linux/pagewalk.h:155-158
#define FW_MIGRATION BIT(0) // migration ์ํธ๋ฆฌ๋ ์ํ
#define FW_ZEROPAGE BIT(1) // ๊ณต์ zero page๋ ๋ฐํ
ํต์ฌ ํจ์
1. walk_page_range()
์ธ๋ถ API ์ง์
์ โ check_ops_safe()๋ก install_pte ์ฌ์ฉ ์ฌ๋ถ ๊ฒ์ฆ ํ walk_page_range_mm_unsafe() ํธ์ถ.
// mm/pagewalk.c:598-606
int walk_page_range(struct mm_struct *mm, unsigned long start,
unsigned long end, const struct mm_walk_ops *ops,
void *private)
{
if (!check_ops_safe(ops))
return -EINVAL;
return walk_page_range_mm_unsafe(mm, start, end, ops, private);
}
mm->mmap_lock ๋ณด์ ํ์install_pte๊ฐ ์ค์ ๋ ops๋ ์ธ๋ถ API์์ ์ฐจ๋จ2. walk_page_range_mm_unsafe()
์ค์ ์ํ ๋ก์ง โ VMA๋ฅผ ์ํํ๋ฉด์ ๊ฐ ์์ญ์ ๋ํด __walk_page_range() ํธ์ถ.
// mm/pagewalk.c:496-530
vma = find_vma(walk.mm, start);
do {
if (!vma) { /* ๋ง์ง๋ง VMA ์ดํ */
walk.vma = NULL;
next = end;
if (ops->pte_hole)
err = ops->pte_hole(start, next, -1, &walk);
} else if (start < vma->vm_start) { /* VMA ๋ฐ๊นฅ */
walk.vma = NULL;
next = min(end, vma->vm_start);
if (ops->pte_hole)
err = ops->pte_hole(start, next, -1, &walk);
} else { /* VMA ๋ด๋ถ */
process_vma_walk_lock(vma, ops->walk_lock);
walk.vma = vma;
next = min(end, vma->vm_end);
vma = find_vma(mm, vma->vm_end);
err = walk_page_test(start, next, &walk);
if (err > 0) {
err = 0;
continue;
}
if (err < 0)
break;
err = __walk_page_range(start, next, &walk);
}
if (err)
break;
} while (start = next, start < end);
find_vma()๋ก ์์ ์ฃผ์์ VMA๋ฅผ ์ฐพ๊ณ , VMA ๊ฐ gap์ pte_hole๋ก ์ฒ๋ฆฌpte_hole(start, next, -1, &walk) ํธ์ถwalk_page_test()๋ก VMA ๊ฒ์ฆ ํ __walk_page_range() ํธ์ถ3. __walk_page_range()
VMA ๋ด๋ถ ์ํ โ HugeTLB๋ฉด walk_hugetlb_range(), ์๋๋ฉด walk_pgd_range() ํธ์ถ.
// mm/pagewalk.c:408-435
static int __walk_page_range(unsigned long start, unsigned long end,
struct mm_walk *walk)
{
int err = 0;
struct vm_area_struct *vma = walk->vma;
const struct mm_walk_ops *ops = walk->ops;
bool is_hugetlb = is_vm_hugetlb_page(vma);
/* hugetlb PTE ์ค์น๋ ์ง์ํ์ง ์๋๋ค. */
if (ops->install_pte && is_hugetlb)
return -EINVAL;
if (ops->pre_vma) {
err = ops->pre_vma(start, end, walk);
if (err)
return err;
}
if (is_hugetlb) {
if (ops->hugetlb_entry)
err = walk_hugetlb_range(start, end, walk);
} else
err = walk_pgd_range(start, end, walk);
if (ops->post_vma)
ops->post_vma(walk);
return err;
}
4. walk_pgd_range() โ walk_p4d_range() โ walk_pud_range() โ walk_pmd_range() โ walk_pte_range()
๊ณ์ธต์ ์ํ ์ฒด์ธ โ ๊ฐ ๋ ๋ฒจ์์ ์ํธ๋ฆฌ ์กด์ฌ/none/leaf ๊ฒ์ฌ ํ ํ์ ๋ ๋ฒจ๋ก ๋ด๋ ค๊ฐ.
// mm/pagewalk.c:289-325
static int walk_pgd_range(unsigned long addr, unsigned long end,
struct mm_walk *walk)
{
pgd_t *pgd;
unsigned long next;
const struct mm_walk_ops *ops = walk->ops;
bool has_handler = ops->p4d_entry || ops->pud_entry || ops->pmd_entry ||
ops->pte_entry;
bool has_install = ops->install_pte;
int err = 0;
if (walk->pgd)
pgd = walk->pgd + pgd_index(addr);
else
pgd = pgd_offset(walk->mm, addr);
do {
next = pgd_addr_end(addr, end);
if (pgd_none_or_clear_bad(pgd)) {
if (has_install)
err = __p4d_alloc(walk->mm, pgd, addr);
else if (ops->pte_hole)
err = ops->pte_hole(addr, next, 0, walk);
if (err)
break;
if (!has_install)
continue;
}
if (ops->pgd_entry) {
err = ops->pgd_entry(pgd, addr, next, walk);
if (err)
break;
}
if (has_handler || has_install)
err = walk_p4d_range(pgd, addr, next, walk);
if (err)
break;
} while (pgd++, addr = next, addr != end);
return err;
}
๊ณตํต ํจํด (๋ชจ๋ walk_*_range ํจ์):
1. ํ์ฌ ๋ ๋ฒจ์ ์ํธ๋ฆฌ ํฌ์ธํฐ ํ๋ (pgd_offset, pmd_offset ๋ฑ)
2. none_or_clear_bad ๊ฒ์ฌ โ ์์ผ๋ฉด __xxx_alloc() ๋๋ pte_hole()
3. ํด๋น ๋ ๋ฒจ ์ฝ๋ฐฑ ํธ์ถ (pgd_entry, pmd_entry ๋ฑ)
4. walk->action ํ์ธ:
- ACTION_SUBTREE โ ํ์ ๋ ๋ฒจ๋ก ๋ด๋ ค๊ฐ
- ACTION_CONTINUE โ ๋ค์ ์ํธ๋ฆฌ๋ก (ํ์ ๋ฌด์)
- ACTION_AGAIN โ ๋ค์ ํ์ฌ ์ํธ๋ฆฌ ์ฒ๋ฆฌ
5. ํ์ ๋ ๋ฒจ ํจ์ ์ฌ๊ท ํธ์ถ
5. folio_walk_start()
๋จ์ผ ๊ฐ์ ์ฃผ์์์ folio๋ฅผ ์ง์ ์ฐพ๋ ๊ฐ๊ฒฐํ API โ folio_walk_end()๋ก ํด์ .
// mm/pagewalk.c:969-1004
if (IS_ENABLED(CONFIG_PGTABLE_HAS_HUGE_LEAVES) &&
(!pmd_present(pmd) || pmd_leaf(pmd))) {
ptl = pmd_lock(vma->vm_mm, pmdp);
pmd = pmdp_get(pmdp);
entry_size = PMD_SIZE;
fw->level = FW_LEVEL_PMD;
fw->pmdp = pmdp;
fw->pmd = pmd;
if (pmd_none(pmd)) {
spin_unlock(ptl);
goto not_found;
} else if (pmd_present(pmd) && !pmd_leaf(pmd)) {
spin_unlock(ptl);
goto pte_table;
} else if (pmd_present(pmd)) {
page = vm_normal_page_pmd(vma, addr, pmd);
if (page)
goto found;
} else if ((flags & FW_MIGRATION) &&
pmd_is_migration_entry(pmd)) {
const softleaf_t entry = softleaf_from_pmd(pmd);
page = softleaf_to_page(entry);
expose_page = false;
goto found;
}
spin_unlock(ptl);
goto not_found;
}
ํธ์ถ ํ๋ฆ
walk_page_range(mm, start, end, ops, private)
โ
โโโ check_ops_safe(ops) โ install_pte ์ฐจ๋จ
โ
โโโ walk_page_range_mm_unsafe(mm, start, end, ops, private)
โ
โโโ process_mm_walk_lock() โ mmap_lock ๊ฒ์ฆ
โ
โโโ VMA ์ํ ๋ฃจํ
โ
โโโ VMA ๋ฐ๊นฅ โ ops->pte_hole()
โ
โโโ VMA ๋ด๋ถ
โ
โโโ process_vma_walk_lock() โ VMA ์ ๊ธ
โโโ walk_page_test() โ test_walk ์ฝ๋ฐฑ
โ
โโโ __walk_page_range(start, end, walk)
โ
โโโ ops->pre_vma()
โ
โโโ HugeTLB?
โ โโโ YES โ walk_hugetlb_range()
โ โ โโโ ops->hugetlb_entry()
โ โโโ NO โ walk_pgd_range()
โ โ
โ โโโ ops->pgd_entry()
โ โโโ walk_p4d_range()
โ โ
โ โโโ ops->p4d_entry()
โ โโโ walk_pud_range()
โ โ
โ โโโ ops->pud_entry()
โ โโโ walk_pmd_range()
โ โ
โ โโโ ops->pmd_entry()
โ โโโ split_huge_pmd()
โ โโโ walk_pte_range()
โ โ
โ โโโ ops->install_pte() ๋๋
โ โโโ ops->pte_entry()
โ
โโโ ops->post_vma()
folio_walk_start() ํธ์ถ ํ๋ฆ
folio_walk_start(fw, vma, addr, flags)
โ
โโโ pgd_offset(mm, addr) โ PGD ๊ฒ์ฌ
โโโ p4d_offset(pgdp, addr) โ P4D ๊ฒ์ฌ
โโโ pud_offset(p4dp, addr) โ PUD ๊ฒ์ฌ
โ โโโ CONFIG_PGTABLE_HAS_HUGE_LEAVES โ PUD leaf ํ์ธ
โ โโโ vm_normal_page_pud() โ found
โโโ pmd_offset(pudp, addr) โ PMD ๊ฒ์ฌ
โ โโโ PMD leaf ํ์ธ
โ โโโ vm_normal_page_pmd() โ found
โ โโโ is_huge_zero_pmd() โ found (FW_ZEROPAGE)
โโโ pte_offset_map_lock() โ PTE ๊ฒ์ฌ
โโโ pte_present โ vm_normal_page() โ found
โโโ migration entry โ softleaf_to_page() โ found (FW_MIGRATION)
์กฐ๊ฑด๋ณ ๋น๊ต
1. API ์ ํ๋ณ ๋น๊ต
| API | ๋ฒ์ | VMA ํ์ | PTL ์ฒ๋ฆฌ | ์ฃผ์ ์ฌ์ฉ์ฒ |
|---|---|---|---|---|
| `walk_page_range()` | ๋ฉํฐ VMA | ์๋์ค | ๋ด๋ถ ์ฒ๋ฆฌ | madvise, mprotect, mlock, mincore |
| `walk_page_range_vma()` | ๋จ์ผ VMA | ์ | ๋ด๋ถ ์ฒ๋ฆฌ | KSM, madvise |
| `walk_page_vma()` | ์ ์ฒด VMA | ์ | ๋ด๋ถ ์ฒ๋ฆฌ | ํน์ ์ฉ๋ |
| `walk_page_mapping()` | address_space | ์๋์ค | ๋ด๋ถ ์ฒ๋ฆฌ | writeback, dirty helpers |
| `walk_kernel_page_table_range()` | ์ปค๋ ํ ์ด๋ธ | ์๋์ค | lockless | vmalloc, ioremap |
| `folio_walk_start()` | ๋จ์ผ ์ฃผ์ | ์ (ํธ์ถ ํ์) | PTL ํ๋ | rmap, migrate, huge_memory |
2. walk_lock ๋ชจ๋๋ณ ๋น๊ต
| ๋ชจ๋ | mmap_lock | VMA lock | ์ฌ์ฉ ์๋๋ฆฌ์ค |
|---|---|---|---|
| `PGWALK_RDLOCK` | ์ฝ๊ธฐ | ์์ | ์ผ๋ฐ์ ์ธ ์ฝ๊ธฐ ์ํ (mincore, mlock) |
| `PGWALK_WRLOCK` | ์ฐ๊ธฐ | ์ฐ๊ธฐ ํ๋ | ์์ ํ์ํ ์ํ (mprotect, madvise FREE) |
| `PGWALK_WRLOCK_VERIFY` | ์ฐ๊ธฐ | ์ฐ๊ธฐ ๊ฒ์ฆ | ์ด๋ฏธ ์ ๊ธด VMA (madvise ๋ด๋ถ) |
| `PGWALK_VMA_RDLOCK_VERIFY` | - | ์ฝ๊ธฐ ๊ฒ์ฆ | VMA read lock ์ด๋ฏธ ํ๋๋จ |
3. walk->action๋ณ ๋์
| action ๊ฐ | ๋์ | ์ ์ฉ ๋ ๋ฒจ |
|---|---|---|
| `ACTION_SUBTREE` (๊ธฐ๋ณธ) | ํ์ ๋ ๋ฒจ๋ก ๋ด๋ ค๊ฐ, THP ํ์์ ๋ถํ | pud_entry, pmd_entry |
| `ACTION_CONTINUE` | ๋ค์ ์ํธ๋ฆฌ๋ก ์ด๋ (ํ์ ๋ฌด์) | pud_entry, pmd_entry |
| `ACTION_AGAIN` | ํ์ฌ ์ํธ๋ฆฌ๋ฅผ ๋ค์ ์ฒ๋ฆฌ (๋๊ธฐํ ์ฌํ์ธ) | pmd_entry, pud_entry |
4. hole ์ฒ๋ฆฌ ๋ฐฉ์ ๋น๊ต
| ์กฐ๊ฑด | pte_hole ๋์ | depth ๊ฐ |
|---|---|---|
| VMA ์์ (find_vma ์คํจ) | pte_hole(start, end, -1) | -1 (๋ชจ๋ฆ) |
| VMA ๋ฐ๊นฅ gap | pte_hole(start, next, -1) | -1 (๋ชจ๋ฆ) |
| PMD none (install_pte ์์) | pte_hole(addr, next, 3) | 3 (PMD) |
| PUD none (install_pte ์์) | pte_hole(addr, next, 2) | 2 (PUD) |
| P4D none (install_pte ์์) | pte_hole(addr, next, 1) | 1 (P4D) |
| PGD none (install_pte ์์) | pte_hole(addr, next, 0) | 0 (PGD) |
| install_pte ์ค์ ์ hole | ์์ (ํญ์ ์ํธ๋ฆฌ ์ค์น) | - |
5. folio_walk_start() vs walk_page_range()
| ํญ๋ชฉ | folio_walk_start() | walk_page_range() |
|---|---|---|
| ๋ชฉ์ | ๋จ์ผ ์ฃผ์ โ folio ๋ฐํ | ๋ฒ์ ์ํ + ์ฝ๋ฐฑ |
| ๋ฐํ๊ฐ | folio* ๋๋ NULL | ์๋ฌ ์ฝ๋ |
| PTL | caller๊ฐ folio_walk_end()๋ก ํด์ | ๋ด๋ถ์์ pte_unmap_unlock |
| ์ฝ๋ฐฑ | ์์ | ops->pte_entry ๋ฑ |
| ๋ฒ์ | ํ๋์ ์ฃผ์๋ง | ์์ ๋ฒ์ |
| ์ฌ์ฉ ์๋๋ฆฌ์ค | rmap, migrate, huge_memory | mlock, madvise, mincore ๋ฑ |