73. MM ์ดˆ๊ธฐํ™” (mm/mm_init.c)

๊ฐœ์š”

mm/mm_init.c๋Š” Linux ์ปค๋„ ๋ถ€ํŒ… ์‹œ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์„œ๋ธŒ์‹œ์Šคํ…œ์˜ ์ดˆ๊ธฐํ™” ๊ณผ์ •์„ ๋‹ด๋‹นํ•˜๋Š” ํ•ต์‹ฌ ์†Œ์Šค ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ์€ ๋ฉ”๋ชจ๋ฆฌ ๋งต ๊ตฌ์„ฑ, ์กด ์„ค์ •, ํŽ˜์ด์ง€ ์ดˆ๊ธฐํ™”, ๊ตฌ์กฐ์ฒด ํ• ๋‹น ๋“ฑ ๋ถ€ํŒ… ์ดˆ๊ธฐ์˜ ๋ชจ๋“  ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

/* mm/mm_init.c - ๋ฉ”๋ชจ๋ฆฌ ์ดˆ๊ธฐํ™” ๊ฒ€์ฆ ๋ฐ ๋””๋ฒ„๊น… - 2743์ค„ */
/* SPDX-License-Identifier: GPL-2.0-only */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/memblock.h>
#include <linux/page-isolation.h>
#include <linux/mm.h>
#include <linux/mmzone.h>
#include <linux/mm_types.h>

์ด ํŒŒ์ผ์€ mm_core_init(), free_area_init(), memmap_init() ๋“ฑ์˜ ํ•ต์‹ฌ ํ•จ์ˆ˜๋ฅผ ํฌํ•จํ•˜๋ฉฐ, ๋ถ€ํŒ… ๊ณผ์ •์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์˜ ๊ธฐ๋ฐ˜์„ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค. ์•„ํ‚คํ…์ฒ˜๋ณ„ ์ฐจ์ด๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ , NUMA ์‹œ์Šคํ…œ์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ์น˜๋ฅผ ์„ค์ •ํ•˜๋ฉฐ, zonelist๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋“ฑ ์ปค๋„ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์˜ ๋ชจ๋“  ๊ฒƒ์„ ์‹œ์ž‘ํ•˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค.

MM ์ดˆ๊ธฐํ™” ํ๋ฆ„๋„

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

# mm_init.c ์ค„ ์ˆ˜ ํ™•์ธ
wc -l ~/Chamber_linux/linux-7.0-source/mm/mm_init.c

# ์ฃผ์š” ํ•จ์ˆ˜ ์ •์˜ ํ™•์ธ
grep -n "^void\|^static void\|^static int\|^int" ~/Chamber_linux/linux-7.0-source/mm/mm_init.c | head -30

# ์ดˆ๊ธฐํ™” ๊ด€๋ จ ๋งคํฌ๋กœ ํ™•์ธ
grep -n "#define\|#ifdef" ~/Chamber_linux/linux-7.0-source/mm/mm_init.c | head -20

# early_param ์ •์˜ ํ™•์ธ
grep -n "early_param" ~/Chamber_linux/linux-7.0-source/mm/mm_init.c

# CONFIG ์˜ต์…˜ ํ™•์ธ
grep -n "CONFIG_" ~/Chamber_linux/linux-7.0-source/mm/mm_init.c | sort -u | head -20

# ์กด ๊ด€๋ จ ๋ณ€์ˆ˜ ํ™•์ธ
grep -n "zone_movable_pfn\|arch_zone_" ~/Chamber_linux/linux-7.0-source/mm/mm_init.c | head -15

# memblock ์‚ฌ์šฉ ํ™•์ธ
grep -n "memblock" ~/Chamber_linux/linux-7.0-source/mm/mm_init.c | head -15

# mm_core_init ํ˜ธ์ถœ ํ๋ฆ„ ํ™•์ธ
grep -n "mm_core_init\|free_area_init\|memmap_init" ~/Chamber_linux/linux-7.0-source/mm/mm_init.c

# ํŽ˜์ด์ง€ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜ ํ™•์ธ
grep -n "__init_single_page\|memmap_init_range\|init_deferred_page" ~/Chamber_linux/linux-7.0-source/mm/mm_init.c

# NUMA ๊ด€๋ จ ํ•จ์ˆ˜ ํ™•์ธ
grep -n "early_pfn_to_nid\|setup_nr_node_ids\|get_pfn_range_for_nid" ~/Chamber_linux/linux-7.0-source/mm/mm_init.c

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

1. mminit_pfnnid_cache (ํŒŒ์ผ:๋ผ์ธ 605-609)

