๐Ÿš‡ ํŽ˜์ด์ง€ Migration

๊ด€๋ จ ์†Œ์Šค: mm/migrate.c (2750์ค„), mm/migrate_device.c (1491์ค„)
๊ด€๋ จ ๋ฌธ์„œ: ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š” ยท Compaction ยท CMA ยท NUMA ยท HMM ยท Hotplug

๊ฐœ์š” (Overview)

ํŽ˜์ด์ง€ Migration์€ ๋ฆฌ๋ˆ…์Šค ์ปค๋„์ด ์‹คํ–‰ ์ค‘์ธ ํ”„๋กœ์„ธ์Šค์˜ ํŽ˜์ด์ง€๋ฅผ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋‹ค๋ฅธ ์œ„์น˜๋กœ ์ด๋™์‹œํ‚ค๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. ์ด๋Š” Memory Compaction(๋‹จํŽธํ™” ํ•ด์†Œ), NUMA ๋ฐธ๋Ÿฐ์‹ฑ(๋…ธ๋“œ ๊ฐ„ ์ด๋™), CMA(์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ ํ™•๋ณด), ๋ฉ”๋ชจ๋ฆฌ ํ•ซํ”Œ๋Ÿฌ๊ทธ(์˜จ๋ผ์ธ/์˜คํ”„๋ผ์ธ), HMM(์ด๊ธฐ์ข… ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ) ๋“ฑ ์—ฌ๋Ÿฌ ์„œ๋ธŒ์‹œ์Šคํ…œ์—์„œ ํ•ต์‹ฌ ๋นŒ๋”ฉ ๋ธ”๋ก์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์›๋ณธ ํŽ˜์ด์ง€์˜ ๋ชจ๋“  ๋งคํ•‘(PTE)์„ migration swap entry๋กœ ๊ต์ฒดํ•œ ๋’ค, ์ƒˆ ํŽ˜์ด์ง€๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌํ•˜๊ณ  ๋งคํ•‘์„ ๋ณต์›ํ•˜๋Š” 3๋‹จ๊ณ„ ํ”„๋กœ์„ธ์Šค๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

Migration์˜ ํ•ต์‹ฌ ์•„์ด๋””์–ด๋Š” "ํŽ˜์ด์ง€๊ฐ€ ์ด๋™๋˜๋Š” ๋™์•ˆ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ ‘๊ทผํ•˜๋ฉด ๋Œ€๊ธฐํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ"์ž…๋‹ˆ๋‹ค. PTE์— migration entry๋ฅผ ์‚ฝ์ž…ํ•˜๋ฉด, ์ ‘๊ทผ ์‹œ ํดํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  migration_entry_wait()๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋ธ”๋ก๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฌด๊ฒฐ์„ฑ์„ ๋ณด์žฅํ•˜๋ฉด์„œ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๋‚ด์—์„œ ํŽ˜์ด์ง€๋ฅผ ํˆฌ๋ช…ํ•˜๊ฒŒ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋„์„œ๊ด€์œผ๋กœ ๋น„์œ ํ•˜๋ฉด, ์ฑ…์„ ๋‹ค๋ฅธ ์„œ๊ฐ€๋กœ ์˜ฎ๊ธฐ๋Š” ๋™์•ˆ ์ž„์‹œ ์˜ˆ์•ฝํ‘œ๋ฅผ ๋ถ™์—ฌ ๋‘๊ณ , ๋‹ค์‹œ ๊ฝ‚ํžˆ๊ธฐ ์ „๊นŒ์ง€๋Š” ๋Œ€์ถœ ์š”์ฒญ์„ ์ž ๊น ๋ฉˆ์ถ”๊ฒŒ ํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.

์†Œ์Šค ํŒŒ์ผ:
mm/migrate.c            โ€” ํ•ต์‹ฌ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์—”์ง„ (2750์ค„)
mm/migrate_device.c     โ€” ๋””๋ฐ”์ด์Šค ๋ฉ”๋ชจ๋ฆฌ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ (1491์ค„)
include/linux/migrate.h โ€” ์™ธ๋ถ€ API, struct movable_operations, migrate_vma
include/linux/migrate_mode.h โ€” enum migrate_mode, enum migrate_reason
Migration ํ˜ธ์ถœ ํ๋ฆ„
Migration ์ž๋ฃŒ๊ตฌ์กฐ ๊ด€๊ณ„๋„

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

# ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ†ต๊ณ„ ํ™•์ธ
cat /proc/vmstat | grep -E 'pgmigrate|thp_migration|numa_pages_migrated'

# NUMA ๋ฐธ๋Ÿฐ์‹ฑ ํ™œ์„ฑํ™” ์ƒํƒœ ํ™•์ธ
cat /proc/sys/kernel/numa_balancing

