内存管理之memblock添加

本文介绍了一个内存块管理API,提供了memblock_add_range()等函数来添加新的内存区域,并允许这些区域与现有区域重叠。该API还包含了用于插入新内存区域的memblock_insert_region()函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里主要提供两个函数memblock_add()和memblock_add_node(),如果标记内存则调用memblock_reserve()。
这些函数核心调用memblock_add_range()

/**
 * memblock_add_range - add new memblock region
 * @type: memblock type to add new region into
 * @base: base address of the new region
 * @size: size of the new region
 * @nid: nid of the new region
 * @flags: flags of the new region
 *
 * Add new memblock region [@base,@base+@size) into @type.  The new region
 * is allowed to overlap with existing ones - overlaps don't affect already
 * existing regions.  @type is guaranteed to be minimal (all neighbouring
 * compatible regions are merged) after the addition.
 *
 * RETURNS:
 * 0 on success, -errno on failure.
 */
int __init_memblock memblock_add_range(struct memblock_type *type,
				phys_addr_t base, phys_addr_t size,
				int nid, unsigned long flags)
{
	bool insert = false;
	phys_addr_t obase = base;
	phys_addr_t end = base + memblock_cap_size(base, &size);
	int idx, nr_new;
	struct memblock_region *rgn;


	if (!size)
		return 0;


	/* special case for empty array */
	if (type->regions[0].size == 0) {
		WARN_ON(type->cnt != 1 || 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;
		return 0;
	}
repeat:
	/*
	 * The following is executed twice.  Once with %false @insert and
	 * then with %true.  The first counts the number of regions needed
	 * to accommodate the new area.  The second actually inserts them.
	 */
	base = obase;
	nr_new = 0;


	for_each_memblock_type(type, rgn) {
		phys_addr_t rbase = rgn->base;
		phys_addr_t rend = rbase + rgn->size;


		if (rbase >= end)
			break;
		if (rend <= base)
			continue;
		/*
		 * @rgn overlaps.  If it separates the lower part of new
		 * area, insert that portion.
		 */
		if (rbase > base) {
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
			WARN_ON(nid != memblock_get_region_node(rgn));
#endif
			WARN_ON(flags != rgn->flags);
			nr_new++;
			if (insert)
				memblock_insert_region(type, idx++, base,
						       rbase - base, nid,
						       flags);
		}
		/* area below @rend is dealt with, forget about it */
		base = min(rend, end);
	}


	/* insert the remaining portion */
	if (base < end) {
		nr_new++;
		if (insert)
			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);
		return 0;
	}
}
/**
 * memblock_insert_region - insert new memblock region
 * @type:	memblock type to insert into
 * @idx:	index for the insertion point
 * @base:	base address of the new region
 * @size:	size of the new region
 * @nid:	node id of the new region
 * @flags:	flags of the new region
 *
 * Insert new memblock region [@base,@base+@size) into @type at @idx.
 * @type must already have extra room to accommodate the new region.
 */
static void memblock_insert_region(struct memblock_type *type,
						   int idx, phys_addr_t base,
						   phys_addr_t size,
						   int nid, unsigned long 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;
}


int memblock_add_node(phys_addr_t base, phys_addr_t size,
				       int nid)
{
	return memblock_add_range(&memblock.memory, base, size, nid, 0);
}


int memblock_add(phys_addr_t base, phys_addr_t size)
{
	memblock_dbg("memblock_add: [%#016llx-%#016llx] flags %#02lx %pF\n",
		     (unsigned long long)base,
		     (unsigned long long)base + size - 1,
		     0UL, (void *)_RET_IP_);

	return memblock_add_range(&memblock.memory, base, size, MAX_NUMNODES, 0);
}



                
<think>好的,我现在需要帮助用户理解memblock内存分配机制中memory和reserve内存的关系,特别是它们是否可以包含同一块内存。首先,我应该回顾一下用户提供的引用内容,确保正确理解相关概念。 根据引用[1],memory和reserved都是struct memblock_type类型的数据结构。memory负责管理所有可用内存,而reserved则记录那些被预留或特殊用途的内存。启动早期,所有内存都挂在memory中,但随着系统运行,部分内存会被标记为预留并加入reserved。这些预留的内存同时被memory和reserved管理,所以可能存在重叠的情况。这里提到预留的内存同时被两者管理,暗示同一块内存在两个结构中都有记录。 接下来,引用[2]说明memblock使用首次匹配算法分配内存,内存块逐渐被分割成小块。分配方向可以是高到低或低到高,管理区域从内核代码段结束到低端内存顶端。这说明内存分配是动态的,初始时是一个大块,随着分配被分割。 引用[3]介绍了三个数据结构:memblock全局变量管理所有物理内存,memblock_type表示内存类型,memblock_region描述具体区域。memory和reserved都是memblock_type的实例,每个包含最多128个region。因此,memory中的region代表可用内存,而reserved中的代表已预留的。 现在,用户的问题是memory和reserved是否可以包含同一块内存。根据引用[1],当内存被预留时,这块内存仍然存在于memory中,但也被加入reserved。因此,同一块内存在两个结构中都存在。例如,启动时所有内存在memory里,之后预留的部分加入reserved,但不会从memory移除。这样,memory记录总可用内存,而reserved记录已被使用的部分,两者可能有重叠。 需要进一步确认的是,这种设计是否允许同一物理地址在两个结构中出现。是的,因为memory管理所有内存,而reserved跟踪预留的部分,所以同一区域可能在memory的某个region中被标记为可用,同时在reserved的region中被标记为预留。这种情况下,分配器在查找可用内存时会检查reserved,避免分配已预留的区域。 总结来说,memory和reserved可以包含同一块内存,因为它们分别管理不同的属性:memory记录所有物理内存,而reserved记录预留部分。这样设计允许系统在启动阶段动态管理内存,保留关键区域不被分配。用户可能还想了解这种机制如何避免冲突,或者如何处理重叠区域的分配,这些问题可以作为相关问题提出。</think>### memblock的memory与reserved内存关系解析 在Linux早期启动阶段,memblock内存管理器通过两个核心数据结构`memory`和`reserved`协同管理物理内存。两者的关系如下: 1. **初始化阶段** 所有物理内存被注册到`memory`类型的memblock中,表现为连续的未分配区域。此时`reserved`为空[^1]。 2. **预留内存操作** 当系统需要预留内存(如内核代码段、设备保留区域等),会通过`memblock_reserve()`将该内存区域**同时**添加到`memory`和`reserved`中: - `memory`中保留该区域的元数据,表示物理存在但逻辑上不可分配 - `reserved`中记录该区域已被占用,防止重复分配 3. **内存分配机制** 通过`memblock_alloc()`分配内存时: - 从`memory`中选择满足条件的区域 - 检查`reserved`中的重叠情况,确保不会分配已预留区域 - 分配成功后,新分配的区域会被**追加**到`reserved`中[^2] 4. **重叠验证示例** 假设物理内存范围$[0x1000, 0x2000)$被预留: ```c // memory中仍包含该区域,但状态标记为不可用 struct memblock_type memory = { .regions = {{base:0x1000, size:0x1000, ...}}, ... }; // reserved中添加新条目记录预留 struct memblock_type reserved = { .regions = {{base:0x1000, size:0x1000, ...}}, ... }; ``` #### 关键结论 ✅ **同一物理内存块会同时存在于`memory`和`reserved`中**,但通过以下机制保证一致性: - `memory`维护完整的物理内存拓扑 - `reserved`记录已分配/预留区域 - 分配时通过遍历`reserved`区域实现冲突检测[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值