PFN-to-NID ๋ณ€ํ™˜ ์บ์‹œ์ž…๋‹ˆ๋‹ค. ์ดˆ๊ธฐ ๋ถ€ํŒ… ์‹œ ๋น ๋ฅธ ์กฐํšŒ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

/* ์ดˆ๊ธฐ PFN-NID ์บ์‹œ - ๋น ๋ฅธ ์กฐํšŒ๋ฅผ ์œ„ํ•œ ์บ์‹œ */
struct mminit_pfnnid_cache {
unsigned long last_start;   /* ๋งˆ์ง€๋ง‰ ๊ฒ€์ƒ‰ ์‹œ์ž‘ PFN */
unsigned long last_end;     /* ๋งˆ์ง€๋ง‰ ๊ฒ€์ƒ‰ ๋ PFN */
int last_nid;               /* ๋งˆ์ง€๋ง‰ ๊ฒ€์ƒ‰๋œ ๋…ธ๋“œ ID */
};

2. zone_movable_pfn (ํŒŒ์ผ:๋ผ์ธ 238)

๊ฐ ๋…ธ๋“œ๋ณ„ ZONE_MOVABLE ์‹œ์ž‘ PFN ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค.

/* ๋…ธ๋“œ๋ณ„ ZONE_MOVABLE ์‹œ์ž‘ PFN */
static unsigned long zone_movable_pfn[MAX_NUMNODES] __initdata;

3. required_kernelcore/required_movablecore (ํŒŒ์ผ:๋ผ์ธ 240-243)

์ปค๋„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ง€์ •๋œ ์ปค๋„/์ด๋™ ๊ฐ€๋Šฅ ์ฝ”์–ด ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ์ž…๋‹ˆ๋‹ค.

/* ์ปค๋„์ฝ”์–ด/์ด๋™๊ฐ€๋Šฅ์ฝ”์–ด ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ */
static unsigned long required_kernelcore __initdata;
static unsigned long required_kernelcore_percent __initdata;
static unsigned long required_movablecore __initdata;
static unsigned long required_movablecore_percent __initdata;

4. deferred_struct_pages (ํŒŒ์ผ:๋ผ์ธ 248)

์ง€์—ฐ๋œ ๊ตฌ์กฐ์ฒด ํŽ˜์ด์ง€ ์ดˆ๊ธฐํ™” ํ™œ์„ฑํ™” ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค.

/* ์ง€์—ฐ๋œ ๊ตฌ์กฐ์ฒด ํŽ˜์ด์ง€ ์ดˆ๊ธฐํ™” ํ”Œ๋ž˜๊ทธ */
static bool deferred_struct_pages __meminitdata;

5. pgdat_set_deferred_range (ํŒŒ์ผ:๋ผ์ธ 690-693)

์ง€์—ฐ๋œ ์ดˆ๊ธฐํ™” ๋ฒ”์œ„๋ฅผ ์„ค์ •ํ•˜๋Š” ์ธ๋ผ์ธ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

/* ์ง€์—ฐ๋œ ์ดˆ๊ธฐํ™” ๋ฒ”์œ„ ์„ค์ • */
static inline void pgdat_set_deferred_range(pg_data_t *pgdat)
{
pgdat->first_deferred_pfn = ULONG_MAX;
}

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

1. free_area_init() (ํŒŒ์ผ:๋ผ์ธ 1820-1933)

๋ชจ๋“  pg_data_t์™€ ์กด ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฉ”์ธ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

/* ๋ชจ๋“  ๋…ธ๋“œ์™€ ์กด ์ดˆ๊ธฐํ™” */
static void __init free_area_init(void)
{
unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0 };
unsigned long start_pfn, end_pfn;
int i, nid, zone;
bool descending;

arch_zone_limits_init(max_zone_pfn);
sparse_init();

start_pfn = PHYS_PFN(memblock_start_of_DRAM());
descending = arch_has_descending_max_zone_pfns();

/* ์กด ๋ฒ”์œ„ ์„ค์ • */
for (i = 0; i < MAX_NR_ZONES; i++) {
if (descending)
zone = MAX_NR_ZONES - i - 1;
else
zone = i;

if (zone == ZONE_MOVABLE)
continue;

end_pfn = max(max_zone_pfn[zone], start_pfn);
arch_zone_lowest_possible_pfn[zone] = start_pfn;
arch_zone_highest_possible_pfn[zone] = end_pfn;

start_pfn = end_pfn;
}

/* ZONE_MOVABLE ์‹œ์ž‘ PFN ์ฐพ๊ธฐ */
memset(zone_movable_pfn, 0, sizeof(zone_movable_pfn));
find_zone_movable_pfns_for_nodes();

