23. HMM โ€” Heterogeneous Memory Management

HMM ํ˜ธ์ถœ ํ๋ฆ„
HMM ์ž๋ฃŒ๊ตฌ์กฐ ๊ด€๊ณ„๋„

๊ฐœ์š” (Overview)

HMM(Heterogeneous Memory Management)๋Š” ๋ฆฌ๋ˆ…์Šค ์ปค๋„์—์„œ GPU, FPGA ๊ฐ™์€ ๋น„-CPU ๋””๋ฐ”์ด์Šค๊ฐ€ CPU ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„์„ ์ง์ ‘ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ์„œ๋ธŒ์‹œ์Šคํ…œ์ด๋‹ค. ๋””๋ฐ”์ด์Šค๊ฐ€ CPU์˜ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์„ ์ฝ๊ณ , ํ•„์š”์‹œ ํŽ˜์ด์ง€ ํดํŠธ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋ฉฐ, DMA ๋งคํ•‘๊นŒ์ง€ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ํ•ต์‹ฌ ์•„์ด๋””์–ด๋Š” ๋””๋ฐ”์ด์Šค ๋“œ๋ผ์ด๋ฒ„๊ฐ€ hmm_range_fault()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํŠน์ • ๊ฐ€์ƒ ์ฃผ์†Œ ๋ฒ”์œ„์˜ ํŽ˜์ด์ง€ ์ƒํƒœ๋ฅผ ํ•œ๊บผ๋ฒˆ์— ํ™•์ธํ•˜๊ณ , ํ•„์š”์‹œ ์ž๋™์œผ๋กœ fault-inํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์†Œ์Šค ํŒŒ์ผ ์œ„์น˜:

mm/hmm.c                          โ† HMM ํ•ต์‹ฌ ๊ตฌํ˜„ (895์ค„)
include/linux/hmm.h               โ† hmm_range, hmm_pfn_flags ์ •์˜
include/linux/hmm-dma.h           โ† hmm_dma_map ๊ตฌ์กฐ์ฒด ์ •์˜

์ด ๊ตฌํ˜„์€ MMU interval notifier๋กœ ๋ฒ”์œ„๋ฅผ ๋ณดํ˜ธํ•˜๋ฉด์„œ CPU ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์ƒํƒœ๋ฅผ ์ฝ์–ด ๋””๋ฐ”์ด์Šค๊ฐ€ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  PFN ๋ฐฐ์—ด์„ ์ฑ„์šฐ๋Š” ๋ฐ ์ดˆ์ ์„ ๋‘”๋‹ค. default_flags์™€ pfn_flags_mask๋ฅผ ์กฐํ•ฉํ•˜๋ฉด ์ „์ฒด ๋ฒ”์œ„๋ฅผ ๋ฏธ๋ฆฌ fault-inํ•˜๊ฑฐ๋‚˜, ๊ฐœ๋ณ„ PFN์—๋งŒ fault/์“ฐ๊ธฐ ์š”๊ตฌ๋ฅผ ์„ž์–ด ๋„ฃ๋Š” ๋ฐฉ์‹๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ดํ›„์—๋Š” ๊ฐ™์€ PFN ๊ฒฐ๊ณผ๋ฅผ hmm_dma_map_pfn()์œผ๋กœ ๋„˜๊ฒจ IOVA ๋˜๋Š” PCI P2P DMA ์ฃผ์†Œ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.


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

# HMM ๊ด€๋ จ ์ปค๋„ ์„ค์ • ํ™•์ธ
grep -E "CONFIG_HMM|CONFIG_DEVICE_PRIVATE" /boot/config-$(uname -r)

# HMM ๋ชจ๋“ˆ ๋กœ๋“œ ์ƒํƒœ ํ™•์ธ
lsmod | grep -i hmm

# /sys์—์„œ HMM ๊ด€๋ จ ๋””๋ฒ„๊ทธ ์ •๋ณด ํ™•์ธ (ํ•ด๋‹น ์ปค๋„ ๋นŒ๋“œ ์‹œ)
cat /sys/kernel/debug/hmm/* 2>/dev/null || echo "HMM debug not available"

# ๋””๋ฐ”์ด์Šค์˜ DMA ์ฃผ์†Œ ๋ฒ”์œ„ ํ™•์ธ
cat /sys/class/dma/*/dmaaddress 2>/dev/null || echo "N/A"

