Memblock ํ• ๋‹น์ž

๊ฐœ์š” (Overview)

Memblock์€ Linux ์ปค๋„ ๋ถ€ํŒ… ์ดˆ๊ธฐ์— ์ผ๋ฐ˜ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ž๊ฐ€ ์•„์ง ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์—์„œ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค. ์‹œ์Šคํ…œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ "์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฉ”๋ชจ๋ฆฌ(memory)"์™€ "์˜ˆ์•ฝ๋œ ๋ฉ”๋ชจ๋ฆฌ(reserved)" ๋‘ ๊ฐ€์ง€ ์ปฌ๋ ‰์…˜์œผ๋กœ ๋‚˜๋ˆ„์–ด ๊ด€๋ฆฌํ•˜๋ฉฐ, ํŽŒ์›จ์–ด(E820/UEFI/Device Tree)๊ฐ€ ์ „๋‹ฌํ•œ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ์„ ํŒŒ์‹ฑํ•˜์—ฌ ์ดˆ๊ธฐ ํ• ๋‹น์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๋ถ€ํŒ…์ด ์™„๋ฃŒ๋˜๋ฉด memblock_free_all()์„ ํ†ตํ•ด Buddy Allocator์— ๋‚จ์€ ํŽ˜์ด์ง€๋ฅผ ๋ชจ๋‘ ๋ฐ˜ํ™˜ํ•˜๊ณ , CONFIG_ARCH_KEEP_MEMBLOCK์ด ์„ค์ •๋˜์ง€ ์•Š์œผ๋ฉด memblock ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ž์ฒด๋ฅผ ํ•ด์ œํ•œ๋‹ค.

memblock์€ ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ๋ฉ”๋ชจ๋ฆฌ ํƒ€์ž…์„ ๊ด€๋ฆฌํ•œ๋‹ค: memory(์ปค๋„์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ), reserved(์ด๋ฏธ ํ• ๋‹น/์˜ˆ์•ฝ๋œ ์˜์—ญ), physmem(์‹ค์ œ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ, ์ผ๋ถ€ ์•„ํ‚คํ…์ฒ˜์—์„œ๋งŒ ์ง€์›). ๊ฐ ํƒ€์ž…์€ struct memblock_type์œผ๋กœ ํ‘œํ˜„๋˜๋ฉฐ, ์ •๋ ฌ๋œ memblock_region ๋ฐฐ์—ด์„ ํฌํ•จํ•œ๋‹ค. ํ• ๋‹น์€ bottom-up ๋˜๋Š” top-down ๋ฐฉ์‹์œผ๋กœ ์ˆ˜ํ–‰๋˜๋ฉฐ, NUMA ๋…ธ๋“œ ํ• ๋‹น, ๋ฏธ๋Ÿฌ๋ง, nomap ํ”Œ๋ž˜๊ทธ ๋“ฑ์„ ์ง€์›ํ•œ๋‹ค.

์ผ์ƒ ๋น„์œ : memblock์€ ์ •์‹ ์ฐฝ๊ณ  ๊ด€๋ฆฌ ์‹œ์Šคํ…œ(Buddy Allocator)์ด ์ผœ์ง€๊ธฐ ์ „, ์ด์‚ฌ ํ˜„์žฅ์—์„œ ์ž„์‹œ๋กœ ์“ฐ๋Š” ํฐ ์ข…์ด ๋ฐฐ์น˜๋„์™€ ๊ฐ™๋‹ค. ํŽŒ์›จ์–ด๊ฐ€ ๋„˜๊ฒจ์ค€ ๊ฑด๋ฌผ ๋„๋ฉด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์€ memory์— ํ‘œ์‹œํ•˜๊ณ , ์ปค๋„ ์ด๋ฏธ์ง€, initrd, ACPI/EFI ํ…Œ์ด๋ธ”, crashkernel์ฒ˜๋Ÿผ ์ด๋ฏธ ์ ์œ ํ•œ ๋ฐฉ์€ reserved์— ํ‘œ์‹œํ•œ ๋’ค, ๊ณต์‚ฌ๊ฐ€ ๋๋‚˜๋ฉด ๋‚จ์€ ๋ฐฉ ๋ชฉ๋ก์„ Buddy Allocator์— ๋„˜๊ธด๋‹ค.

์†Œ์Šค ํŒŒ์ผ ๊ฒฝ๋กœ:
mm/memblock.c              โ† ํ•ต์‹ฌ ๊ตฌํ˜„ (2768์ค„)
include/linux/memblock.h   โ† ๊ณต๊ฐœ API ๋ฐ ์ž๋ฃŒ๊ตฌ์กฐ ์ •์˜ (624์ค„)

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

# memblock ๋””๋ฒ„๊ทธ ํ™œ์„ฑํ™” (์ปค๋„ ํŒŒ๋ผ๋ฏธํ„ฐ)
# ๋ถ€ํŒ… ์‹œ: memblock=debug

# ํ˜„์žฌ memblock ์ƒํƒœ ํ™•์ธ (CONFIG_MEMBLOCK_DEBUG ํ™œ์„ฑํ™” ์‹œ)
dmesg | grep -i memblock

# ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ์ „์ฒด ํฌ๊ธฐ ํ™•์ธ
cat /proc/meminfo | head -5

# Buddy Allocator์— ๋ฐ˜ํ™˜๋œ ํ›„ ๋ฉ”๋ชจ๋ฆฌ ํ˜„ํ™ฉ
cat /proc/buddyinfo

# memblock์ด ๊ด€๋ฆฌํ•˜๋Š” ์˜์—ญ ํ™•์ธ (debugfs)
sudo cat /sys/kernel/debug/memblock/memory 2>/dev/null
sudo cat /sys/kernel/debug/memblock/reserved 2>/dev/null

# ์ปค๋„ ๋ถ€ํŒ… ์‹œ memblock ๋ฉ”์‹œ์ง€ ํ™•์ธ
dmesg | grep -E 'BIOS-e820|Memory:|MEMBLOCK'