/* ๊ฐ ๋…ธ๋“œ ์ดˆ๊ธฐํ™” */
for_each_node(nid) {
pg_data_t *pgdat;
if (!NODE_DATA(nid))
alloc_offline_node_data(nid);

pgdat = NODE_DATA(nid);
free_area_init_node(nid);

if (pgdat->node_present_pages) {
node_set_state(nid, N_MEMORY);
check_for_memory(pgdat);
}
}

calc_nr_kernel_pages();
memmap_init();
set_high_memory();
}

2. free_area_init_node() (ํŒŒ์ผ:๋ผ์ธ 1714-1746)

๋‹จ์ผ ๋…ธ๋“œ์˜ ๋ฉ”๋ชจ๋ฆฌ ๋งต์„ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

/* ๋‹จ์ผ ๋…ธ๋“œ ์ดˆ๊ธฐํ™” */
static void __init free_area_init_node(int nid)
{
pg_data_t *pgdat = NODE_DATA(nid);
unsigned long start_pfn = 0;
unsigned long end_pfn = 0;

get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);

pgdat->node_id = nid;
pgdat->node_start_pfn = start_pfn;
pgdat->per_cpu_nodestats = NULL;

if (start_pfn != end_pfn) {
calculate_node_totalpages(pgdat, start_pfn, end_pfn);
} else {
reset_memoryless_node_totalpages(pgdat);
}

alloc_node_mem_map(pgdat);
pgdat_set_deferred_range(pgdat);
free_area_init_core(pgdat);
lru_gen_init_pgdat(pgdat);
}

3. memmap_init_range() (ํŒŒ์ผ:๋ผ์ธ 872-939)

๋ฉ”๋ชจ๋ฆฌ ๋งต ๋ฒ”์œ„๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

/* ๋ฉ”๋ชจ๋ฆฌ ๋งต ๋ฒ”์œ„ ์ดˆ๊ธฐํ™” */
void __meminit memmap_init_range(unsigned long size, int nid, unsigned long zone,
unsigned long start_pfn, unsigned long zone_end_pfn,
enum meminit_context context,
struct vmem_altmap *altmap, int migratetype,
bool isolate_pageblock)
{
unsigned long pfn, end_pfn = start_pfn + size;
struct page *page;

for (pfn = start_pfn; pfn < end_pfn; ) {
if (context == MEMINIT_EARLY) {
if (overlap_memmap_init(zone, &pfn))
continue;
if (defer_init(nid, pfn, zone_end_pfn)) {
deferred_struct_pages = true;
break;
}
}

page = pfn_to_page(pfn);
__init_single_page(page, pfn, zone, nid);

if (pageblock_aligned(pfn)) {
init_pageblock_migratetype(page, migratetype, isolate_pageblock);
cond_resched();
}
pfn++;
}
}

4. __init_single_page() (ํŒŒ์ผ:๋ผ์ธ 581-597)

๊ฐœ๋ณ„ ํŽ˜์ด์ง€ ๊ตฌ์กฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

/* ๊ฐœ๋ณ„ ํŽ˜์ด์ง€ ์ดˆ๊ธฐํ™” */
void __meminit __init_single_page(struct page *page, unsigned long pfn,
unsigned long zone, int nid)
{
mm_zero_struct_page(page);
set_page_links(page, zone, nid, pfn);
init_page_count(page);
atomic_set(&page->_mapcount, -1);
page_cpupid_reset_last(page);
page_kasan_tag_reset(page);

INIT_LIST_HEAD(&page->lru);
}

5. mm_core_init() (ํŒŒ์ผ:๋ผ์ธ 2694-2743)

์ปค๋„ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์˜ ๋ฉ”์ธ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

/* ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ํ•ต์‹ฌ ์ดˆ๊ธฐํ™” */
void __init mm_core_init(void)
{
arch_mm_preinit();

BUILD_BUG_ON(MAX_ZONELISTS > 2);
build_all_zonelists(NULL);
page_alloc_init_cpuhp();
alloc_tag_sec_init();

page_ext_init_flatmem();
mem_debugging_and_hardening_init();
kfence_alloc_pool_and_metadata();
report_meminit();
kmsan_init_shadow();
stack_depot_early_init();

kho_memory_init();

memblock_free_all();
mem_init();
kmem_cache_init();

page_ext_init_flatmem_late();
kmemleak_init();
ptlock_cache_init();
pgtable_cache_init();
debug_objects_mem_init();
vmalloc_init();

if (!deferred_struct_pages)
page_ext_init();

init_espfix_bsp();
pti_init();
kmsan_init_runtime();
mm_cache_init();
execmem_init();
}

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