# ์ปค๋„ ๋กœ๊ทธ์—์„œ HMM ๊ด€๋ จ ๋ฉ”์‹œ์ง€ ํ™•์ธ
dmesg | grep -i "hmm\|device.private\|dma.map"

# ํ˜„์žฌ ์‹œ์Šคํ…œ์˜ NUMA ๋…ธ๋“œ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ํ‹ฐ์–ด ํ™•์ธ
numactl --hardware
ls /sys/devices/system/memory/ | head -20

# ํŽ˜์ด์ง€ ํดํŠธ ํ†ต๊ณ„ ํ™•์ธ (HMM์ด fault๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•  ๋•Œ ํ™œ์šฉ)
vmstat 1 3

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

1. `struct hmm_range` โ€” ๊ฐ€์ƒ ์ฃผ์†Œ ๋ฒ”์œ„ ์ถ”์ 

๋””๋ฐ”์ด์Šค๊ฐ€ ์š”์ฒญํ•œ ๊ฐ€์ƒ ์ฃผ์†Œ ๋ฒ”์œ„์˜ ํŽ˜์ด์ง€ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•œ๋‹ค. MMU interval notifier๋ฅผ ํ†ตํ•ด ๋ฌดํšจํ™”(invalidation)๋กœ๋ถ€ํ„ฐ ๋ณดํ˜ธ๋ฐ›๋Š”๋‹ค.

/* include/linux/hmm.h:111-120 */
struct hmm_range {
struct mmu_interval_notifier *notifier; /* MMU ๋ฌดํšจํ™” ์•Œ๋ฆผ */
unsigned long       notifier_seq;       /* ๋ฌดํšจํ™” ์‹œํ€€์Šค ๋ฒˆํ˜ธ */
unsigned long       start;              /* ๋ฒ”์œ„ ์‹œ์ž‘ ๊ฐ€์ƒ ์ฃผ์†Œ (inclusive) */
unsigned long       end;                /* ๋ฒ”์œ„ ๋ ๊ฐ€์ƒ ์ฃผ์†Œ (exclusive) */
unsigned long       *hmm_pfns;          /* PFN ๋ฐฐ์—ด (๋ฒ”์œ„ ํฌ๊ธฐ๋งŒํผ) */
unsigned long       default_flags;      /* ๋ฒ”์œ„ ๊ธฐ๋ณธ ํ”Œ๋ž˜๊ทธ (์ฝ๊ธฐ/์“ฐ๊ธฐ ๋“ฑ) */
unsigned long       pfn_flags_mask;     /* ๊ฐœ๋ณ„ PFN ๋งˆ์Šคํฌ */
void                *dev_private_owner; /* ๋””๋ฐ”์ด์Šค ํ”„๋ผ์ด๋น— ํŽ˜์ด์ง€ ์†Œ์œ ์ž */
};

2. `enum hmm_pfn_flags` โ€” PFN ์ž…์ถœ๋ ฅ ํ”Œ๋ž˜๊ทธ

ํŽ˜์ด์ง€ PFN์˜ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋น„ํŠธ ํ”Œ๋ž˜๊ทธ. ์ž…๋ ฅ ํ”Œ๋ž˜๊ทธ์™€ ์ถœ๋ ฅ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๊ตฌ๋ถ„๋œ๋‹ค.