# ํ˜„์žฌ NUMA ์ •์ฑ…๊ณผ ๋…ธ๋“œ ๋ฐฐ์น˜ ํ™•์ธ
numactl --show
numastat -p $$

# ๋ฉ”๋ชจ๋ฆฌ ํ•ซํ”Œ๋Ÿฌ๊ทธ ๋ธ”๋ก ์ƒํƒœ ํ™•์ธ
cat /sys/devices/system/memory/auto_online_blocks 2>/dev/null
ls /sys/devices/system/memory/ | grep memory | head -5

# Compaction๊ณผ ํ•จ๊ป˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋™์ž‘ ๊ด€์ฐฐ
cat /proc/vmstat | grep -E 'compact_stall|compact_success|compact_fail'
cat /proc/buddyinfo | head -4

# ํŽ˜์ด์ง€ ํดํŠธ ๊ธฐ๋ฐ˜ NUMA ์ด๋ฒคํŠธ ํ™•์ธ
cat /proc/vmstat | grep numa_hit

# NUMA ํ† ํด๋กœ์ง€์™€ ๋…ธ๋“œ ๋ฉ”๋ชจ๋ฆฌ ๋ถ„ํฌ ํ™•์ธ
numactl -H
cat /proc/zoneinfo | grep -E 'Node|zone|present|managed|spanned' | head -40

# ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ด€๋ จ ์ปค๋„ ํŠธ๋ ˆ์ด์Šค (root ๊ถŒํ•œ)
sudo perf trace -e 'migrate:*' --duration 10 2>/dev/null || true

# CMA ์˜์—ญ ์ •๋ณด ํ™•์ธ
cat /proc/meminfo | grep Cma

# ๋ฉ”๋ชจ๋ฆฌ ์••๋ฐ•๊ณผ ํšŒ์ˆ˜ ๊ฐ•๋„ ํ™•์ธ
cat /proc/pressure/memory
cat /proc/vmstat | grep -E 'allocstall|pgscan|pgsteal'

# ํ•ซํ”Œ๋Ÿฌ๊ทธ/์ด๊ธฐ์ข… ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ จ ๋ฉ”์‹œ์ง€ ํ™•์ธ
dmesg | grep -Ei 'migrate|numa|hotplug|cxl' | tail -20

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

movable_operations โ€” ๋“œ๋ผ์ด๋ฒ„ ์ˆ˜์ค€ ํŽ˜์ด์ง€ ์ด๋™ ์ธํ„ฐํŽ˜์ด์Šค

balloon, zsmalloc, hotplug ๊ฐ™์€ ์ด๋™ ๊ฐ€๋Šฅํ•œ ํŽ˜์ด์ง€ ์†Œ๋น„์ž๊ฐ€ ์“ฐ๋Š” ์ฝœ๋ฐฑ ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค. LRU์— ์ง์ ‘ ์˜ฌ๋ผ๊ฐ€์ง€ ์•Š๋Š” ํŽ˜์ด์ง€๋„ ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ๋‹ค์‹œ ๋ฐ›์•„ ์ฃผ๊ณ , ์ด๋™์ด ๋๋‚˜๋ฉด ์›๋ž˜ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ๋˜๋Œ๋ฆด ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

/* include/linux/migrate.h:44-49 */
struct movable_operations {
bool (*isolate_page)(struct page *, isolate_mode_t);
int (*migrate_page)(struct page *dst, struct page *src,
enum migrate_mode);
void (*putback_page)(struct page *);
};

migrate_vma โ€” ๋””๋ฐ”์ด์Šค ๋ฉ”๋ชจ๋ฆฌ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ปจํ…์ŠคํŠธ

GPU/๊ฐ€์†๊ธฐ ๋“ฑ ๋””๋ฐ”์ด์Šค ๋ฉ”๋ชจ๋ฆฌ์™€ ์‹œ์Šคํ…œ ๋ฉ”๋ชจ๋ฆฌ ๊ฐ„ ํŽ˜์ด์ง€ ์ด๋™์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. src[]์™€ dst[] ๋ฐฐ์—ด์€ MIGRATE_PFN_* ํ”Œ๋ž˜๊ทธ์™€ PFN์„ ์ธ์ฝ”๋”ฉํ•˜์—ฌ ๊ฐ ๊ฐ€์ƒ ์ฃผ์†Œ์˜ ํŽ˜์ด์ง€ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.

