vmalloc 主要用于给内核从高端内存中以页为单位分配大块内存,对应关系如下所示,主要分配 896M~1G 的物理地址空间
vmalloc 的执行流程简述为:
-
分配小块内存。实例化vmalloc内存分配器的核心数据描述符 vmap_area|vm_struct|pages,为 vmalloc 的工作提供内存基础。分配合适的虚拟内存区间 hole 从空闲红黑树找到合适大小的hole,隔离分配给 vmalloc
-
分配物理内存。调用alloc_page系列函数,从 pcp 或者 buddy 0 阶每次分配1页物理内存,直到分配满足需求为止。
-
更新页表映射。将物理内存与虚拟内存一一建立映射,然后返回虚拟起始地址给用户,完成分配动作
vmalloc
vmalloc 调用链如下
vmalloc
--- __vmalloc
--- __vmalloc_node
--- get_vm_area_node : 获取一个 vm_struct
--- __get_vm_area_node
--- __vmalloc_area_node : 为 vm_struct 映射 pages
__get_vm_area_node 用于申请 vm_struct ,vm_struct 用于管理如下图所示的 vmalloc 区对应的虚拟地址,属于高端内存的非连续映射区域。所有的 vmalloc 区由 vmlist 串联起来,因此,想要根据某个地址区间使用 vmalloc 区,只需要遍历 vmlist 即可
具体地,__get_vm_area_node 实现如下
- 首先,调用 kmalloc_node 为 vm_struct 结构申请内存(这部分内存为低端内存)
- 根据 size+addr < tmp->addr 遍历 vmlist 找出待申请地址对应的下一个 vm_struct
- 初始化申请好的 vm_struct ,其表示的便是申请的地址段对应的虚拟地址
struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end, int node)
{
struct vm_struct **p, *tmp, *area;
unsigned long align = 1;
unsigned long addr;
// ...
addr = ALIGN(start, align);
size = PAGE_ALIGN(size);
area = kmalloc_node(sizeof(*area), GFP_KERNEL, node);
size += PAGE_SIZE;
write_lock(&vmlist_lock);
for (p = &vmlist; (tmp = *p) != NULL ;p = &tmp->next) {
if ((unsigned long)tmp->addr < addr) {
if((unsigned long)tmp->addr + tmp->size >= addr)
addr = ALIGN(tmp->size +
(unsigned long)tmp->addr