/* include/linux/hmm.h:38-58 */
enum hmm_pfn_flags {
/* ์ถœ๋ ฅ ํ•„๋“œ ๋ฐ ํ”Œ๋ž˜๊ทธ */
HMM_PFN_VALID     = 1UL << (BITS_PER_LONG - 1), /* ์œ ํšจํ•œ PFN */
HMM_PFN_WRITE     = 1UL << (BITS_PER_LONG - 2), /* ์“ฐ๊ธฐ ๊ฐ€๋Šฅ */
HMM_PFN_ERROR     = 1UL << (BITS_PER_LONG - 3), /* ์ ‘๊ทผ ๋ถˆ๊ฐ€ (์˜ค๋ฅ˜) */
HMM_PFN_DMA_MAPPED = 1UL << (BITS_PER_LONG - 4), /* DMA ๋งคํ•‘๋จ */
HMM_PFN_P2PDMA    = 1UL << (BITS_PER_LONG - 5), /* P2P ํŽ˜์ด์ง€ */
HMM_PFN_P2PDMA_BUS = 1UL << (BITS_PER_LONG - 6), /* ๋ฒ„์Šค ๋งคํ•‘ P2P */

HMM_PFN_ORDER_SHIFT = (BITS_PER_LONG - 11),

/* ์ž…๋ ฅ ํ”Œ๋ž˜๊ทธ */
HMM_PFN_REQ_FAULT = HMM_PFN_VALID,  /* ํดํŠธ ์š”์ฒญ */
HMM_PFN_REQ_WRITE = HMM_PFN_WRITE,  /* ์“ฐ๊ธฐ ํดํŠธ ์š”์ฒญ */

HMM_PFN_FLAGS = ~((1UL << HMM_PFN_ORDER_SHIFT) - 1), /* PFN ๋น„ํŠธ ๋งˆ์Šคํฌ */
};

3. `struct hmm_vma_walk` โ€” ๋‚ด๋ถ€ VMA ์›Œํฌ ์ƒํƒœ

hmm_range_fault() ๋‚ด๋ถ€์—์„œ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์„ ์ˆœํšŒํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ์ž„์‹œ ์ƒํƒœ ๊ตฌ์กฐ์ฒด.

/* mm/hmm.c:33-36 */
struct hmm_vma_walk {
struct hmm_range   *range; /* ํ˜„์žฌ ์ฒ˜๋ฆฌ ์ค‘์ธ hmm_range */
unsigned long      last;  /* ๋งˆ์ง€๋ง‰์œผ๋กœ ์ฒ˜๋ฆฌ๋œ ์ฃผ์†Œ (์žฌ์‹œ์ž‘ ์ง€์ ) */
};

4. `struct hmm_dma_map` โ€” DMA ๋งคํ•‘ ๋ฐฐ์—ด

PFN ๋ชฉ๋ก๊ณผ DMA ์ฃผ์†Œ ๋ฐฐ์—ด์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ์ฒด. IOVA ๊ธฐ๋ฐ˜ ๋งคํ•‘๊ณผ ์ผ๋ฐ˜ ๋งคํ•‘์„ ์ง€์›ํ•œ๋‹ค.

/* include/linux/hmm-dma.h:19-24 */
struct hmm_dma_map {
struct dma_iova_state state;    /* DMA IOVA ์ƒํƒœ */
unsigned long         *pfn_list; /* PFN ๋ฐฐ์—ด */
dma_addr_t            *dma_list; /* DMA ์ฃผ์†Œ ๋ฐฐ์—ด */
size_t                dma_entry_size; /* ๊ฐ DMA ์—”ํŠธ๋ฆฌ ํฌ๊ธฐ */
};

5. `struct mm_walk_ops` โ€” ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์›Œํฌ ์—ฐ์‚ฐ์ž

HMM์ด ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์„ ์ˆœํšŒํ•  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ํ…Œ์ด๋ธ”.

/* mm/hmm.c:631-638 */
static const struct mm_walk_ops hmm_walk_ops = {
.pud_entry      = hmm_vma_walk_pud,     /* PUD ์—”ํŠธ๋ฆฌ ์ฒ˜๋ฆฌ */
.pmd_entry      = hmm_vma_walk_pmd,     /* PMD ์—”ํŠธ๋ฆฌ ์ฒ˜๋ฆฌ */
.pte_hole       = hmm_vma_walk_hole,    /* PTE ๊ณต๋ฐฑ ์ฒ˜๋ฆฌ */
.hugetlb_entry  = hmm_vma_walk_hugetlb_entry, /* HugeTLB ์ฒ˜๋ฆฌ */
.test_walk      = hmm_vma_walk_test,    /* VMA ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ */
.walk_lock      = PGWALK_RDLOCK,        /* ์ฝ๊ธฐ ์ž ๊ธˆ */
};

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

