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_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 ๋น๊ต
| ๊ตฌ๋ถ | NUMA | UMA |
|---|---|---|
| ๋ ธ๋ ์ | 2๊ฐ ์ด์ | 1๊ฐ |
| ์ด๊ธฐํๅคๆๅบฆ | ๋์ (๋ ธ๋๋ณ ์ฒ๋ฆฌ) | ๋ฎ์ (๋จ์ผ ๋ ธ๋) |
| ๋ฉ๋ชจ๋ฆฌ ๋ฐฐ์น | ๋ ธ๋๋ณ ๋ถ์ฐ | ์ฐ์ ํ ๋น |
| ๊ด๋ จ ํจ์ | early_pfn_to_nid(), get_pfn_range_for_nid() | ๋จ์ ์ด๊ธฐํ |