src[]์™€ dst[]๋Š” (end - start) >> PAGE_SHIFT ๊ฐœ์ˆ˜๋งŒํผ ์ค€๋น„๋˜์–ด์•ผ ํ•˜๋ฉฐ, migrate_vma_setup() ์ดํ›„์—๋Š” src[]๋ฅผ ๊ฑด๋“œ๋ฆฌ๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. migrate_vma_pages()๊ฐ€ ๋๋‚œ ๋’ค์—๋Š” dst[]๋„ ๋” ์ด์ƒ ๋ฐ”๊พธ์ง€ ์•Š์•„์•ผ ํ•˜๊ณ , fault_page๋Š” migrate_to_ram() ํ๋ฆ„์—์„œ ๋””๋ฐ”์ด์Šค ์‚ฌ์„ค ํŽ˜์ด์ง€๋ฅผ RAM์œผ๋กœ ๋˜๋Œ๋ฆด ๋•Œ ์“ฐ์ž…๋‹ˆ๋‹ค.

/* include/linux/migrate.h:158-191 */
struct migrate_vma {
struct vm_area_struct   *vma;
/*
* src์™€ dst ๋ฐฐ์—ด์€
* (end - start) >> PAGE_SHIFT ๊ฐœ์ˆ˜๋งŒํผ ์ถฉ๋ถ„ํžˆ ์ปค์•ผ ํ•œ๋‹ค.
*
* ํ˜ธ์ถœ์ž๋Š” migrate_vma_setup() ์ดํ›„ src ๋ฐฐ์—ด์„ ์ˆ˜์ •ํ•˜๋ฉด ์•ˆ ๋˜๊ณ ,
* migrate_vma_pages()๊ฐ€ ๋ฐ˜ํ™˜๋œ ๋’ค์—๋Š” dst ๋ฐฐ์—ด๋„ ๋ฐ”๊พธ๋ฉด ์•ˆ ๋œ๋‹ค.
*/
unsigned long           *dst;
unsigned long           *src;
unsigned long           cpages;
unsigned long           npages;
unsigned long           start;
unsigned long           end;

/*
* device private memory์—์„œ ์˜ฎ๊ธธ ๋•Œ page_pgmap(page)->owner์—
* ๋“ค์–ด ์žˆ๋Š” ์†Œ์œ ์ž ๊ฐ’๊ณผ ๋งž์ถฐ ๋‘๋Š” ํ•„๋“œ๋‹ค. ์ด ๊ฒฝ์šฐ flags๋„
* MIGRATE_VMA_SELECT_DEVICE_PRIVATE๋กœ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.
* ํ˜ธ์ถœ์ž๊ฐ€ mmu notifier ์ฝœ๋ฐฑ์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š”, ์˜ฎ๊ธฐ์ง€ ์•Š์„
* device private ํŽ˜์ด์ง€์— ๋Œ€ํ•œ device MMU invalidation์„ ํ”ผํ•˜๋ ค๊ณ 
* ์ด ๊ฐ’์„ ํ•ญ์ƒ ์ฑ„์›Œ์•ผ ํ•œ๋‹ค.
*/
void                    *pgmap_owner;
unsigned long           flags;

/*
* migrate_to_ram() ์ฝœ๋ฐฑ์˜ ์ผ๋ถ€๋กœ ํŽ˜์ด์ง€๋ฅผ ์˜ฎ๊ธธ ๋•Œ vmf->page๋ฅผ ๋„ฃ๋Š”๋‹ค.
*/
struct page             *fault_page;
};

migrate_pages_stats โ€” ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฒฐ๊ณผ ํ†ต๊ณ„

๋ฐฐ์น˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ค‘ ๋ฐœ์ƒํ•˜๋Š” ์„ฑ๊ณต/์‹คํŒจ/THP ๋ถ„ํ•  ํ†ต๊ณ„๋ฅผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. migrate_pages() ํ•จ์ˆ˜ ์ข…๋ฃŒ ํ›„ vmstat ์นด์šดํ„ฐ์— ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.

/* mm/migrate.c:1592-1601 */
struct migrate_pages_stats {
int nr_succeeded;   /* base page ๋‹จ์œ„๋กœ ์„ฑ๊ณตํ•œ ์ผ๋ฐ˜/๋Œ€ํ˜• folio ์ˆ˜ */
int nr_failed_pages;    /* base page ๋‹จ์œ„๋กœ ์‹คํŒจํ•œ ์ผ๋ฐ˜/๋Œ€ํ˜• folio ์ˆ˜.
์‹œ๋„ํ•˜์ง€ ์•Š์€ folio๋Š” ์ œ์™ธ */
int nr_thp_succeeded;   /* THP ์„ฑ๊ณต ์ˆ˜ */
int nr_thp_failed;  /* THP ์‹คํŒจ ์ˆ˜ */
int nr_thp_split;   /* ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ „ ๋ถ„ํ• ๋œ THP ์ˆ˜ */
int nr_split;   /* THP๋ฅผ ํฌํ•จํ•œ ๋Œ€ํ˜• folio ๋ถ„ํ•  ์ˆ˜ */
};

MIGRATE_PFN_* ํ”Œ๋ž˜๊ทธ โ€” src/dst ๋ฐฐ์—ด ์ธ์ฝ”๋”ฉ

