[TOC]
mm/memblock.c: Linux内核的“拓荒时代”内存管理器 mm/memblock.c
实现了一种极其早期 的、简单 的物理内存分配器,它在内核启动的“拓荒时代”——即在页分配器(伙伴系统)初始化之前 ——扮演着至关重要的角色。
可以将其想象成一个在建造正式仓库(伙伴系统)之前,用来管理建筑材料(物理内存)的临时账本和场地规划师 。它的唯一使命是在最原始的环境下,为内核自身的初始化提供最基本的内存分配服务,并在完成使命后,将所有管理权平稳地移交给更高级的内存管理系统。
一、 核心问题:为什么需要 memblock
? 在内核启动的极早期(start_kernel
函数刚开始执行时),真正的内存管理子系统(如伙伴系统、Slab 分配器)还完全不存在。这些高级系统本身就需要分配内存来存放它们复杂的数据结构(如 mem_map
数组、kmem_cache
结构等)。这就产生了一个“先有鸡还是先有蛋”的问题:
为了初始化内存管理器,你需要分配内存。
但为了分配内存,你需要一个已初始化的内存管理器。
memblock
就是为了打破这个循环而存在的。它是一个极其简单的、无须复杂数据结构 的分配器,可以在最简陋的环境下工作。
二、 核心原理与设计 memblock
的设计思想是极简主义 。它不使用链表、树等复杂结构,而是只用了几个静态数组来管理整个系统的物理内存布局。
memblock
将系统的物理内存分为两大类:
内存区域 (Memory Regions) : memblock.memory
这是一个 struct memblock_region
类型的数组,记录了系统中所有可用 的物理内存块。
这些信息通常由 Bootloader(通过设备树、E820 表等)传递给内核。例如,[0x100000 - 0x80000000]
(1MB 到 2GB)。
保留区域 (Reserved Regions) : memblock.reserved
这也是一个 struct memblock_region
类型的数组,记录了那些不可用 的物理内存块。
这些区域包括:内核自身的代码和数据段(.text
, .data
, .bss
)、ACPI 数据、设备树二进制文件等。
struct memblock_region
的定义 :
1 2 3 4 5 struct memblock_region { phys_addr_t base; phys_addr_t size; };
内存分配的工作方式 : 当内核需要调用 memblock_alloc()
来分配一块内存时,memblock
的工作方式就像一个反向的橡皮擦 :
扫描可用内存 : 它会遍历 memblock.memory
数组,寻找一个足够大的、尚未被保留 的可用内存区域。
“保留”新区域 : 一旦找到合适的空间,它不会 从 memblock.memory
中“切”一块下来,而是简单地调用 memblock_reserve()
,将刚刚分配出去的这块内存区域的信息,添加 到 memblock.reserved
数组中。
返回物理地址 : 最后,它返回这块内存的物理基地址。
内存释放 : memblock
也提供了 memblock_free()
,其工作方式与分配相反,即从 memblock.reserved
数组中移除一个区域。
核心优势 :
实现简单 : 只需要几个数组和一些循环遍历逻辑。
无动态分配 : memblock
自身的数据结构(memblock_region
数组)是在编译时静态分配的(或在 .bss
段),它在工作时不需要为自己动态分配任何内存。
功能足够 : 它提供了启动阶段所需的所有基本功能:添加内存区域、保留内存区域、分配内存、查找可用内存等。
三、 在内核启动流程中的角色 memblock
的生命周期非常短暂,但作用贯穿了整个启动过程的前半段。
信息收集阶段 (Arch-specific code) :
在 start_kernel
之前,特定于体系结构的代码(如 arch/arm64/kernel/setup.c
)会解析 Bootloader 传递的内存布局信息。
它会调用 memblock_add(base, size)
将所有发现的可用物理 RAM 段添加到 memblock.memory
中。
早期保留阶段 :
内核会立即调用 memblock_reserve()
来“保护”那些已经被占用的关键区域,例如:
内核镜像本身占用的空间。
传递进来的设备树二进制文件 (initrd/dtb) 占用的空间。
早期分配阶段 (start_kernel
内部) :
在 start_kernel
函数中,许多早期的子系统初始化都需要内存。它们会调用 memblock_alloc()
来获取。
最重要的分配 : 为伙伴系统的 mem_map
数组分配空间是 memblock
最关键的任务之一。mem_map
可能非常巨大(几百MB),只有 memblock
才能在伙伴系统上线前完成这个艰巨的任务。
“交接仪式” (mm_init()
内部) :
当内核执行到 mm_init()
-> mem_init()
时,标志着 memblock
的历史使命即将结束。
mem_init()
函数会遍历 memblock.memory
中记录的所有可用内存区域。
对于每个区域,它会逐页地调用 __free_pages_bootmem()
(或类似函数),将这些物理页**“释放”到刚刚初始化完成的伙伴系统中**。
这个过程就像是临时账本的管理员,将所有账目和剩余物资,都交接给了新上任的正式仓库管理员。
退役 : 交接完成后,memblock
的数据结构本身所占用的内存也会被回收,它从此在内核的运行中销声匿迹。
四、 关键 API
memblock_add(phys_addr_t base, phys_addr_t size)
: 添加一段物理内存到 memblock.memory
。
memblock_reserve(phys_addr_t base, phys_addr_t size)
: 将一段内存标记为已保留,添加到 memblock.reserved
。
memblock_alloc(phys_addr_t size, phys_addr_t align)
: 从可用内存中分配一块指定大小和对齐的内存,并将其标记为保留。
memblock_free(phys_addr_t base, phys_addr_t size)
: 释放一块之前保留的内存。
memblock_find_in_range(phys_addr_t start, phys_addr_t end, ...)
: 在指定范围内查找一块符合条件的空闲内存,常用于为 mem_map
寻找空间。
五、 总结 memblock
是 Linux 内核启动过程的奠基石 。它是一个专门为解决“鸡生蛋,蛋生鸡”问题而设计的引导期物理内存管理器 。
核心特点 :
简单高效 : 基于静态数组,操作逻辑直观。
生命周期短暂 : 仅在伙伴系统初始化之前活跃。
任务关键 : 负责为内核早期初始化(特别是为伙伴系统自身)提供内存。
承上启下 : 它的角色是收集硬件信息,服务早期分配,并最终将整个物理内存的管理权无缝地移交给伙伴系统。
理解 memblock
的工作原理,是理解 Linux 内核如何从最原始的硬件状态,一步步建立起复杂而强大的内存管理大厦的第一步。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
include/linux/memblock.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 struct memblock { bool bottom_up; phys_addr_t current_limit; struct memblock_type memory ; struct memblock_type reserved ; }; #define INIT_MEMBLOCK_REGIONS 128 #define INIT_PHYSMEM_REGIONS 4 #ifndef INIT_MEMBLOCK_RESERVED_REGIONS # define INIT_MEMBLOCK_RESERVED_REGIONS INIT_MEMBLOCK_REGIONS #endif #ifndef INIT_MEMBLOCK_MEMORY_REGIONS #define INIT_MEMBLOCK_MEMORY_REGIONS INIT_MEMBLOCK_REGIONS #endif 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
memblock_alloc_from: 需要写入可以从最小的地址开始的内存块.如果没有找到,则从0开始分配
1 2 3 static inline void *memblock_alloc_from (phys_addr_t size, phys_addr_t align, phys_addr_t min_addr)
memblock_reserve 预留内存块 1 2 3 4 5 6 7 8 int __init_memblock memblock_reserve (phys_addr_t base, phys_addr_t size) { phys_addr_t end = base + size - 1 ; memblock_dbg("%s: [%pa-%pa] %pS\n" , __func__, &base, &end, (void *)_RET_IP_); return memblock_add_range(&memblock.reserved, base, size, MAX_NUMNODES, 0 ); }
for_each_memblock_type 遍历 memblock 区域 1 2 3 4 #define for_each_memblock_type(i, memblock_type, rgn) \ for (i = 0, rgn = &memblock_type->regions[0]; \ i < memblock_type-> cnt; \ i++, rgn = &memblock_type->regions[i])
memblock_insert_region 插入新的 memblock 区域 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 static void __init_memblock memblock_insert_region (struct memblock_type *type, int idx, phys_addr_t base, phys_addr_t size, int nid, enum memblock_flags flags) { struct memblock_region *rgn = &type->regions[idx]; BUG_ON(type->cnt >= type->max); memmove(rgn + 1 , rgn, (type->cnt - idx) * sizeof (*rgn)); rgn->base = base; rgn->size = size; rgn->flags = flags; memblock_set_region_node(rgn, nid); type->cnt++; type->total_size += size; }
memblock_add_range 添加新的 memblock 区域
没有添加过区域,直接添加
添加过区域,需要判断是否需要扩展区域数组
需要扩展区域数组,需要判断是否有足够的空间
如果没有足够的空间,扩展区域数组
如果有足够的空间,直接添加
添加区域后,合并区域
如果没有添加区域,直接返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 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) { bool insert = false ; phys_addr_t obase = base; phys_addr_t end = base + memblock_cap_size(base, &size); int idx, nr_new, start_rgn = -1 , end_rgn; struct memblock_region *rgn ; if (!size) return 0 ; 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 ; } if (type->cnt * 2 + 1 <= type->max) insert = true ; repeat: base = obase; nr_new = 0 ; for_each_memblock_type(idx, type, rgn) { phys_addr_t rbase = rgn->base; phys_addr_t rend = rbase + rgn->size; if (rbase >= end) break ; if (rend <= base) continue ; if (rbase > base) { #ifdef CONFIG_NUMA WARN_ON(nid != memblock_get_region_node(rgn)); #endif WARN_ON(flags != rgn->flags); nr_new++; if (insert) { if (start_rgn == -1 ) start_rgn = idx; end_rgn = idx + 1 ; memblock_insert_region(type, idx++, base, rbase - base, nid, flags); } } base = min(rend, end); } 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 (!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 ; } }
memblock_is_region_memory 判断区域是否是内存区域 1 2 3 4 5 6 7 8 9 10 11 12 13 bool __init_memblock memblock_is_region_memory (phys_addr_t base, phys_addr_t size) { int idx = memblock_search(&memblock.memory, base); phys_addr_t end = base + memblock_cap_size(base, &size); if (idx == -1 ) return false ; return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size) >= end; }
memblock_is_region_reserved 判断区域是否是保留区域 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 unsigned long __init_memblockmemblock_addrs_overlap (phys_addr_t base1, phys_addr_t size1, phys_addr_t base2, phys_addr_t size2) { return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); } bool __init_memblock memblock_overlaps_region (struct memblock_type *type, phys_addr_t base, phys_addr_t size) { unsigned long i; memblock_cap_size(base, &size); for (i = 0 ; i < type->cnt; i++) if (memblock_addrs_overlap(base, size, type->regions[i].base, type->regions[i].size)) return true ; return false ; } bool __init_memblock memblock_is_region_reserved (phys_addr_t base, phys_addr_t size) { return memblock_overlaps_region(&memblock.reserved, base, size); }
__memblock_find_range_bottom_up __memblock_find_range_top_down 查找空闲区域 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 static phys_addr_t __init_memblock__memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align, int nid, enum memblock_flags flags) { phys_addr_t this_start, this_end, cand; u64 i; for_each_free_mem_range(i, nid, flags, &this_start, &this_end, NULL ) { this_start = clamp(this_start, start, end); this_end = clamp(this_end, start, end); cand = round_up(this_start, align); if (cand < this_end && this_end - cand >= size) return cand; } return 0 ; } static phys_addr_t __init_memblock__memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align, int nid, enum memblock_flags flags) { phys_addr_t this_start, this_end, cand; u64 i; for_each_free_mem_range_reverse(i, nid, flags, &this_start, &this_end, NULL ) { this_start = clamp(this_start, start, end); this_end = clamp(this_end, start, end); if (this_end < size) continue ; cand = round_down(this_end - size, align); if (cand >= this_start) return cand; } return 0 ; }
memblock_alloc_range_nid 分配启动内存块 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 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) { enum memblock_flags flags = choose_memblock_flags(); phys_addr_t found; if (WARN_ON_ONCE(slab_is_available())) { void *vaddr = kzalloc_node(size, GFP_NOWAIT, nid); return vaddr ? virt_to_phys(vaddr) : 0 ; } if (!align) { 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)) 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(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; } return 0 ; done: if (end != MEMBLOCK_ALLOC_NOLEAKTRACE) kmemleak_alloc_phys(found, size, 0 ); accept_memory(found, size); return found; }
memblock_phys_alloc_range 物理地址分配 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 phys_addr_t __init memblock_phys_alloc_range (phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end) { memblock_dbg("%s: %llu bytes align=0x%llx from=%pa max_addr=%pa %pS\n" , __func__, (u64)size, (u64)align, &start, &end, (void *)_RET_IP_); return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE, false ); }
memblock_flags 内存区域属性的定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 enum memblock_flags { MEMBLOCK_NONE = 0x0 , MEMBLOCK_HOTPLUG = 0x1 , MEMBLOCK_MIRROR = 0x2 , MEMBLOCK_NOMAP = 0x4 , MEMBLOCK_DRIVER_MANAGED = 0x8 , MEMBLOCK_RSRV_NOINIT = 0x10 , };
memblock_setclr_flag 设置或清除内存区域的标志 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 static int __init_memblock memblock_setclr_flag (struct memblock_type *type, phys_addr_t base, phys_addr_t size, int set , int flag) { int i, ret, start_rgn, end_rgn; ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn); if (ret) return ret; for (i = start_rgn; i < end_rgn; i++) { struct memblock_region *r = &type->regions[i]; if (set ) r->flags |= flag; else r->flags &= ~flag; } memblock_merge_regions(type, start_rgn, end_rgn); return 0 ; }
memblock_mark_nomap 使用标志 MEMBLOCK_NOMAP 标记内存区域 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int __init_memblock memblock_mark_nomap (phys_addr_t base, phys_addr_t size) { return memblock_setclr_flag(&memblock.memory, base, size, 1 , MEMBLOCK_NOMAP); }
memblock_dump_all 打印所有内存块信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 static int memblock_debug __initdata_memblock = 1 ;static void __init_memblock memblock_dump (struct memblock_type *type) { phys_addr_t base, end, size; enum memblock_flags flags ; int idx; struct memblock_region *rgn ; pr_info(" %s.cnt = 0x%lx\n" , type->name, type->cnt); for_each_memblock_type(idx, type, rgn) { char nid_buf[32 ] = "" ; base = rgn->base; size = rgn->size; end = base + size - 1 ; flags = rgn->flags; #ifdef CONFIG_NUMA if (numa_valid_node(memblock_get_region_node(rgn))) snprintf (nid_buf, sizeof (nid_buf), " on node %d" , memblock_get_region_node(rgn)); #endif pr_info(" %s[%#x]\t[%pa-%pa], %pa bytes%s flags: %#x\n" , type->name, idx, &base, &end, &size, nid_buf, flags); } } static void __init_memblock __memblock_dump_all(void ){ pr_info("MEMBLOCK configuration:\n" ); pr_info(" memory size = %pa reserved size = %pa\n" , &memblock.memory.total_size, &memblock.reserved.total_size); memblock_dump(&memblock.memory); memblock_dump(&memblock.reserved); #ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP memblock_dump(&physmem); #endif } void __init_memblock memblock_dump_all (void ) { if (memblock_debug) __memblock_dump_all(); }
memblock_alloc_try_nid 尝试分配内存块 1 memblock_alloc_try_nid: 4096 bytes align=0x1000 nid=-1 from=0x00000000 max_addr=0x00000000 __memblock_alloc_or_panic+0x15/0x28
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 static void * __init memblock_alloc_internal ( phys_addr_t size, phys_addr_t align, phys_addr_t min_addr, phys_addr_t max_addr, int nid, bool exact_nid) { phys_addr_t alloc; if (max_addr > memblock.current_limit) max_addr = memblock.current_limit; alloc = memblock_alloc_range_nid(size, align, min_addr, max_addr, nid, exact_nid); if (!alloc && min_addr) alloc = memblock_alloc_range_nid(size, align, 0 , max_addr, nid, exact_nid); if (!alloc) return NULL ; return phys_to_virt(alloc); } 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; }
__memblock_alloc_or_panic 分配内存并在失败时出现 panic 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 static __always_inline void *memblock_alloc (phys_addr_t size, phys_addr_t align) { return memblock_alloc_try_nid(size, align, MEMBLOCK_LOW_LIMIT, MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE); } void *__init __memblock_alloc_or_panic(phys_addr_t size, phys_addr_t align, const char *func) { void *addr = memblock_alloc(size, align); if (unlikely(!addr)) panic("%s: Failed to allocate %pap bytes\n" , func, &size); return addr; }
memblock_allow_resize Memblock 允许调整大小 1 2 3 4 5 6 7 8 9 10 11 12 13 static int __init_memblock memblock_double_array (struct memblock_type *type, phys_addr_t new_area_start, phys_addr_t new_area_size) { if (!memblock_can_resize) panic("memblock: cannot resize %s array\n" , type->name); } void __init memblock_allow_resize (void ) { memblock_can_resize = 1 ; }
memblock_insert_region 插入新的内存区域 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 static void __init_memblock memblock_insert_region (struct memblock_type *type, int idx, phys_addr_t base, phys_addr_t size, int nid, enum memblock_flags flags) { struct memblock_region *rgn = &type->regions[idx]; BUG_ON(type->cnt >= type->max); memmove(rgn + 1 , rgn, (type->cnt - idx) * sizeof (*rgn)); rgn->base = base; rgn->size = size; rgn->flags = flags; memblock_set_region_node(rgn, nid); type->cnt++; type->total_size += size; }
memblock_isolate_range 隔离内存区域 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 static int __init_memblock memblock_isolate_range (struct memblock_type *type, phys_addr_t base, phys_addr_t size, int *start_rgn, int *end_rgn) { phys_addr_t end = base + memblock_cap_size(base, &size); int idx; struct memblock_region *rgn ; *start_rgn = *end_rgn = 0 ; if (!size) return 0 ; while (type->cnt + 2 > type->max) if (memblock_double_array(type, base, size) < 0 ) return -ENOMEM; for_each_memblock_type(idx, type, rgn) { phys_addr_t rbase = rgn->base; phys_addr_t rend = rbase + rgn->size; if (rbase >= end) break ; if (rend <= base) continue ; if (rbase < base) { rgn->base = base; rgn->size -= base - rbase; type->total_size -= base - rbase; memblock_insert_region(type, idx, rbase, base - rbase, memblock_get_region_node(rgn), rgn->flags); } else if (rend > end) { rgn->base = end; rgn->size -= end - rbase; type->total_size -= end - rbase; memblock_insert_region(type, idx--, rbase, end - rbase, memblock_get_region_node(rgn), rgn->flags); } else { if (!*end_rgn) *start_rgn = idx; *end_rgn = idx + 1 ; } } return 0 ; }
memblock_remove_region 删除内存区域 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static void __init_memblock memblock_remove_region (struct memblock_type *type, unsigned long r) { type->total_size -= type->regions[r].size; memmove(&type->regions[r], &type->regions[r + 1 ], (type->cnt - (r + 1 )) * sizeof (type->regions[r])); type->cnt--; if (type->cnt == 0 ) { WARN_ON(type->total_size != 0 ); type->regions[0 ].base = 0 ; type->regions[0 ].size = 0 ; type->regions[0 ].flags = 0 ; memblock_set_region_node(&type->regions[0 ], MAX_NUMNODES); } }
memblock_phys_free 释放物理内存块 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 static int __init_memblock memblock_remove_range (struct memblock_type *type, phys_addr_t base, phys_addr_t size) { int start_rgn, end_rgn; int i, ret; ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn); if (ret) return ret; for (i = end_rgn - 1 ; i >= start_rgn; i--) memblock_remove_region(type, i); return 0 ; } int __init_memblock memblock_phys_free (phys_addr_t base, phys_addr_t size) { phys_addr_t end = base + size - 1 ; memblock_dbg("%s: [%pa-%pa] %pS\n" , __func__, &base, &end, (void *)_RET_IP_); kmemleak_free_part_phys(base, size); return memblock_remove_range(&memblock.reserved, base, size); }
free_memmap 释放内存映射 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 static void __init free_memmap (unsigned long start_pfn, unsigned long end_pfn) { struct page *start_pg , *end_pg ; phys_addr_t pg, pgend; start_pg = pfn_to_page(start_pfn - 1 ) + 1 ; end_pg = pfn_to_page(end_pfn - 1 ) + 1 ; pg = PAGE_ALIGN(__pa(start_pg)); pgend = PAGE_ALIGN_DOWN(__pa(end_pg)); if (pg < pgend) memblock_phys_free(pg, pgend - pg); }
free_unused_memmap 释放未使用的内存映射
mem_map 是内核用于管理物理内存页面的核心数据结构,但在某些情况下,部分内存映射可能未被使用。通过释放这些未使用的区域,可以减少内存浪费,提高系统的可用内存量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 static void __init free_unused_memmap (void ) { unsigned long start, end, prev_end = 0 ; int i; if (!IS_ENABLED(CONFIG_HAVE_ARCH_PFN_VALID) || IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP)) return ; for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, NULL ) { start = pageblock_start_pfn(start); if (prev_end && prev_end < start) free_memmap(prev_end, start); prev_end = pageblock_align(end); } }
reset_all_zones_managed_pages 重置所有区域的管理页面 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 static int reset_managed_pages_done __initdata;static void __init reset_node_managed_pages (pg_data_t *pgdat) { struct zone *z ; for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++) atomic_long_set(&z->managed_pages, 0 ); } void __init reset_all_zones_managed_pages (void ) { struct pglist_data *pgdat ; if (reset_managed_pages_done) return ; for_each_online_pgdat(pgdat) reset_node_managed_pages(pgdat); reset_managed_pages_done = 1 ; }
memmap_init_reserved_pages 初始化保留页面
用于初始化内核中标记为“保留”(reserved)的内存区域的相关数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 static void __init memmap_init_reserved_pages (void ) { struct memblock_region *region ; phys_addr_t start, end; int nid; for_each_mem_region(region) { nid = memblock_get_region_node(region); start = region->base; end = start + region->size; if (memblock_is_nomap(region)) reserve_bootmem_region(start, end, nid); memblock_set_node(start, end, &memblock.reserved, nid); } for_each_reserved_mem_region(region) { if (!memblock_is_reserved_noinit(region)) { nid = memblock_get_region_node(region); start = region->base; end = start + region->size; if (!numa_valid_node(nid)) nid = early_pfn_to_nid(PFN_DOWN(start)); reserve_bootmem_region(start, end, nid); } } }
__free_memory_core 释放页面内存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 static void __init __free_pages_memory(unsigned long start, unsigned long end){ int order; while (start < end) { if (start) order = min_t (int , MAX_PAGE_ORDER, __ffs(start)); else order = MAX_PAGE_ORDER; while (start + (1UL << order) > end) order--; memblock_free_pages(pfn_to_page(start), start, order); start += (1UL << order); } } static unsigned long __init __free_memory_core(phys_addr_t start, phys_addr_t end) { unsigned long start_pfn = PFN_UP(start); unsigned long end_pfn = PFN_DOWN(end); if (!IS_ENABLED(CONFIG_HIGHMEM) && end_pfn > max_low_pfn) end_pfn = max_low_pfn; if (start_pfn >= end_pfn) return 0 ; __free_pages_memory(start_pfn, end_pfn); return end_pfn - start_pfn; }
free_low_memory_core_early 释放低内存区域 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 static unsigned long __init free_low_memory_core_early (void ) { unsigned long count = 0 ; phys_addr_t start, end; u64 i; memblock_clear_hotplug(0 , -1 ); memmap_init_reserved_pages(); for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end, NULL ) count += __free_memory_core(start, end); return count; }
memblock_free_all 释放所有内存块 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void __init memblock_free_all (void ) { unsigned long pages; free_unused_memmap(); reset_all_zones_managed_pages(); pages = free_low_memory_core_early(); totalram_pages_add(pages); }
memblock_estimated_nr_free_pages 从 memblock 角度返回估计的免费页面数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 phys_addr_t __init_memblock memblock_phys_mem_size (void ) { return memblock.memory.total_size; } phys_addr_t __init_memblock memblock_reserved_size (void ) { return memblock.reserved.total_size; } #define PHYS_PFN(x) ((unsigned long)((x) >> PAGE_SHIFT)) unsigned long __init memblock_estimated_nr_free_pages (void ) { return PHYS_PFN(memblock_phys_mem_size() - memblock_reserved_size()); }