vmalloc的两个数据结构也就是vm_struct和pages依赖于slab系统,pages指向的page依赖于buddy系统,另外修改页表重新映射依赖于maping
vmalloc
=>__vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);//丫的竟然用高端内存????,是的,在最高的128M
=>__vmalloc_node(size, gfp_mask, prot, -1);
=>size = PAGE_ALIGN(size); //size大小页对齐
=>area = get_vm_area_node(size, VM_ALLOC, node, gfp_mask);//struct vm_struct *area;
=>return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node, gfp_mask);//VMALLOC_START和VMALLOC_END分别是vmalloc的起始和终止区域
=>area = kmalloc_node(sizeof(*area), gfp_mask & GFP_LEVEL_MASK, node);//vm_struct依赖于kmalloc,也就是slab系统
=>return kmalloc(size, flags);
=>return kmem_cache_alloc(malloc_sizes[i].cs_cachep, flags);//进入slab领域
=>size += PAGE_SIZE; //We always allocate a guard page. 申请的时候加个栅栏
=>for (p = &vmlist; (tmp = *p) != NULL ;p = &tmp->next) { //在vmlist链表里面找到area合适的位置,把新分配的area插入到里面
if ((unsigned long)tmp->addr < addr) {
if((unsigned long)tmp->addr + tmp->size >= addr)
addr = ALIGN(tmp->size +
(unsigned long)tmp->addr, align);
continue;
}
if ((size + addr) < addr)
goto out;
if (size + addr <= (unsigned long)tmp->addr)
goto found;
addr = ALIGN(tmp->size + (unsigned long)tmp->addr, align);
if (addr > end - size)
goto out;
}
=>
found: //一旦找到合适的地方就初始化
area->next = *p; //这两句话是将area加入到vm_struct链表中
*p = area;
area->flags = flags;
area->addr = (void *)addr;//addr作为内容,area作为载体
area->size = size;
area->pages = NULL;
area->nr_pages = 0;
area->phys_addr = 0;
=>return __vmalloc_area_node(area, gfp_mask, prot, node);
=>nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT; //真正申请的时候取消栅栏,递归的时候也做递减的作用
array_size = (nr_pages * sizeof(struct page *));
area->nr_pages = nr_pages;
=>if (array_size > PAGE_SIZE) {//为pages分配空间,如果pages正常占用的字节有限,但是如果超过一个页框大小,也就是4KB,需要递归调用,关于pages的详细描述详见“参考”里面的第一章节最后一张图片,很形象
pages = __vmalloc_node(array_size, gfp_mask | __GFP_ZERO,
PAGE_KERNEL, node);//页面大小超过1个页
area->flags |= VM_VPAGES;
} else {//
pages = kmalloc_node(array_size,
(gfp_mask & GFP_LEVEL_MASK) | __GFP_ZERO,
node);//页面大小没有超过1个页,递归递减1个页框,最终会调用的这个地方
}
area->pages = pages;
=>for (i = 0; i < area->nr_pages; i++) { 好多页面物理不连续,但是虚拟地址连续
if (node < 0)
area->pages[i] = alloc_page(gfp_mask);
else
area->pages[i] = alloc_pages_node(node, gfp_mask, 0);
if (unlikely(!area->pages[i])) {
/* Successfully allocated i pages, free them in __vunmap() */
area->nr_pages = i;
goto fail;
}
}
=>if (map_vm_area(area, prot, &pages))//页表映射修改
=>return area->addr;
void vfree(const void *addr)
__vunmap(addr, 1);
=>void __vunmap(const void *addr, int deallocate_pages)
area = remove_vm_area(addr);
=>struct vm_struct *remove_vm_area(const void *addr)
va = find_vmap_area((unsigned long)addr);
free_unmap_vmap_area(va);
for (i = 0; i < area->nr_pages; i++) {
struct page *page = area->pages[i];
__free_page(page);
}
kfree(area);
参考
高端内存映射之vmalloc分配内存中不连续的页–Linux内存管理(十九)
http://blog.csdn.net/gatieme/article/details/52705111
启动过程内存check和vmalloc大小设置
https://blog.csdn.net/sunlei0625/article/details/50465713
内核中的内存申请:kmalloc、vmalloc、kzalloc、kcalloc、get_free_pages
https://www.cnblogs.com/eleclsc/p/11531589.html