- 论坛徽章:
- 0
|
本帖最后由 paul719 于 2014-12-05 10:41 编辑
回复 2# Tinnal
谢谢版主解答,但是还是不理解。。。。版主可能还没真正理解我的疑惑~
详细阐述一下:
看最后的调用函数,确实是像你所说的,这里的unused是未被bootmem分配出去的内存。为了说清楚我的问题,我把bootmem到buddy system过渡阶段,尽可能说明白一些。
我们说对于bootmem的视角来看,就分为"已被分配出去的内存"和“未分配出去的内存”。
已被分配出去的内存(bitmap位:1)很简单,当然不可能交给buddy system的free_list(比如内核代码段区域),这个后面也会将这部分bit置1的区域交给reserve_list。
未被分配出去的内存(bitmap位:0)在我看来应该是两部分构成:1 可以分配给内核使用但尚未使用的 2 不可以使用的内存。
假如说未被分配出去的内存不存在第二种情况-不可以使用的内存,就清楚多了,去查bitmap位就好了,已分配的交给buddy system的reserve保留页列表,未分配的交给free空白页列表。
但是,这里出现了第二种情况,不可使用的内存,这里可能是版主和我存在理解不一样的地方,也是我迷惑的地方:
未被分配出去的内存就一定能交给buddy system的空白页链表,作为供内核申请的可用空间吗?我的理解是,不可以!不可以使用的内存就不能交给free空白页列表。
为什么会说有个不可使用的内存呢(也就是图中那个黑色区域)?版主在回复的第2点的说明可能认为这个区域根本不存在,因为内核要物理内存连续。我想说:
第一,一致性内存的概念应该是相对于线性地址空间而言的,物理地址不一致并不影响线性地址空间的一致性。
第二,这里的不可使用的内存也不是凭空捏造的,很多资料都有说到早期的处理器,内存bank之间是有hole的概念的,这里的洞也就是说有一块儿地址存在,但不可操作使用的空间,主要原因是受硬件制约,图中为了方便理解,可能画的夸张一点,实际上即使两个bank的物理地址空间紧挨着,在早期的处理器中,两个bank相邻的一块区域也是不可被操作的。
而且从代码中可以看出来:
free_memmap(prev_bank_end, bank_start);
注意看标红的参数,第一个参数是前一个bank的结束,第二个参数是当前bank的开始。用前一个bank的结束和后一个bank的开始标记的区域,难道不是不可用区域吗?因为bank本来就是描述可用物理内存的数据结构,不管是分配的内存和没有分配的内存,能用的都必然在bank范围之内,而这里的区域很明显在bank之外。
版主也说了,free_unused_memmap_node指定的区域,交给buddy system后,如果有人申请内存,系统就有可能把这块地址空间交给他使用。可是,再看看上面那个函数标红的区域,那一块区域在bank范围内吗?能用吗?如果是不可用,那为什么最后调用mark_bootmem(start, end, 0, 0)将这块区域设置成可分配区域?
附这部分源码:
static inline void
free_memmap(unsigned long start_pfn, unsigned long end_pfn)
{
struct page *start_pg, *end_pg;
unsigned long pg, pgend;
/*
* Convert start_pfn/end_pfn to a struct page pointer.
*/
start_pg = pfn_to_page(start_pfn - 1) + 1;
end_pg = pfn_to_page(end_pfn - 1) + 1;
/*
* Convert to physical addresses, and
* round start upwards and end downwards.
*/
pg = (unsigned long)PAGE_ALIGN(__pa(start_pg));
pgend = (unsigned long)__pa(end_pg) & PAGE_MASK;
/*
* If there are free pages between these,
* free the section of the memmap array.
*/
if (pg < pgend)
free_bootmem(pg, pgend - pg);
}
void __init free_bootmem(unsigned long addr, unsigned long size)
{
unsigned long start, end;
kmemleak_free_part(__va(addr), size);
start = PFN_UP(addr);
end = PFN_DOWN(addr + size);
mark_bootmem(start, end, 0, 0); //对应区域的bitmap置0,表示可分配
}
|
|