# NUMA ๋…ธ๋“œ๋ณ„ ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ์น˜
numactl -H 2>/dev/null

# ํŽŒ์›จ์–ด/์ปค๋„์ด ๋ณธ ๋ฌผ๋ฆฌ ์ฃผ์†Œ ๊ณต๊ฐ„
cat /proc/iomem | head -80

# memblock์— ์˜ํ–ฅ์„ ์ค€ ๋ถ€ํŒ… ํŒŒ๋ผ๋ฏธํ„ฐ ํ™•์ธ
cat /proc/cmdline

# initrd, crashkernel, reserved-memory๊นŒ์ง€ ํ•จ๊ป˜ ํ™•์ธ
dmesg | grep -Ei 'memblock|BIOS-e820|efi: mem|OF: fdt|reserved-memory|initrd|crashkernel'

# CONFIG_HAVE_MEMBLOCK_PHYS_MAP + debugfs ์œ ์ง€ ์‹œ physmem ํ™•์ธ
sudo cat /sys/kernel/debug/memblock/physmem 2>/dev/null

# ์ง์ ‘ ๋งคํ•‘, ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”, vmalloc ์‚ฌ์šฉ๋Ÿ‰ ํ™•์ธ
grep -E 'Vmalloc|DirectMap|PageTables' /proc/meminfo

# x86 CONFIG_X86_PTDUMP + debugfs ํ™œ์„ฑํ™” ์‹œ ์ปค๋„ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ํ™•์ธ
sudo cat /sys/kernel/debug/kernel_page_tables 2>/dev/null | head -40

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

struct memblock_region โ€” ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ ํ•˜๋‚˜

struct memblock_region {
phys_addr_t base;
phys_addr_t size;
enum memblock_flags flags;
#ifdef CONFIG_NUMA
int nid;
#endif
};

์œ„์น˜: include/linux/memblock.h:73-80. base์™€ size๋Š” ๋ฐ˜์—ด๋ฆผ ๊ตฌ๊ฐ„ [base, base + size)๋ฅผ ๋งŒ๋“ค๊ณ , flags๋Š” HOTPLUG/MIRROR/NOMAP ๊ฐ™์€ ์†์„ฑ์„ ๋‹ด๋Š”๋‹ค. CONFIG_NUMA์—์„œ๋Š” nid๊ฐ€ ํ•จ๊ป˜ ์ €์žฅ๋˜์–ด ์ดˆ๊ธฐ ๋ฌผ๋ฆฌ ์ฃผ์†Œ ๋ฒ”์œ„๋ฅผ NUMA ๋…ธ๋“œ๋กœ ๋ฌถ์„ ์ˆ˜ ์žˆ๋‹ค.

struct memblock_type โ€” ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ ์ปฌ๋ ‰์…˜

struct memblock_type {
unsigned long cnt;
unsigned long max;
phys_addr_t total_size;
struct memblock_region *regions;
char *name;
};

์œ„์น˜: include/linux/memblock.h:90-96. cnt๋Š” ํ˜„์žฌ ์œ ํšจํ•œ region ๊ฐœ์ˆ˜์ด๊ณ  max๋Š” ๋ฐฐ์—ด ์šฉ๋Ÿ‰์ด๋‹ค. total_size๋Š” ์ด ํƒ€์ž…์— ๋“ค์–ด ์žˆ๋Š” ์˜์—ญ ํฌ๊ธฐ์˜ ํ•ฉ์ด๋ฉฐ, regions๋Š” base ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ๋œ memblock_region ๋ฐฐ์—ด์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค.

struct memblock โ€” ์ „์—ญ ํ• ๋‹น์ž ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ

struct memblock {
bool bottom_up;  /* is bottom up direction? */
phys_addr_t current_limit;
struct memblock_type memory;
struct memblock_type reserved;
};

์œ„์น˜: include/linux/memblock.h:105-110. bottom_up์€ ๋‚ฎ์€ ์ฃผ์†Œ๋ถ€ํ„ฐ ์ฐพ์„์ง€ ๋†’์€ ์ฃผ์†Œ๋ถ€ํ„ฐ ์ฐพ์„์ง€๋ฅผ ์ •ํ•˜๊ณ , current_limit์€ MEMBLOCK_ALLOC_ACCESSIBLE ์š”์ฒญ์˜ ์ƒํ•œ์œผ๋กœ ์“ฐ์ธ๋‹ค. memory๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ RAM ๋ชฉ๋ก, reserved๋Š” ์ด๋ฏธ ์ ์œ ๋œ ๋ฌผ๋ฆฌ ์ฃผ์†Œ ๋ชฉ๋ก์ด๋‹ค.

enum memblock_flags โ€” ์˜์—ญ ์†์„ฑ ํ”Œ๋ž˜๊ทธ

enum memblock_flags {
MEMBLOCK_NONE       = 0x0,  /* ํŠน๋ณ„ํ•œ ์š”์ฒญ ์—†์Œ */
MEMBLOCK_HOTPLUG    = 0x1,  /* ํ•ซํ”Œ๋Ÿฌ๊ทธ ๊ฐ€๋Šฅํ•œ ์˜์—ญ */
MEMBLOCK_MIRROR     = 0x2,  /* ๋ฏธ๋Ÿฌ๋ง๋œ ์˜์—ญ */
MEMBLOCK_NOMAP      = 0x4,  /* don't add to kernel direct mapping */
MEMBLOCK_DRIVER_MANAGED = 0x8,  /* always detected via a driver */
MEMBLOCK_RSRV_NOINIT    = 0x10, /* don't initialize struct pages */
MEMBLOCK_RSRV_KERN  = 0x20, /* memory reserved for kernel use */
MEMBLOCK_KHO_SCRATCH    = 0x40, /* scratch memory for kexec handover */
};