migrate_vma API์—์„œ src[]์™€ dst[] ๋ฐฐ์—ด์˜ ๊ฐ ์—”ํŠธ๋ฆฌ๋Š” PFN๊ณผ ํ”Œ๋ž˜๊ทธ๋ฅผ ๋น„ํŠธ ๋งˆ์Šคํ‚นํ•˜์—ฌ ์ธ์ฝ”๋”ฉ๋ฉ๋‹ˆ๋‹ค. ๋น„ํŠธ 0-5๋Š” ํ”Œ๋ž˜๊ทธ, ๋น„ํŠธ 6 ์ด์ƒ์€ PFN์ž…๋‹ˆ๋‹ค.

ํ”Œ๋ž˜๊ทธ๋น„ํŠธ์˜๋ฏธ
`MIGRATE_PFN_VALID`bit 0์œ ํšจํ•œ PFN ์—”ํŠธ๋ฆฌ
`MIGRATE_PFN_MIGRATE`bit 1๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋Œ€์ƒ์œผ๋กœ ํ‘œ์‹œ
`MIGRATE_PFN_WRITE`bit 3์“ฐ๊ธฐ ๊ถŒํ•œ์ด ์žˆ๋Š” ํŽ˜์ด์ง€
`MIGRATE_PFN_COMPOUND`bit 4๋ณตํ•ฉ(compound) ํŽ˜์ด์ง€
`MIGRATE_PFN_SHIFT`6PFN ์‹œ์ž‘ ๋น„ํŠธ ์œ„์น˜

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

migrate_pages() โ€” ์ตœ์ƒ์œ„ ๋ฐฐ์น˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ API

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์˜ ๋ฉ”์ธ ์ง„์ž…์ ์ž…๋‹ˆ๋‹ค. hugetlb ํŽ˜์ด์ง€๋ฅผ ๋จผ์ € ์ฒ˜๋ฆฌํ•œ ๋’ค, ๋‚˜๋จธ์ง€ folio๋ฅผ ๋ฐฐ์น˜(batch) ๋‹จ์œ„๋กœ ๋‚˜๋ˆ„์–ด ๋น„๋™๊ธฐ ๋˜๋Š” ๋™๊ธฐ ๋ฐฉ์‹์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•ฉ๋‹ˆ๋‹ค.

/* mm/migrate.c:2072-2074 */
int migrate_pages(struct list_head *from, new_folio_t get_new_folio,
free_folio_t put_new_folio, unsigned long private,
enum migrate_mode mode, int reason, unsigned int *ret_succeeded)

๋™์ž‘ ํ๋ฆ„:

1. migrate_hugetlbs()๋กœ HugeTLB folio๋ฅผ ๋จผ์ € ์ฒ˜๋ฆฌ

2. ๋‚จ์€ folio๋ฅผ NR_MAX_BATCHED_MIGRATION(THP ์‚ฌ์šฉ ์‹œ HPAGE_PMD_NR, ๊ทธ ์™ธ 512) ๋‹จ์œ„๋กœ ๋ฐฐ์น˜ ๋ถ„ํ• 

3. MIGRATE_ASYNC์ด๋ฉด migrate_pages_batch(), ๊ทธ ์™ธ์ด๋ฉด migrate_pages_sync()

4. ๋™๊ธฐ ๋ชจ๋“œ์—์„œ๋Š” ๋จผ์ € ASYNC๋กœ ์‹œ๋„ํ•œ ๋’ค ์‹คํŒจ๋ถ„์„ ๊ฐœ๋ณ„ ๋™๊ธฐ ์ฒ˜๋ฆฌ

5. ๋ถ„ํ• ๋œ split_folios๋„ ASYNC ๋ชจ๋“œ๋กœ ํ•œ ๋ฒˆ ๋” ์‹œ๋„

6. count_vm_events()๋กœ vmstat ์นด์šดํ„ฐ ์—…๋ฐ์ดํŠธ

migrate_folio_unmap() โ€” folio ๋งคํ•‘ ํ•ด์ œ ๋‹จ๊ณ„

์†Œ์Šค folio์˜ ๋ชจ๋“  PTE๋ฅผ migration entry๋กœ ๊ต์ฒดํ•˜๋Š” 1๋‹จ๊ณ„ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ํŽ˜์ด์ง€ ์ž ๊ธˆ, writeback ๋Œ€๊ธฐ, anon_vma ํš๋“, try_to_migrate() ํ˜ธ์ถœ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

/* mm/migrate.c:1203-1206 */
static int migrate_folio_unmap(new_folio_t get_new_folio,
free_folio_t put_new_folio, unsigned long private,
struct folio *src, struct folio **dstp, enum migrate_mode mode,
struct list_head *ret)

๋™์ž‘ ํ๋ฆ„:

1. get_new_folio()๋กœ ๋Œ€์ƒ folio ํ• ๋‹น