1. `hmm_range_fault()` โ€” ๋ฉ”์ธ ์ง„์ž…์ 

/* mm/hmm.c:659-686 */
int hmm_range_fault(struct hmm_range *range)

์—ญํ• : ๋””๋ฐ”์ด์Šค๊ฐ€ ์š”์ฒญํ•œ ๊ฐ€์ƒ ์ฃผ์†Œ ๋ฒ”์œ„์˜ ํŽ˜์ด์ง€๋ฅผ fault-inํ•˜๊ณ , ํ•ด๋‹น PFN์„ range->hmm_pfns[] ๋ฐฐ์—ด์— ๊ธฐ๋กํ•œ๋‹ค.

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

1. mmu_interval_check_retry() โ†’ ๋ฒ”์œ„๊ฐ€ ๋ฌดํšจํ™”๋˜์—ˆ์œผ๋ฉด -EBUSY ๋ฐ˜ํ™˜ (์žฌ์‹œ์ž‘)

2. walk_page_range() ํ˜ธ์ถœ โ†’ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์ˆœํšŒ

3. -EBUSY ๋ฐ˜ํ™˜ ์‹œ hmm_vma_walk.last์—์„œ ์žฌ์‹œ์ž‘ (do-while ๋ฃจํ”„)

2. `hmm_vma_walk_pmd()` โ€” PMD ์—”ํŠธ๋ฆฌ ์ฒ˜๋ฆฌ

/* mm/hmm.c:396-471 */
static int hmm_vma_walk_pmd(pmd_t *pmdp, unsigned long start,
unsigned long end, struct mm_walk *walk)

์—ญํ• : PMD ์ˆ˜์ค€์˜ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์—”ํŠธ๋ฆฌ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค. Huge Page, migration, ์ผ๋ฐ˜ PTE ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋ถ„๊ธฐํ•œ๋‹ค.

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

1. pmd_none() โ†’ hmm_vma_walk_hole() (๋นˆ ์˜์—ญ ์ฒ˜๋ฆฌ)

2. pmd_is_migration_entry() โ†’ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋Œ€๊ธฐ ํ›„ ์žฌ์‹œ์ž‘

3. !pmd_present() โ†’ hmm_vma_handle_absent_pmd() (๋””๋ฐ”์ด์Šค ํ”„๋ผ์ด๋น— ๋“ฑ)

4. pmd_trans_huge() โ†’ hmm_vma_handle_pmd() (THP ์ฒ˜๋ฆฌ)

5. pmd_bad() โ†’ HMM_PFN_ERROR ๋ฐ˜ํ™˜

6. ์ผ๋ฐ˜ PTE โ†’ PTE ๋ฃจํ”„๋กœ ์ง„์ž…

3. `hmm_vma_handle_pte()` โ€” ๊ฐœ๋ณ„ PTE ์ฒ˜๋ฆฌ

/* mm/hmm.c:235-332 */
static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
unsigned long end, pmd_t *pmdp, pte_t *ptep,
unsigned long *hmm_pfn)

์—ญํ• : ๋‹จ์ผ PTE์˜ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ , ํ•„์š”์‹œ ํดํŠธ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๊ฑฐ๋‚˜PFN ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋กํ•œ๋‹ค.

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

1. pte_none() ๋˜๋Š” UFFD WP ๋งˆ์ปค โ†’ ํดํŠธ ํ•„์š”์‹œ fault, ์•„๋‹ˆ๋ฉด ์Šคํ‚ต

2. !pte_present() โ€” softleaf ํƒ€์ž…๋ณ„ ๋ถ„๊ธฐ:

- Device Private (์ž๊ธฐ ์†Œ์œ ) โ†’ HMM_PFN_VALID ์ง์ ‘ ๊ธฐ๋ก

- Swap โ†’ fault ํŠธ๋ฆฌ๊ฑฐ

- Device Private (ํƒ€์ธ) โ†’ fault ํŠธ๋ฆฌ๊ฑฐ

- Device Exclusive โ†’ fault ํŠธ๋ฆฌ๊ฑฐ