์ปค๋„ ๋ถ€ํŒ…
โ”œโ”€โ”€ mm_core_init_early()
โ”‚   โ”œโ”€โ”€ hugetlb_cma_reserve()
โ”‚   โ”œโ”€โ”€ hugetlb_bootmem_alloc()
โ”‚   โ””โ”€โ”€ free_area_init()
โ”‚       โ”œโ”€โ”€ arch_zone_limits_init()
โ”‚       โ”œโ”€โ”€ sparse_init()
โ”‚       โ”œโ”€โ”€ find_zone_movable_pfns_for_nodes()
โ”‚       โ””โ”€โ”€ for_each_node()
โ”‚           โ””โ”€โ”€ free_area_init_node()
โ”‚               โ”œโ”€โ”€ get_pfn_range_for_nid()
โ”‚               โ”œโ”€โ”€ calculate_node_totalpages()
โ”‚               โ”œโ”€โ”€ alloc_node_mem_map()
โ”‚               โ””โ”€โ”€ free_area_init_core()
โ”‚                   โ”œโ”€โ”€ pgdat_init_internals()
โ”‚                   โ””โ”€โ”€ for_each_zone()
โ”‚                       โ””โ”€โ”€ zone_init_internals()
โ”‚
โ””โ”€โ”€ mm_core_init()
โ”œโ”€โ”€ arch_mm_preinit()
โ”œโ”€โ”€ build_all_zonelists()
โ”œโ”€โ”€ page_alloc_init_cpuhp()
โ”œโ”€โ”€ mem_debugging_and_hardening_init()
โ”œโ”€โ”€ memblock_free_all()
โ”œโ”€โ”€ mem_init()
โ”œโ”€โ”€ kmem_cache_init()
โ”œโ”€โ”€ vmalloc_init()
โ””โ”€โ”€ execmem_init()

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

์ดˆ๊ธฐํ™” ๊ฒฝ๋กœ ๋น„๊ต

๊ตฌ๋ถ„mm_core_init_early()mm_core_init()
์‹œ์ ๋ถ€ํŒ… ์ดˆ๊ธฐ๋ถ€ํŒ… ํ›„๊ธฐ
์—ญํ• ๋ฉ”๋ชจ๋ฆฌ ๋งต ๊ธฐ๋ณธ ๊ตฌ์กฐ ์„ค์ •ํ• ๋‹น์ž ๋ฐ ๋””๋ฒ„๊น… ์ดˆ๊ธฐํ™”
์ฃผ์š” ํ•จ์ˆ˜free_area_init()memblock_free_all(), kmem_cache_init()
์‚ฌ์šฉ ๊ฐ€๋Šฅ์ œํ•œ์ ์ „์ฒด ๊ธฐ๋Šฅ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

์กด ์ดˆ๊ธฐํ™” ์ƒํƒœ ๋น„๊ต

์ƒํƒœ์„ค๋ช…๊ด€๋ จ ํ•จ์ˆ˜
์ดˆ๊ธฐํ™” ์ „๋ฉ”๋ชจ๋ฆฌ ๋งต ๋ฏธ์ •์˜memblock ๋‹จ๊ณ„
์ดˆ๊ธฐํ™” ์ค‘ํŽ˜์ด์ง€ ๊ตฌ์กฐ์ฒด ์„ค์ • ์ค‘memmap_init_range()
์ดˆ๊ธฐํ™” ์™„๋ฃŒํ• ๋‹น ๊ฐ€๋Šฅ ์ƒํƒœfree_area_init_core() ์™„๋ฃŒ

NUMA vs UMA ๋น„๊ต

๊ตฌ๋ถ„NUMAUMA
๋…ธ๋“œ ์ˆ˜2๊ฐœ ์ด์ƒ1๊ฐœ
์ดˆ๊ธฐํ™”ๅคๆ‚ๅบฆ๋†’์Œ (๋…ธ๋“œ๋ณ„ ์ฒ˜๋ฆฌ)๋‚ฎ์Œ (๋‹จ์ผ ๋…ธ๋“œ)
๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ์น˜๋…ธ๋“œ๋ณ„ ๋ถ„์‚ฐ์—ฐ์† ํ• ๋‹น
๊ด€๋ จ ํ•จ์ˆ˜early_pfn_to_nid(), get_pfn_range_for_nid()๋‹จ์ˆœ ์ดˆ๊ธฐํ™”

๊ด€๋ จ ๋ฌธ์„œ

  • 00-๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š”
  • 01-Buddy Allocator
  • 04-Memblock
  • 11-Compaction
  • 13-NUMA
  • 22-Hotplug
  • 64-MMU ์—†๋Š” ์‹œ์Šคํ…œ
  • ์ฐธ๊ณ  ์ž๋ฃŒ

  • Linux Kernel Documentation - mm/
  • Linux Kernel Source - mm/mm_init.c