2. ์†Œ์Šค folio ์ž ๊ธˆ (MIGRATE_ASYNC์—์„œ๋Š” trylock, ์‹คํŒจ ์‹œ ๊ฑด๋„ˆ๋œ€)

3. writeback ์ค‘์ด๋ฉด MIGRATE_SYNC์—์„œ๋งŒ ๋Œ€๊ธฐ

4. ์ต๋ช… ํŽ˜์ด์ง€์ด๋ฉด folio_get_anon_vma()๋กœ anon_vma ์ฐธ์กฐ ํš๋“

5. try_to_migrate()๋กœ ๋ชจ๋“  PTE๋ฅผ migration entry๋กœ ๊ต์ฒด

6. ๋งคํ•‘ ํ•ด์ œ ์„ฑ๊ณต ์‹œ __migrate_folio_record()๋กœ ์ƒํƒœ ์ €์žฅ ํ›„ ๋ฐ˜ํ™˜

migrate_folio_move() โ€” folio ์ด๋™ ๋‹จ๊ณ„

๋งคํ•‘์ด ํ•ด์ œ๋œ ์†Œ์Šค folio๋ฅผ ๋Œ€์ƒ folio๋กœ ์‹ค์ œ๋กœ ์ด๋™์‹œํ‚ค๋Š” 2๋‹จ๊ณ„ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. move_to_new_folio()๋ฅผ ํ†ตํ•ด address_space๋ฅผ ๊ต์ฒดํ•˜๊ณ , ์„ฑ๊ณต ์‹œ remove_migration_ptes()๋กœ ์ƒˆ folio๋ฅผ ๋‹ค์‹œ ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.

/* mm/migrate.c:1353-1356 */
static int migrate_folio_move(free_folio_t put_new_folio, unsigned long private,
struct folio *src, struct folio *dst,
enum migrate_mode mode, enum migrate_reason reason,
struct list_head *ret)

๋™์ž‘ ํ๋ฆ„:

1. __migrate_folio_extract()๋กœ ์ด์ „ ์ƒํƒœ ๋ณต์› ์ •๋ณด ์ถ”์ถœ

2. movable_ops ํŽ˜์ด์ง€์ด๋ฉด migrate_movable_ops_page() ํ˜ธ์ถœ

3. move_to_new_folio() โ†’ mapping->a_ops->migrate_folio() ์ฝœ๋ฐฑ ํ˜ธ์ถœ

4. ์„ฑ๊ณต ์‹œ folio_add_lru(dst)๋กœ ๋Œ€์ƒ LRU ์ถ”๊ฐ€

5. ๋งคํ•‘๋œ ์ƒํƒœ์˜€์œผ๋ฉด remove_migration_ptes(src, dst)๋กœ PTE ๋ณต์›

6. ์†Œ์Šค folio ํ•ด์ œ ๋ฐ migrate_folio_done() ํ˜ธ์ถœ

move_to_new_folio() โ€” address_space ๊ต์ฒด

์‹ค์ œ folio ๊ต์ฒด๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๋งคํ•‘ ์œ ํ˜•(๋ฌด๋งคํ•‘, inaccessible, filesystem, anonymous, fallback)์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ฝœ๋ฐฑ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