- Migration โ†’ migration_entry_wait() ํ›„ -EBUSY

- ๊ธฐํƒ€ โ†’ -EFAULT

3. pte_present() โ†’ pte_to_hmm_pfn_flags()๋กœ ํ”Œ๋ž˜๊ทธ ๋ณ€ํ™˜ ํ›„ ๊ธฐ๋ก

4. `hmm_vma_fault()` โ€” ํŽ˜์ด์ง€ ํดํŠธ ํŠธ๋ฆฌ๊ฑฐ

/* mm/hmm.c:73-94 */
static int hmm_vma_fault(unsigned long addr, unsigned long end,
unsigned int required_fault, struct mm_walk *walk)

์—ญํ• : ์ง€์ •๋œ ๋ฒ”์œ„์˜ ํŽ˜์ด์ง€๋ฅผ fault-inํ•œ๋‹ค. handle_mm_fault()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ปค๋„์˜ ํ‘œ์ค€ ํŽ˜์ด์ง€ ํดํŠธ ์ฒ˜๋ฆฌ๋ฅผ ํ™œ์šฉํ•œ๋‹ค.

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

1. HMM_NEED_WRITE_FAULT && !(vma->vm_flags & VM_WRITE) โ†’ -EPERM

2. handle_mm_fault()์—์„œ VM_FAULT_ERROR โ†’ -EFAULT

3. ์„ฑ๊ณต ์‹œ -EBUSY ๋ฐ˜ํ™˜ (์žฌ์‹œ์ž‘ ์œ ๋„)

5. `hmm_dma_map_pfn()` โ€” PFN์„ DMA ์ฃผ์†Œ๋กœ ๋งคํ•‘

/* mm/hmm.c:771-857 */
dma_addr_t hmm_dma_map_pfn(struct device *dev, struct hmm_dma_map *map,
size_t idx,
struct pci_p2pdma_map_state *p2pdma_state)

์—ญํ• : HMM PFN์„ DMA ๊ฐ€๋Šฅํ•œ ์ฃผ์†Œ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค. IOVA ๊ธฐ๋ฐ˜ ๋งคํ•‘๊ณผ ์ผ๋ฐ˜ ๋งคํ•‘์„ ๋ชจ๋‘ ์ง€์›ํ•˜๋ฉฐ, PCI P2P DMA๋„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

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

1. HMM_PFN_DMA_MAPPED && !HMM_PFN_P2PDMA_BUS โ†’ ์ด๋ฏธ ๋งคํ•‘๋จ, IOVA/dma_addrs์—์„œ ๋ฐ˜ํ™˜

2. pci_p2pdma_state() ๋ถ„๊ธฐ:

- MAP_THRU_HOST_BRIDGE โ†’ DMA_ATTR_MMIO ์„ค์ •

- MAP_BUS_ADDR โ†’ ๋ฒ„์Šค ์ฃผ์†Œ ์ง์ ‘ ๋ฐ˜ํ™˜

3. dma_use_iova() โ†’ IOVA ๊ธฐ๋ฐ˜ ๋งคํ•‘ (dma_iova_link + dma_iova_sync)

4. ์ผ๋ฐ˜ โ†’ dma_map_phys()๋กœ ์ง์ ‘ ๋งคํ•‘


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