์œ„์น˜: include/linux/memblock.h:55-64. MEMBLOCK_NOMAP์€ ์ง์ ‘ ๋งคํ•‘์—์„œ ์ œ์™ธ๋˜๋Š” RAM์„ ํ‘œ์‹œํ•˜๊ณ , MEMBLOCK_RSRV_KERN์€ memblock ํ• ๋‹น API๊ฐ€ ์˜ˆ์•ฝํ•œ ์ปค๋„์šฉ ์˜์—ญ์— ๋ถ™๋Š”๋‹ค. MEMBLOCK_DRIVER_MANAGED์™€ MEMBLOCK_KHO_SCRATCH๋Š” ์ผ๋ฐ˜ System RAM๊ณผ ๋‹ค๋ฅด๊ฒŒ ์ทจ๊ธ‰ํ•ด์•ผ ํ•˜๋Š” ์˜์—ญ์„ ๊ตฌ๋ถ„ํ•œ๋‹ค.

์ „์—ญ ์ดˆ๊ธฐํ™” ๋ฐ์ดํ„ฐ

static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_MEMORY_REGIONS] __initdata_memblock;
static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_RESERVED_REGIONS] __initdata_memblock;

struct memblock memblock __initdata_memblock = {
.memory.regions     = memblock_memory_init_regions,
.memory.max     = INIT_MEMBLOCK_MEMORY_REGIONS,
.memory.name        = "memory",

.reserved.regions   = memblock_reserved_init_regions,
.reserved.max       = INIT_MEMBLOCK_RESERVED_REGIONS,
.reserved.name      = "reserved",

.bottom_up      = false,
.current_limit      = MEMBLOCK_ALLOC_ANYWHERE,
};

์œ„์น˜: mm/memblock.c:123-140. ์ดˆ๊ธฐ ๋ฐฐ์—ด ์šฉ๋Ÿ‰์€ INIT_MEMBLOCK_MEMORY_REGIONS์™€ INIT_MEMBLOCK_RESERVED_REGIONS๋กœ ์‹œ์ž‘ํ•œ๋‹ค. ์˜์—ญ์ด ๋” ๋งŽ์ด ํ•„์š”ํ•  ๋•Œ๋Š” memblock_allow_resize() ์ดํ›„ memblock_double_array()๊ฐ€ ์ƒˆ ๋ฐฐ์—ด์„ ์žก์•„ ํ™•์žฅํ•œ๋‹ค.

struct memblock_type physmem = {
.regions        = memblock_physmem_init_regions,
.max            = INIT_PHYSMEM_REGIONS,
.name           = "physmem",
};

์œ„์น˜: mm/memblock.c:142-148. CONFIG_HAVE_MEMBLOCK_PHYS_MAP์ด ์žˆ๋Š” ์•„ํ‚คํ…์ฒ˜์—์„œ๋Š” physmem์ด ์‹ค์ œ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๋ชฉ๋ก์„ ๋ณ„๋„๋กœ ๋ณด์กดํ•œ๋‹ค. mem= ๊ฐ™์€ ์ œํ•œ์œผ๋กœ ์ปค๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ค„์–ด๋„, ํŽŒ์›จ์–ด๊ฐ€ ๋ณด๊ณ ํ•œ ์‹ค์ œ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๊ด€์ฐฐ์ ์€ physmem ์ชฝ์— ๋‚จ์„ ์ˆ˜ ์žˆ๋‹ค.

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

1. memblock_add_range() โ€” ์˜์—ญ ์ถ”๊ฐ€์˜ ํ•ต์‹ฌ

// mm/memblock.c:609-713
static int __init_memblock memblock_add_range(struct memblock_type *type,
phys_addr_t base, phys_addr_t size,
int nid, enum memblock_flags flags)