/* mm/migrate.c:1090-1092 */
static int move_to_new_folio(struct folio *dst, struct folio *src,
enum migrate_mode mode)

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

  • mapping == NULL โ†’ migrate_folio() (๋‹จ์ˆœ ๋งคํ•‘ ์—†๋Š” folio)
  • mapping_inaccessible(mapping) โ†’ -EOPNOTSUPP (์ ‘๊ทผ ๋ถˆ๊ฐ€ ๋งคํ•‘)
  • mapping->a_ops->migrate_folio ์กด์žฌ โ†’ filesystem/swap ์ฝœ๋ฐฑ ํ˜ธ์ถœ
  • ๊ทธ ์™ธ โ†’ fallback_migrate_folio() (writepages ๊ฒฝ๊ณ  + ๊ฐ•์ œ ํ•ด์ œ)
  • migrate_misplaced_folio() โ€” NUMA ๋ฐธ๋Ÿฐ์‹ฑ์šฉ ๋‹จ์ผ folio ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜

    NUMA ๋ฐธ๋Ÿฐ์‹ฑ์—์„œ ์ž˜๋ชป ๋ฐฐ์น˜๋œ ๋‹จ์ผ folio๋ฅผ ์ง€์ • ๋…ธ๋“œ๋กœ ์ด๋™์‹œํ‚ต๋‹ˆ๋‹ค. migrate_misplaced_folio_prepare()๋กœ ๊ฒฉ๋ฆฌ๋œ folio๋ฅผ ๋ฐ›์•„ migrate_pages()๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

    /* mm/migrate.c:2722-2723 */
    int migrate_misplaced_folio(struct folio *folio, int node)

    ๋™์ž‘ ํ๋ฆ„:

    1. folio๋ฅผ migratepages ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€

    2. alloc_misplaced_dst_folio() ์ฝœ๋ฐฑ์œผ๋กœ ๋Œ€์ƒ ๋…ธ๋“œ์— ํ• ๋‹น

    3. MIGRATE_ASYNC + MR_NUMA_MISPLACED๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‹œ๋„

    4. ์‹คํŒจ ์‹œ putback_movable_pages()๋กœ ๋ณต์›

    5. ์„ฑ๊ณต ์‹œ NUMA_PAGE_MIGRATE vmstat ์นด์šดํ„ฐ ์—…๋ฐ์ดํŠธ

    6. ํ‹ฐ์–ด๋ง ๋ชจ๋“œ์—์„œ ์ €์†โ†’๊ณ ์† ๋…ธ๋“œ ์ด๋™ ์‹œ PGPROMOTE_SUCCESS ๊ธฐ๋ก

    migrate_vma_setup() / migrate_vma_pages() / migrate_vma_finalize() โ€” ๋””๋ฐ”์ด์Šค ๊ฒฝ๋กœ

    migrate_vma_setup()์€ VMA ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์™€ src[] ์ˆ˜์ง‘, migrate_vma_pages()๋Š” ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ๋ณต์‚ฌํ•œ ๋’ค ํŽ˜์ด์ง€ ์ƒํƒœ ๊ฐฑ์‹ , migrate_vma_finalize()๋Š” CPU ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ณต์›์„ ๋งก์Šต๋‹ˆ๋‹ค.

    /* include/linux/migrate.h:193-195 */
    int migrate_vma_setup(struct migrate_vma *args);
    void migrate_vma_pages(struct migrate_vma *migrate);
    void migrate_vma_finalize(struct migrate_vma *migrate);

    ๋™์ž‘ ํ๋ฆ„:

    1. migrate_vma_setup()์ด VMA, src[], dst[], fault_page๋ฅผ ๊ฒ€์‚ฌํ•˜๊ณ  ํŽ˜์ด์ง€๋ฅผ ์ž ๊ทผ ๋’ค ์–ธ๋งคํ•‘

    2. ๋“œ๋ผ์ด๋ฒ„๊ฐ€ dst[]๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋””๋ฐ”์ด์Šค ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌ

    3. migrate_vma_pages()๊ฐ€ ์„ฑ๊ณตํ•œ PFN์— MIGRATE_PFN_MIGRATE๋ฅผ ๋‚จ๊น€

    4. migrate_vma_finalize()๊ฐ€ CPU ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์„ ์ƒˆ ํŽ˜์ด์ง€ ๋˜๋Š” ์›๋ž˜ ํŽ˜์ด์ง€๋กœ ์ •๋ฆฌ

    ๊ตฌํ˜„์€ migrate_vma_collect_pmd()๊ฐ€ PMD/PTE๋ฅผ ํ›‘์–ด src[]๋ฅผ ์ฑ„์šฐ๊ณ , migrate_device_unmap()์ด ์žฅ์น˜ ์‚ฌ์„ค ํŽ˜์ด์ง€๋ฅผ ๋–ผ์–ด๋‚ธ ๋’ค migrate_device_pages()์™€ migrate_device_finalize()๊ฐ€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์™€ PTE๋ฅผ ๋งˆ๋ฌด๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

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

    migrate_pages()                          โ† ์ตœ์ƒ์œ„ API
    โ”œโ”€โ”€ migrate_hugetlbs()                   โ† HugeTLB ๋จผ์ € ์ฒ˜๋ฆฌ
    โ”‚   โ””โ”€โ”€ unmap_and_move_huge_page()
    โ”‚       โ”œโ”€โ”€ get_new_folio()              โ† ๋Œ€์ƒ ํ• ๋‹น
    โ”‚       โ”œโ”€โ”€ try_to_migrate()             โ† PTE โ†’ migration entry
    โ”‚       โ””โ”€โ”€ move_to_new_folio()          โ† ์‹ค์ œ ์ด๋™
    โ”œโ”€โ”€ migrate_pages_batch()                โ† ์ผ๋ฐ˜ folio ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ
    โ”‚   โ”œโ”€โ”€ [pass 1] unmapping ๋‹จ๊ณ„
    โ”‚   โ”‚   โ”œโ”€โ”€ try_split_folio()            โ† THP ๋ถ„ํ•  ํ•„์š” ์‹œ
    โ”‚   โ”‚   โ”œโ”€โ”€ migrate_folio_unmap()        โ† PTE ๊ต์ฒด
    โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ get_new_folio()
    โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ try_to_migrate()
    โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ __migrate_folio_record()
    โ”‚   โ”‚   โ””โ”€โ”€ unmap_folios/dst_folios ๋ฆฌ์ŠคํŠธ ๊ตฌ์ถ•
    โ”‚   โ””โ”€โ”€ [pass 2] moving ๋‹จ๊ณ„
    โ”‚       โ””โ”€โ”€ migrate_folios_move()
    โ”‚           โ””โ”€โ”€ migrate_folio_move()
    โ”‚               โ”œโ”€โ”€ move_to_new_folio()  โ† ๋งคํ•‘ ๊ต์ฒด
    โ”‚               โ”œโ”€โ”€ folio_add_lru()      โ† ๋Œ€์ƒ LRU ์ถ”๊ฐ€
    โ”‚               โ””โ”€โ”€ remove_migration_ptes() โ† PTE ๋ณต์›
    โ””โ”€โ”€ migrate_pages_sync()                 โ† ๋™๊ธฐ ๋ชจ๋“œ ์‹œ
    โ”œโ”€โ”€ migrate_pages_batch(ASYNC)       โ† ๋จผ์ € ASYNC๋กœ ์‹œ๋„
    โ””โ”€โ”€ ๊ฐœ๋ณ„ ๋™๊ธฐ ์ฒ˜๋ฆฌ (๋‚จ์€ ์‹คํŒจ๋ถ„)
    
    migrate_vma_setup()                      โ† ๋””๋ฐ”์ด์Šค ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ง„์ž…
    โ”œโ”€โ”€ migrate_vma_collect()                โ† ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์›Œํฌ
    โ”‚   โ””โ”€โ”€ walk_page_range(migrate_vma_walk_ops)
    โ”‚       โ””โ”€โ”€ migrate_vma_collect_pmd()
    โ”‚           โ”œโ”€โ”€ migrate_vma_collect_huge_pmd()
    โ”‚           โ””โ”€โ”€ [PTE ์ˆœํšŒ] โ†’ src[] ๋ฐฐ์—ด ์ฑ„์šฐ๊ธฐ
    โ””โ”€โ”€ migrate_vma_unmap()                  โ† ๋งคํ•‘ ํ•ด์ œ
    โ””โ”€โ”€ migrate_device_unmap()
    โ”œโ”€โ”€ folio_isolate_lru()
    โ””โ”€โ”€ try_to_migrate()

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

    ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ชจ๋“œ ๋น„๊ต

    ๋ชจ๋“œ๋™์ž‘ ๋ฐฉ์‹์ž ๊ธˆ ๋ธ”๋กwriteback ๋Œ€๊ธฐ์‚ฌ์šฉ ์‹œ์ 
    `MIGRATE_ASYNC`์ ˆ๋Œ€ ๋ธ”๋กํ•˜์ง€ ์•Š์Œtrylock๋งŒ ์‚ฌ์šฉ๋Œ€๊ธฐ ์•ˆ ํ•จCompaction, proactive
    `MIGRATE_SYNC_LIGHT`๋Œ€๋ถ€๋ถ„์˜ ์ž ๊ธˆ์—์„œ ๋ธ”๋ก ๊ฐ€๋Šฅlock ํ—ˆ์šฉuptodata ์•„๋‹Œ ๊ฒฝ์šฐ๋งŒNUMA ๋ฐธ๋Ÿฐ์‹ฑ
    `MIGRATE_SYNC`๋ชจ๋“  ์ž ๊ธˆ์—์„œ ๋ธ”๋กlock ํ—ˆ์šฉ๋Œ€๊ธฐmove_pages ์‹œ์Šคํ…œ ์ฝœ

    ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‚ฌ์œ (migrate_reason) ๋น„๊ต

    ์‚ฌ์œ ์ƒ์ˆ˜ํŠธ๋ฆฌ๊ฑฐ
    Compaction`MR_COMPACTION`๋‹จํŽธํ™” ํ•ด์†Œ๋ฅผ ์œ„ํ•œ kcompactd/direct compaction
    Memory Failure`MR_MEMORY_FAILURE`ํ•˜๋“œ์›จ์–ด ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฅ˜ (ECC ์ˆ˜์ • ๋ถˆ๊ฐ€)
    Memory Hotplug`MR_MEMORY_HOTPLUG`๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ์˜คํ”„๋ผ์ธ
    Syscall`MR_SYSCALL``move_pages()` ์‹œ์Šคํ…œ ์ฝœ
    mbind`MR_MEMPOLICY_MBIND``mbind()`๋กœ NUMA ์ •์ฑ… ๋ณ€๊ฒฝ ์‹œ
    NUMA Misplaced`MR_NUMA_MISPLACED`AutoNUMA๊ฐ€ ์ž˜๋ชป ๋ฐฐ์น˜๋œ ํŽ˜์ด์ง€ ๊ฐ์ง€
    Contig Range`MR_CONTIG_RANGE`์—ฐ์† ๋ฒ”์œ„ ํ• ๋‹น (CMA ๋“ฑ)
    Long-term Pin`MR_LONGTERM_PIN`VFIO/์žฅ์น˜ ๋“œ๋ผ์ด๋ฒ„์˜ ์žฅ๊ธฐ ํ•€ning
    Demotion`MR_DEMOTION`๋ฉ”๋ชจ๋ฆฌ ํ‹ฐ์–ด๋ง์—์„œ ๊ณ ์†โ†’์ €์† ํ•˜ํ–ฅ
    DAMON`MR_DAMON`DAMON ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ํŒจํ„ด ๋ถ„์„

    ๋””๋ฐ”์ด์Šค ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ vs ์ผ๋ฐ˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋น„๊ต

    ํ•ญ๋ชฉ์ผ๋ฐ˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ (migrate.c)๋””๋ฐ”์ด์Šค ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ (migrate_device.c)
    ์ง„์ž… ๋ฐฉ์‹`migrate_pages()` + `migrate_reason``migrate_vma_setup()` โ†’ `migrate_vma_pages()` โ†’ `migrate_vma_finalize()`
    ๋Œ€์ƒLRU์— ์žˆ๋Š” ์ผ๋ฐ˜ folioZONE_DEVICE folio (GPU/HBM)
    ๊ฒฉ๋ฆฌ`folio_isolate_lru()``folio_get()`์œผ๋กœ ๊ณ ์ • (LRU ์—†์Œ)
    ๋งคํ•‘ ํ•ด์ œ`try_to_migrate()` + rmap walk`try_to_migrate()` + mm_walk
    ์ฝœ๋ฐฑ`mapping->a_ops->migrate_folio()`๋“œ๋ผ์ด๋ฒ„๊ฐ€ dst ํ• ๋‹น + ๋ณต์‚ฌ
    API`migrate_pages()``migrate_vma_setup/pages/finalize()`
    THP ์ฒ˜๋ฆฌ๋ฐฐ์น˜ ๋‚ด ๋ถ„ํ•  ์ง€์›`migrate_vma_split_folio()`
    ๊ฒฐ๊ณผ ํ™•์ธ๋ฐ˜ํ™˜๊ฐ’ + ret_succeeded`src[]` ๋ฐฐ์—ด์˜ MIGRATE_PFN_MIGRATE ํ”Œ๋ž˜๊ทธ

    ์‹คํŒจ ์‹œ ์ฒ˜๋ฆฌ ๋น„๊ต

    ๋ฐ˜ํ™˜๊ฐ’์˜๋ฏธ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•
    0์„ฑ๊ณตsrc folio ํ•ด์ œ, dst LRU ์ถ”๊ฐ€
    `-EAGAIN`์ผ์‹œ์  ์‹คํŒจ๋ฆฌ์ŠคํŠธ์— ์œ ์ง€, ์žฌ์‹œ๋„
    `-ENOMEM`๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ๋‚จ์€ ์ฒ˜๋ฆฌ ์ค‘๋‹จ, ์‹คํŒจ ๋ชฉ๋ก์œผ๋กœ ์ด๋™
    `-EBUSY`์˜๊ตฌ ์‹คํŒจ์‹คํŒจ ๋ชฉ๋ก์œผ๋กœ ์ด๋™, ์žฌ์‹œ๋„ ์•ˆ ํ•จ
    `-EOPNOTSUPP`๋ฏธ์ง€์› ๋งคํ•‘inaccessible ๋งคํ•‘

    ๊ด€๋ จ ๋ฌธ์„œ

  • ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š” โ€” ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์•„ํ‚คํ…์ฒ˜ ์กฐ๊ฐ๋„
  • Buddy Allocator โ€” ํŽ˜์ด์ง€ ํ• ๋‹น ๊ธฐ๋ฐ˜
  • Compaction โ€” ๋‹จํŽธํ™” ํ•ด์†Œ๋ฅผ ์œ„ํ•œ Two-Scanner ์•Œ๊ณ ๋ฆฌ์ฆ˜
  • CMA โ€” ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์—์„œ์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ™œ์šฉ
  • NUMA โ€” NUMA ๋ฐธ๋Ÿฐ์‹ฑ๊ณผ ์ž๋™ ํŽ˜์ด์ง€ ์ด๋™
  • HMM โ€” ์ด๊ธฐ์ข… ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ํ”„๋ ˆ์ž„์›Œํฌ
  • Hotplug โ€” ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ์˜จ๋ผ์ธ/์˜คํ”„๋ผ์ธ
  • Folio โ€” folio ์ถ”์ƒํ™”์™€ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ†ตํ•ฉ
  • Memory Tiers โ€” ๋ฉ”๋ชจ๋ฆฌ ํ‹ฐ์–ด๋ง๊ณผ demotion