hmm_range_fault()                    โ† ๋””๋ฐ”์ด์Šค ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ํ˜ธ์ถœ
โ”‚
โ”œโ”€ do-while (-EBUSY ์žฌ์‹œ์ž‘ ๋ฃจํ”„)
โ”‚   โ”‚
โ”‚   โ”œโ”€ mmu_interval_check_retry()  โ† ๋ฌดํšจํ™” ํ™•์ธ
โ”‚   โ”‚
โ”‚   โ””โ”€ walk_page_range()           โ† ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์ˆœํšŒ ์‹œ์ž‘
โ”‚       โ”‚
โ”‚       โ”œโ”€ hmm_vma_walk_test()     โ† VMA ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ (VM_IO/VM_PFNMAP ์Šคํ‚ต)
โ”‚       โ”‚
โ”‚       โ”œโ”€ hmm_vma_walk_pud()      โ† PUD ์ˆ˜์ค€ ์ฒ˜๋ฆฌ (CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)
โ”‚       โ”‚   โ”œโ”€ pud_leaf() โ†’ pfn ๊ธฐ๋ก
โ”‚       โ”‚   โ””โ”€ ACTION_SUBTREE โ†’ PMD ์ˆ˜์ค€์œผ๋กœ ๋‚ด๋ ค๊ฐ
โ”‚       โ”‚
โ”‚       โ”œโ”€ hmm_vma_walk_pmd()      โ† PMD ์ˆ˜์ค€ ์ฒ˜๋ฆฌ
โ”‚       โ”‚   โ”œโ”€ pmd_none() โ†’ hmm_vma_walk_hole()
โ”‚       โ”‚   โ”œโ”€ pmd_is_migration_entry() โ†’ migration_entry_wait()
โ”‚       โ”‚   โ”œโ”€ !pmd_present() โ†’ hmm_vma_handle_absent_pmd()
โ”‚       โ”‚   โ”œโ”€ pmd_trans_huge() โ†’ hmm_vma_handle_pmd()
โ”‚       โ”‚   โ””โ”€ ์ผ๋ฐ˜ PTE โ†’ hmm_vma_handle_pte() [for ๋ฃจํ”„]
โ”‚       โ”‚
โ”‚       โ”œโ”€ hmm_vma_walk_hole()     โ† ๋นˆ ์˜์—ญ ์ฒ˜๋ฆฌ
โ”‚       โ”‚   โ””โ”€ hmm_vma_fault() ํ•„์š”์‹œ ํ˜ธ์ถœ
โ”‚       โ”‚
โ”‚       โ””โ”€ hmm_vma_walk_hugetlb_entry() โ† HugeTLB ์—”ํŠธ๋ฆฌ ์ฒ˜๋ฆฌ
โ”‚
โ””โ”€ ๋ฐ˜ํ™˜ (0: ์„ฑ๊ณต, -EBUSY: ์žฌ์‹œ์ž‘ ํ•„์š”, ๊ธฐํƒ€: ์˜ค๋ฅ˜)

hmm_dma_map_pfn()                    โ† DMA ๋งคํ•‘ ์‹œ ํ˜ธ์ถœ
โ”‚
โ”œโ”€ ์ด๋ฏธ ๋งคํ•‘๋จ? โ†’ ๊ธฐ์กด ์ฃผ์†Œ ๋ฐ˜ํ™˜
โ”‚
โ”œโ”€ pci_p2pdma_state() โ†’ P2P ๋ถ„๊ธฐ
โ”‚   โ”œโ”€ MAP_THRU_HOST_BRIDGE โ†’ MMIO ์†์„ฑ
โ”‚   โ”œโ”€ MAP_BUS_ADDR โ†’ ๋ฒ„์Šค ์ฃผ์†Œ ๋ฐ˜ํ™˜
โ”‚   โ””โ”€ MAP_NONE โ†’ ๊ณ„์†
โ”‚
โ”œโ”€ dma_use_iova() โ†’ IOVA ๋งคํ•‘
โ”‚   โ”œโ”€ dma_iova_link()
โ”‚   โ””โ”€ dma_iova_sync()
โ”‚
โ””โ”€ ์ผ๋ฐ˜ โ†’ dma_map_phys()

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

PFN ํ”Œ๋ž˜๊ทธ ์ƒํƒœ ๋น„๊ต