์—ญํ• : ์ƒˆ๋กœ์šด ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ memblock ํƒ€์ž…์— ์ถ”๊ฐ€ํ•œ๋‹ค. ๊ธฐ์กด ์˜์—ญ๊ณผ ์ค‘๋ณต๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ค‘๋ณต ์‹œ ๊ฒน์น˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„๋งŒ ์‚ฝ์ž…ํ•œ๋‹ค. ์ถ”๊ฐ€ ํ›„ ์ธ์ ‘ ํ˜ธํ™˜ ์˜์—ญ์„ ์ž๋™ ๋ณ‘ํ•ฉํ•œ๋‹ค.

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

  • ๋ฐฐ์—ด์ด ๋น„์–ด ์žˆ์œผ๋ฉด ์ฒซ ๋ฒˆ์งธ ์˜์—ญ์œผ๋กœ ๋ฐ”๋กœ ์„ค์ •
  • cnt * 2 + 1 <= max์ด๋ฉด ๋ฐ”๋กœ ์‚ฝ์ž… ๊ฐ€๋Šฅํ•˜๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํฌ๊ธฐ ํ™•์žฅ ํ›„ ๋ฐ˜๋ณต
  • ๊ธฐ์กด ์˜์—ญ๊ณผ ๊ฒน์น˜๋Š” ๋ถ€๋ถ„์€ ์ž˜๋ผ๋‚ด๊ณ  ๋‚˜๋จธ์ง€ ์‚ฝ์ž…
  • memblock_double_array()๋กœ ๋ฐฐ์—ด ํฌ๊ธฐ 2๋ฐฐ ํ™•์žฅ ๊ฐ€๋Šฅ
  • if (!size)
    return 0;
    
    /* special case for empty array */
    if (type->regions[0].size == 0) {
    WARN_ON(type->cnt != 0 || type->total_size);
    type->regions[0].base = base;
    type->regions[0].size = size;
    type->regions[0].flags = flags;
    memblock_set_region_node(&type->regions[0], nid);
    type->total_size = size;
    type->cnt = 1;
    return 0;
    }
    
    /*
    * The worst case is when new range overlaps all existing regions,
    * then we'll need type->cnt + 1 empty regions in @type. So if
    * type->cnt * 2 + 1 is less than or equal to type->max, we know
    * that there is enough empty regions in @type, and we can insert
    * regions directly.
    */
    if (type->cnt * 2 + 1 <= type->max)
    insert = true;

    ์œ„์น˜: mm/memblock.c:619-642. ์ฒซ region์„ ๋„ฃ๋Š” ๊ฒฝ์šฐ์™€ ๋ฐฐ์—ด ์—ฌ์œ ๊ฐ€ ์ถฉ๋ถ„ํ•œ ๊ฒฝ์šฐ๋ฅผ ๋จผ์ € ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•œ๋‹ค.

    /* insert the remaining portion */
    if (base < end) {
    nr_new++;
    if (insert) {
    if (start_rgn == -1)
    start_rgn = idx;
    end_rgn = idx + 1;
    memblock_insert_region(type, idx, base, end - base,
    nid, flags);
    }
    }
    
    if (!nr_new)
    return 0;
    
    /*
    * If this was the first round, resize array and repeat for actual
    * insertions; otherwise, merge and return.
    */
    if (!insert) {
    while (type->cnt + nr_new > type->max)
    if (memblock_double_array(type, obase, size) < 0)
    return -ENOMEM;
    insert = true;
    goto repeat;
    } else {
    memblock_merge_regions(type, start_rgn, end_rgn);
    return 0;
    }

    ์œ„์น˜: mm/memblock.c:684-712. ์ฒซ pass๋Š” ํ•„์š”ํ•œ region ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ , ๋‘ ๋ฒˆ์งธ pass๋Š” ์‚ฝ์ž… ํ›„ ์ธ์ ‘ํ•œ ๊ฐ™์€ ์†์„ฑ์˜ region์„ ๋ณ‘ํ•ฉํ•œ๋‹ค.

    2. memblock_find_in_range_node() โ€” ์˜์—ญ ๊ฒ€์ƒ‰

    // mm/memblock.c:308-328
    static phys_addr_t __init_memblock memblock_find_in_range_node(
    phys_addr_t size, phys_addr_t align,
    phys_addr_t start, phys_addr_t end, int nid,
    enum memblock_flags flags)

    ์—ญํ• : ์ง€์ •๋œ ๋ฒ”์œ„์™€ NUMA ๋…ธ๋“œ์—์„œ ์š”์ฒญ ํฌ๊ธฐ์˜ ๋นˆ ์˜์—ญ์„ ์ฐพ๋Š”๋‹ค.

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

  • end == MEMBLOCK_ALLOC_ACCESSIBLE โ†’ memblock.current_limit๋กœ ๋Œ€์ฒด
  • start๋Š” ์ตœ์†Œ PAGE_SIZE (์ฒซ ํŽ˜์ด์ง€ ํ• ๋‹น ํšŒํ”ผ)
  • memblock_bottom_up() โ†’ bottom-up / top-down ๋ถ„๊ธฐ
  • static phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size,
    phys_addr_t align, phys_addr_t start,
    phys_addr_t end, int nid,
    enum memblock_flags flags)
    {
    /* pump up @end */
    if (end == MEMBLOCK_ALLOC_ACCESSIBLE ||
    end == MEMBLOCK_ALLOC_NOLEAKTRACE)
    end = memblock.current_limit;
    
    /* avoid allocating the first page */
    start = max_t(phys_addr_t, start, PAGE_SIZE);
    end = max(start, end);
    
    if (memblock_bottom_up())
    return __memblock_find_range_bottom_up(start, end, size, align,
    nid, flags);
    else
    return __memblock_find_range_top_down(start, end, size, align,
    nid, flags);
    }

    ์œ„์น˜: mm/memblock.c:308-328. MEMBLOCK_ALLOC_NOLEAKTRACE๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅ ์ƒํ•œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ current_limit์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ๋‚˜์ค‘์— kmemleak ๋“ฑ๋ก์„ ๊ฑด๋„ˆ๋›ฐ๋Š” ์˜๋ฏธ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.

    3. memblock_alloc_range_nid() โ€” ๋ถ€ํŒ… ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น

    // mm/memblock.c:1474-1546
    phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
    phys_addr_t align, phys_addr_t start,
    phys_addr_t end, int nid, bool exact_nid)

    ์—ญํ• : ๋ถ€ํŒ… ์ค‘ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ  ๋ฌผ๋ฆฌ ์ฃผ์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

  • slab_is_available() โ†’ slab ํ• ๋‹น์ž๋กœ fallback
  • ์ง€์ • ๋…ธ๋“œ์—์„œ ํ• ๋‹น ์‹คํŒจ ์‹œ exact_nid == false โ†’ ๋ชจ๋“  ๋…ธ๋“œ๋กœ ํ™•์žฅ
  • ๋ฏธ๋Ÿฌ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ์‹คํŒจ โ†’ ๋ฏธ๋Ÿฌ ํ”Œ๋ž˜๊ทธ ์ œ๊ฑฐ ํ›„ ์žฌ์‹œ๋„
  • ํ• ๋‹น ์„ฑ๊ณต ์‹œ kmemleak_alloc_phys()๋กœ ๋ˆ„์ˆ˜ ์ถ”์  ์ œ์™ธ
  • if (WARN_ON_ONCE(slab_is_available())) {
    void *vaddr = kzalloc_node(size, GFP_NOWAIT, nid);
    
    return vaddr ? virt_to_phys(vaddr) : 0;
    }
    
    if (!align) {
    /* powerpc์—์„œ ๋ถ€ํŒ… ์ดˆ๊ธฐ์—๋Š” WARN์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ */
    dump_stack();
    align = SMP_CACHE_BYTES;
    }
    
    again:
    found = memblock_find_in_range_node(size, align, start, end, nid,
    flags);
    if (found && !__memblock_reserve(found, size, nid, MEMBLOCK_RSRV_KERN))
    goto done;
    
    if (numa_valid_node(nid) && !exact_nid) {
    found = memblock_find_in_range_node(size, align, start,
    end, NUMA_NO_NODE,
    flags);
    if (found && !memblock_reserve_kern(found, size))
    goto done;
    }
    
    if (flags & MEMBLOCK_MIRROR) {
    flags &= ~MEMBLOCK_MIRROR;
    pr_warn_ratelimited("Could not allocate %pap bytes of mirrored memory\n",
    &size);
    goto again;
    }

    ์œ„์น˜: mm/memblock.c:1487-1518. slab ์ค€๋น„ ์ดํ›„์˜ ์šฐ๋ฐœ์  ํ˜ธ์ถœ์€ kzalloc_node()๋กœ ์šฐํšŒํ•˜๊ณ , NUMA fallback๊ณผ mirror fallback์€ ๊ฐ™์€ ๊ฒ€์ƒ‰ ํ•จ์ˆ˜๋ฅผ ๋‹ค๋ฅธ ์กฐ๊ฑด์œผ๋กœ ๋‹ค์‹œ ํ˜ธ์ถœํ•œ๋‹ค.

    done:
    /*
    * Skip kmemleak for those places like kasan_init() and
    * early_pgtable_alloc() due to high volume.
    */
    if (end != MEMBLOCK_ALLOC_NOLEAKTRACE)
    /*
    * Memblock allocated blocks are never reported as
    * leaks. This is because many of these blocks are
    * only referred via the physical address which is
    * not looked up by kmemleak.
    */
    kmemleak_alloc_phys(found, size, 0);
    
    /*
    * Some Virtual Machine platforms, such as Intel TDX or AMD SEV-SNP,
    * require memory to be accepted before it can be used by the
    * guest.
    *
    * Accept the memory of the allocated buffer.
    */
    accept_memory(found, size);
    
    return found;

    ์œ„์น˜: mm/memblock.c:1522-1545. ๋ฌผ๋ฆฌ ์ฃผ์†Œ๋งŒ์œผ๋กœ ์ฐธ์กฐ๋˜๋Š” ์ดˆ๊ธฐ ํ• ๋‹น์€ kmemleak ์˜คํƒ์„ ํ”ผํ•˜๊ณ , TDX/SEV-SNP ๊ฐ™์€ ๊ฒŒ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฐ˜ํ™˜ ์ „์— ๋ฉ”๋ชจ๋ฆฌ accept๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

    4. memblock_alloc_try_nid() โ€” ๊ฐ€์ƒ ์ฃผ์†Œ ๋ฐ˜ํ™˜ ํ• ๋‹น

    // mm/memblock.c:1716-1732
    void * __init memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align,
    phys_addr_t min_addr, phys_addr_t max_addr, int nid)

    ์—ญํ• : memblock_alloc_range_nid()์˜ ๊ฒฐ๊ณผ๋ฅผ phys_to_virt()๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๊ฐ€์ƒ ์ฃผ์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , memset(ptr, 0, size)๋กœ ์ œ๋กœ์ž‰ํ•œ๋‹ค.

    void * __init memblock_alloc_try_nid(
    phys_addr_t size, phys_addr_t align,
    phys_addr_t min_addr, phys_addr_t max_addr,
    int nid)
    {
    void *ptr;
    
    memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=%pa max_addr=%pa %pS\n",
    __func__, (u64)size, (u64)align, nid, &min_addr,
    &max_addr, (void *)_RET_IP_);
    ptr = memblock_alloc_internal(size, align,
    min_addr, max_addr, nid, false);
    if (ptr)
    memset(ptr, 0, size);
    
    return ptr;
    }

    ์œ„์น˜: mm/memblock.c:1716-1732. memblock_alloc_try_nid_raw()์™€ ๋‹ฌ๋ฆฌ ๋ฐ˜ํ™˜ ์ง์ „ ๋ฒ„ํผ๋ฅผ 0์œผ๋กœ ์ฑ„์šด๋‹ค.

    5. memblock_free_all() โ€” Buddy Allocator์— ๋ฐ˜ํ™˜

    void __init memblock_free_all(void)
    {
    unsigned long pages;
    
    free_unused_memmap();
    reset_all_zones_managed_pages();
    
    memblock_clear_kho_scratch_only();
    pages = free_low_memory_core_early();
    totalram_pages_add(pages);
    }

    ์—ญํ• : ๋ถ€ํŒ…์ด ์™„๋ฃŒ๋˜๋ฉด ๋‚จ์€ ๋ชจ๋“  free ๋ฉ”๋ชจ๋ฆฌ๋ฅผ Buddy Allocator์— ๋ฐ˜ํ™˜ํ•œ๋‹ค. free_low_memory_core_early()๊ฐ€ for_each_free_mem_range()๋กœ ์ˆœํšŒํ•˜๋ฉฐ __free_pages_memory()๋กœ ๊ฐ ์˜์—ญ์„ ํ•ด์ œํ•œ๋‹ค.

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

    ํŽŒ์›จ์–ด ๋ฉ”๋ชจ๋ฆฌ๋งต (E820/UEFI/DT)
    โ”‚
    โ–ผ
    arch_mem_init() / setup_arch()
    โ”‚
    โ”œโ”€โ”€ memblock_add(base, size)          โ† ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๋“ฑ๋ก
    โ”‚       โ””โ”€โ”€ memblock_add_range()
    โ”‚               โ”œโ”€โ”€ memblock_insert_region()
    โ”‚               โ”œโ”€โ”€ memblock_double_array()   โ† ๋ฐฐ์—ด ํ™•์žฅ
    โ”‚               โ””โ”€โ”€ memblock_merge_regions()  โ† ์ธ์ ‘ ์˜์—ญ ๋ณ‘ํ•ฉ
    โ”‚
    โ”œโ”€โ”€ memblock_reserve(base, size)      โ† ์˜ˆ์•ฝ (์ปค๋„ ์ด๋ฏธ์ง€, initrd ๋“ฑ)
    โ”‚       โ””โ”€โ”€ __memblock_reserve()
    โ”‚               โ””โ”€โ”€ memblock_add_range(&memblock.reserved, ...)
    โ”‚
    โ”œโ”€โ”€ memblock_alloc(size, align)       โ† ๋ถ€ํŒ… ์ค‘ ํ• ๋‹น
    โ”‚       โ””โ”€โ”€ memblock_alloc_try_nid()
    โ”‚               โ””โ”€โ”€ memblock_alloc_internal()
    โ”‚                       โ””โ”€โ”€ memblock_alloc_range_nid()
    โ”‚                               โ”œโ”€โ”€ memblock_find_in_range_node()
    โ”‚                               โ”‚       โ”œโ”€โ”€ __memblock_find_range_top_down()
    โ”‚                               โ”‚       โ””โ”€โ”€ __memblock_find_range_bottom_up()
    โ”‚                               โ””โ”€โ”€ __memblock_reserve()
    โ”‚
    โ””โ”€โ”€ memblock_free_all()               โ† ๋ถ€ํŒ… ์™„๋ฃŒ ์‹œ Buddy์— ๋ฐ˜ํ™˜
    โ”œโ”€โ”€ free_unused_memmap()
    โ”œโ”€โ”€ reset_all_zones_managed_pages()
    โ””โ”€โ”€ free_low_memory_core_early()
    โ””โ”€โ”€ __free_pages_memory()

    ํŽŒ์›จ์–ด ์ž…๋ ฅ๊ณผ ์˜ˆ์•ฝ ์˜์—ญ

    memblock_add()์˜ ์›์ฒœ์€ ์•„ํ‚คํ…์ฒ˜๋ณ„ ํŽŒ์›จ์–ด ๋ฉ”๋ชจ๋ฆฌ๋งต์ด๋‹ค. x86์€ BIOS E820 ๋˜๋Š” UEFI Memory Map์„, ARM64/์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ์€ Device Tree์˜ /memory์™€ /reserved-memory๋ฅผ, NUMA ์„œ๋ฒ„๋Š” ACPI SRAT/HMAT ๊ฐ™์€ ๋…ธ๋“œ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค. ์ด ๋‹จ๊ณ„์—์„œ memory์— ๋“ค์–ด๊ฐ€๋Š” ๊ฒƒ์€ ์ปค๋„์ด ์ผ๋ฐ˜ RAM์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ”์œ„์ด๊ณ , ์žฅ์น˜ MMIO, ํŽŒ์›จ์–ด ๋Ÿฐํƒ€์ž„ ์„œ๋น„์Šค, ACPI ํ…Œ์ด๋ธ”, initrd, crashkernel, CMA ์˜ˆ์•ฝ ์˜์—ญ์€ ์ผ๋ฐ˜ ํ• ๋‹น ๋Œ€์ƒ์œผ๋กœ ๋‚จ๊ฒจ ๋‘๋ฉด ์•ˆ ๋œ๋‹ค.

    reserved๋Š” ๋‹จ์ˆœํžˆ "์‚ฌ์šฉ ๋ถˆ๊ฐ€" ๋ชฉ๋ก์ด ์•„๋‹ˆ๋ผ ์ดˆ๊ธฐ ๋ถ€ํŒ… ์ค‘ ์ด๋ฏธ ๋ชฉ์ ์ด ์ •ํ•ด์ง„ ๋ฌผ๋ฆฌ ์ฃผ์†Œ ๋ชฉ๋ก์ด๋‹ค. ์ปค๋„ ์ด๋ฏธ์ง€์™€ ์ดˆ๊ธฐ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์€ ๋ถ€ํŒ… ์ž์ฒด์— ํ•„์š”ํ•˜๊ณ , initrd๋Š” ๋ฃจํŠธ ํŒŒ์ผ์‹œ์Šคํ…œ ์ „๊ฐœ ์ „๊นŒ์ง€ ๋ณด์กด๋˜์–ด์•ผ ํ•˜๋ฉฐ, crashkernel์€ ํŒจ๋‹‰ ์ดํ›„ ๋‘ ๋ฒˆ์งธ ์ปค๋„์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. Device Tree์˜ /reserved-memory๋Š” ํŽŒ์›จ์–ด, ๋ณด์•ˆ ์˜์—ญ, ๋””์Šคํ”Œ๋ ˆ์ด ๋ฒ„ํผ, ์›๊ฒฉ ํ”„๋กœ์„ธ์„œ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ, CMA์ฒ˜๋Ÿผ ์šด์˜ ์ค‘์—๋„ ์ผ๋ฐ˜ Buddy ํ• ๋‹น๊ณผ ์„ž์ด๋ฉด ์•ˆ ๋˜๋Š” ์˜์—ญ์„ ํ‘œํ˜„ํ•œ๋‹ค.

    /proc/iomem์€ ๋ถ€ํŒ… ์ดํ›„ ๋ฌผ๋ฆฌ ์ฃผ์†Œ ๊ณต๊ฐ„์„ ๋ณด๋Š” ๊ฐ€์žฅ ์ง์ ‘์ ์ธ ๊ด€์ฐฐ์ ์ด๋‹ค. System RAM์œผ๋กœ ํ‘œ์‹œ๋œ ๋ฒ”์œ„๊ฐ€ ๋Œ€์ฒด๋กœ memblock memory์˜ ์ถœ๋ฐœ์ ์ด๊ณ , ๊ทธ ํ•˜์œ„์˜ Kernel code, Kernel data, reserved, Crash kernel ๊ฐ™์€ ํ•ญ๋ชฉ์€ memblock reserved ๋˜๋Š” ์ดํ›„ resource tree์—์„œ ์˜ˆ์•ฝ๋œ ์˜์—ญ๊ณผ ์—ฐ๊ฒฐ๋œ๋‹ค. ์ปค๋„ ๊ฐ€์ƒ ์ฃผ์†Œ ๋ฐฐ์น˜๊ฐ€ ๊ถ๊ธˆํ•  ๋•Œ๋Š” /proc/meminfo์˜ DirectMap, Vmalloc, PageTables์™€ kernel_page_tables debugfs๋ฅผ ํ•จ๊ป˜ ๋ด์•ผ ํ•œ๋‹ค.

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

    ์กฐ๊ฑดํ• ๋‹น ๋ฐฉํ–ฅ๋ฉ”๋ชจ๋ฆฌ ํƒ€์ž…์‚ฌ์šฉ API๋น„๊ณ 
    UMA ์‹œ์Šคํ…œtop-down (๊ธฐ๋ณธ)memory + reserved`memblock_add()` + `memblock_reserve()`NUMA ๋…ธ๋“œ ๋ฏธ์‚ฌ์šฉ
    NUMA ์‹œ์Šคํ…œtop-down (๊ธฐ๋ณธ)memory + reserved`memblock_add_node()` + `memblock_set_node()`๋…ธ๋“œ๋ณ„ ์˜์—ญ ๊ด€๋ฆฌ
    bottom-up ๋ชจ๋“œbottom-upmemory + reserved`memblock_set_bottom_up(true)` ์ดํ›„ ํ• ๋‹นํŠน์ • ์ดˆ๊ธฐํ™” ์‹œ ์‚ฌ์šฉ
    ๋ฏธ๋Ÿฌ ๋ฉ”๋ชจ๋ฆฌtop-downmemory (MIRROR ํ”Œ๋ž˜๊ทธ)`memblock_mark_mirror()` + ์ผ๋ฐ˜ ํ• ๋‹น๋ฏธ๋Ÿฌ ํ• ๋‹น ์‹คํŒจ ์‹œ ์ผ๋ฐ˜ ์˜์—ญ์œผ๋กœ fallback
    KHO scratchbottom-upmemory (KHO_SCRATCH ํ”Œ๋ž˜๊ทธ)`memblock_set_kho_scratch_only()`kexec handover ์‹œ ์ž„์‹œ ๋ฉ”๋ชจ๋ฆฌ
    nomap ์˜์—ญtop-downmemory (NOMAP ํ”Œ๋ž˜๊ทธ)`memblock_mark_nomap()`์ง์ ‘ ๋งคํ•‘์—์„œ ์ œ์™ธ, struct page๋Š” PageReserved()
    memblock=debug---๋ถ€ํŒ… ์‹œ ์ƒ์„ธ ๋กœ๊ทธ ์ถœ๋ ฅ
    slab ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์‹œ--`kzalloc_node()` fallbackmemblock ์ดˆ๊ธฐํ™” ํ›„ slab์ด ์ค€๋น„๋˜๋ฉด ์ž๋™ ์ „ํ™˜

    ๋ฉ”๋ชจ๋ฆฌ๋งต ์ž…๋ ฅ๋ณ„ ์ฒ˜๋ฆฌ

    ์ž…๋ ฅmemblock ์ฒ˜๋ฆฌ์ฃผ์˜ํ•  ์ ํ™•์ธ ๋ฐฉ๋ฒ•
    BIOS E820RAM ๋ฒ”์œ„๋Š” `memblock_add()`, reserved/ACPI/NVS/MMIO๋Š” ์˜ˆ์•ฝ ๋˜๋Š” ์ œ์™ธE820์˜ ์ „์ฒด ๋ฌผ๋ฆฌ ์ฃผ์†Œ ๊ณต๊ฐ„๊ณผ ์ปค๋„ ์ง์ ‘ ๋งคํ•‘ ๋ฒ”์œ„๋Š” ๊ฐ™์€ ํ‘œ๊ฐ€ ์•„๋‹˜`dmesg \grep BIOS-e820`, `cat /proc/iomem`
    UEFI Memory MapConventional Memory๋Š” ์‚ฌ์šฉ ํ›„๋ณด, Runtime/ACPI/Reserved ํƒ€์ž…์€ ๋ณด์กดEFI runtime ์„œ๋น„์Šค ์˜์—ญ์€ ๋‚˜์ค‘์—๋„ ์ ‘๊ทผ ๊ฒฝ๋กœ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Œ`dmesg \grep 'efi: mem'`
    Device Tree `/memory`RAM bank๋ฅผ `memory` region์œผ๋กœ ๋“ฑ๋กbank ์‚ฌ์ด hole๊ณผ SoC MMIO๋ฅผ RAM์œผ๋กœ ์ทจ๊ธ‰ํ•˜๋ฉด ์•ˆ ๋จ`dmesg \grep -Ei 'OF: fdt\Memory:'`
    Device Tree `/reserved-memory`CMA, framebuffer, secure memory ๋“ฑ์„ `reserved` ๋˜๋Š” NOMAP์œผ๋กœ ๋ถ„๋ฆฌ๋“œ๋ผ์ด๋ฒ„ ์ „์šฉ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ๋Š” Buddy์— ์„ž์ด๋ฉด ๋ฐ์ดํ„ฐ ์†์ƒ ๊ฐ€๋Šฅ`dmesg \grep -Ei 'reserved-memory\cma'`
    ACPI SRAT/HMAT`memblock_add_node()` ๋˜๋Š” `memblock_set_node()`๋กœ NUMA ๋…ธ๋“œ ์—ฐ๊ฒฐ์ฃผ์†Œ๊ฐ€ ์—ฐ์†์ด์–ด๋„ latency/locality๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ`numactl -H`, `/sys/devices/system/node/`
    `mem=`, `crashkernel=`, `movable_node`์‚ฌ์šฉ ๊ฐ€๋Šฅ ์ƒํ•œ, crash kernel ์˜ˆ์•ฝ, hotplug ์„ ํ˜ธ ํ”Œ๋ž˜๊ทธ์— ์˜ํ–ฅ`physmem`๊ณผ `memory`๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ์˜๋ฏธ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ`cat /proc/cmdline`, `cat /proc/iomem`

    ์ดˆ๊ธฐ ํ• ๋‹น์ž ๋น„๊ต

    ๊ตฌ๋ถ„memblockBuddy AllocatorSLUB
    ์‚ฌ์šฉ ์‹œ์ ๋ถ€ํŒ… ์ดˆ๊ธฐ, ์ผ๋ฐ˜ ํ• ๋‹น์ž ์ค€๋น„ ์ „Zone๊ณผ `struct page` ์ดˆ๊ธฐํ™” ์ดํ›„Buddy ์œ„์—์„œ ์ปค๋„ ๊ฐ์ฒด ํ• ๋‹น ์‹œ
    ๊ด€๋ฆฌ ๋‹จ์œ„๋ฌผ๋ฆฌ ์ฃผ์†Œ ๊ตฌ๊ฐ„ `[base, size)``struct page`์™€ order๋ณ„ free list์บ์‹œ๋ณ„ object/slab
    ๋Œ€ํ‘œ API`memblock_add()`, `memblock_reserve()`, `memblock_alloc()``alloc_pages()`, `__free_pages()``kmalloc()`, `kmem_cache_alloc()`
    ๊ฐ•์ ํŽŒ์›จ์–ด ๋ฉ”๋ชจ๋ฆฌ๋งต๊ณผ ์˜ˆ์•ฝ ์˜์—ญ์„ ๋‹จ์ˆœํ•œ ๊ตฌ๊ฐ„ ๋ฐฐ์—ด๋กœ ์ •๋ฆฌ๋Ÿฐํƒ€์ž„ ํŽ˜์ด์ง€ ํ• ๋‹น/ํ•ด์ œ์™€ ๋ณ‘ํ•ฉ ์ฒ˜๋ฆฌ์ž‘์€ ๊ฐ์ฒด ๋ฐ˜๋ณต ํ• ๋‹น ์ตœ์ ํ™”
    ์ „ํ™˜์ `memblock_free_all()`์—์„œ ๋‚จ์€ free range ๋ฐ˜ํ™˜์ดํ›„ ์ผ๋ฐ˜ ํŽ˜์ด์ง€ ํ• ๋‹น์„ ๋‹ด๋‹นslab ์ค€๋น„ ํ›„ memblock ์šฐ๋ฐœ ํ˜ธ์ถœ fallback ๋Œ€์ƒ

    ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น API ๊ณ„์ธต

    ํ•จ์ˆ˜๋ฐ˜ํ™˜ ํƒ€์ž…ํŠน์ง•
    `memblock_phys_alloc()``phys_addr_t`๋ฌผ๋ฆฌ ์ฃผ์†Œ ๋ฐ˜ํ™˜, ์ œ๋กœ์ž‰ ์—†์Œ
    `memblock_alloc()``void *`๊ฐ€์ƒ ์ฃผ์†Œ ๋ฐ˜ํ™˜, ์ œ๋กœ์ž‰ ํฌํ•จ
    `memblock_alloc_raw()``void *`๊ฐ€์ƒ ์ฃผ์†Œ ๋ฐ˜ํ™˜, ์ œ๋กœ์ž‰ ์—†์Œ
    `memblock_alloc_low()``void *`๋‚ฎ์€ ์ฃผ์†Œ ์˜์—ญ์—์„œ ํ• ๋‹น
    `memblock_alloc_node()``void *`ํŠน์ • NUMA ๋…ธ๋“œ์—์„œ ํ• ๋‹น
    `memblock_alloc_or_panic()``void *`ํ• ๋‹น ์‹คํŒจ ์‹œ panic ๋ฐœ์ƒ

    memblock โ†’ Buddy ์ „ํ™˜

    ๋ถ€ํŒ…์ด ์™„๋ฃŒ๋˜๋ฉด memblock_free_all()์ด ํ˜ธ์ถœ๋˜์–ด ๋ชจ๋“  ๋‚จ์€ ํŽ˜์ด์ง€๋ฅผ Buddy Allocator๋กœ ๋„˜๊ธด๋‹ค. ์ด ๊ณผ์ •์—์„œ:

    1. free_unused_memmap() โ€” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” struct page ๋ฐฐ์—ด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œ

    2. reset_all_zones_managed_pages() โ€” Zone์˜ managed_pages ์นด์šดํ„ฐ ๋ฆฌ์…‹

    3. free_low_memory_core_early() โ€” for_each_free_mem_range()๋กœ ์ˆœํšŒํ•˜๋ฉฐ __free_pages_memory()๋กœ ๊ฐ ํŽ˜์ด์ง€๋ฅผ Buddy์— ๋ฐ˜ํ™˜

    4. totalram_pages_add() โ€” ์ „์ฒด RAM ํŽ˜์ด์ง€ ์ˆ˜ ์—…๋ฐ์ดํŠธ

    ์ดํ›„ CONFIG_ARCH_KEEP_MEMBLOCK์ด ์—†์œผ๋ฉด memblock_discard()๊ฐ€ ํ˜ธ์ถœ๋˜์–ด memblock ๋‚ด๋ถ€ ๋ฐฐ์—ด์„ ํ•ด์ œํ•˜๊ณ , memblock ํฌ์ธํ„ฐ๋Š” NULL๋กœ ์„ค์ •๋œ๋‹ค.

    ๊ด€๋ จ ๋ฌธ์„œ

  • 00-overview.html โ€” ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š”
  • 01-page_alloc.html โ€” Buddy Allocator (memblock ์ดํ›„ ๋‹จ๊ณ„)
  • 03-vma_mmap.html โ€” VMA / mmap (๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ)
  • 13-numa.html โ€” NUMA (memblock์˜ NUMA ๋…ธ๋“œ ํ• ๋‹น)
  • 22-memory_hotplug.html โ€” Hotplug (MEMBLOCK_HOTPLUG ํ”Œ๋ž˜๊ทธ)
  • SVG ๋‹ค์ด์–ด๊ทธ๋žจ

    Memblock ํ• ๋‹น์ž ๊ตฌ์กฐ
    Memblock ํ˜ธ์ถœ ํ๋ฆ„