ํ”Œ๋ž˜๊ทธ์˜๋ฏธ์ž…๋ ฅ ์‹œ์ถœ๋ ฅ ์‹œ
`HMM_PFN_VALID`์œ ํšจํ•œ ํŽ˜์ด์ง€`HMM_PFN_REQ_FAULT`๋กœ ์žฌ์‚ฌ์šฉํŽ˜์ด์ง€๊ฐ€ ์กด์žฌํ•จ
`HMM_PFN_WRITE`์“ฐ๊ธฐ ๊ฐ€๋Šฅ`HMM_PFN_REQ_WRITE`๋กœ ์žฌ์‚ฌ์šฉPTE์— ์“ฐ๊ธฐ ๊ถŒํ•œ ์žˆ์Œ
`HMM_PFN_ERROR`์ ‘๊ทผ ๋ถˆ๊ฐ€-์˜ค๋ฅ˜ ํŽ˜์ด์ง€ (poisoned, no vma ๋“ฑ)
`HMM_PFN_DMA_MAPPED`DMA ๋งคํ•‘๋จsticky (์ž…๋ ฅโ†’์ถœ๋ ฅ ์œ ์ง€)DMA ๋งคํ•‘ ์™„๋ฃŒ
`HMM_PFN_P2PDMA`P2P ํŽ˜์ด์ง€stickyPCI P2P ๋งคํ•‘
`HMM_PFN_P2PDMA_BUS`๋ฒ„์Šค ๋งคํ•‘ P2Psticky๋ฒ„์Šค ์ฃผ์†Œ ๊ธฐ๋ฐ˜ P2P

PTE ์ฒ˜๋ฆฌ ๊ฒฝ๋กœ ๋น„๊ต

PTE ์ƒํƒœ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋™์ž‘
`pte_none()``hmm_pte_need_fault()`ํดํŠธ ํ•„์š”์‹œ fault-in, ์•„๋‹ˆ๋ฉด ์Šคํ‚ต
Device Private (์ž๊ธฐ ์†Œ์œ )์ง์ ‘ ๊ธฐ๋ก`HMM_PFN_VALID` + PFN ๊ธฐ๋ก
Device Private (ํƒ€์ธ)fault ํŠธ๋ฆฌ๊ฑฐ`hmm_vma_fault()` ํ˜ธ์ถœ
Swapfault ํŠธ๋ฆฌ๊ฑฐ์Šค์™‘์—์„œ ์ธ
Migration`migration_entry_wait()`๋Œ€๊ธฐ ํ›„ `-EBUSY` ๋ฐ˜ํ™˜
`pte_present()``pte_to_hmm_pfn_flags()`ํ”Œ๋ž˜๊ทธ ๋ณ€ํ™˜ ํ›„ PFN ๊ธฐ๋ก

DMA ๋งคํ•‘ ๊ฒฝ๋กœ ๋น„๊ต

์กฐ๊ฑด๋งคํ•‘ ๋ฐฉ์‹ํ•จ์ˆ˜
IOVA ์ง€์› + !dma_need_unmapIOVA ๊ธฐ๋ฐ˜`dma_iova_link()` + `dma_iova_sync()`
IOVA ๋ฏธ์ง€์› + dma_need_unmap์ผ๋ฐ˜ DMA`dma_map_phys()`
P2P (Host Bridge ๊ฒฝ์œ )MMIO ๋งคํ•‘`DMA_ATTR_MMIO` ์„ค์ •
P2P (Bus Address)๋ฒ„์Šค ์ฃผ์†Œ`pci_p2pdma_bus_addr_map()`
์ด๋ฏธ ๋งคํ•‘๋จ์žฌ์‚ฌ์šฉ๊ธฐ์กด ์ฃผ์†Œ ๋ฐ˜ํ™˜

๊ด€๋ จ ๋ฌธ์„œ

  • 00-overview.html โ€” ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š”
  • 20-migrate.html โ€” ํŽ˜์ด์ง€ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ (HMM ๋‚ด migration ์ฒ˜๋ฆฌ์™€ ์—ฐ๊ด€)
  • 03-vma_mmap.html โ€” VMA / mmap (HMM์ด ์ˆœํšŒํ•˜๋Š” ๋Œ€์ƒ)
  • 10-hugepage.html โ€” Huge Pages / THP (HMM์˜ THP ์ฒ˜๋ฆฌ)
  • 24-memory_tiers.html โ€” ๋ฉ”๋ชจ๋ฆฌ ํ‹ฐ์–ด๋ง (HMM๊ณผ ํ•จ๊ป˜ ๋””๋ฐ”์ด์Šค ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ)
  • 38-pagewalk.html โ€” Page Table Walk (HMM์ด ํ™œ์šฉํ•˜๋Š” walk_page_range)