详细的概念性解释就不说了,如果对vmalloc没有一点概念的话,可以稍微找些资料了解下,这里主要就是分析下在内核中vmalloc的实现;
直接物理内存映射(内核逻辑地址)-- 8 MB -- vm -- 1 page -- vm -- 1page --vm ......
大概就是这样:逻辑地址以high_memory为结束边界;然后是 8MB 的空洞(主要是防止指针越界访问);接着就是 VMALLOC_START为边界 开始了vmalloc 区域,该区域有多个vm小区域组成,每个小区域之间有1页(一个page大小)的空洞地址,作用还是防止越界访问;结束是以VMALLOC_END,后面还有个空洞地址,接着最后就是固定映射和临时映射的区域了;
结构体:
struct vm_struct {
struct vm_struct *next;//所有vm_struct链接的链表,vmlist是表头
void *addr;//分配得到的子区域在虚拟地址空间中的起始地址
unsigned long size;//表示区域长度
unsigned long flags;//标识
struct page **pages;//这是个指针数组,每个数组元素都是一个被映射的page指针
unsigned int nr_pages;//表示多少个page被映射
phys_addr_t phys_addr;
const void *caller;
};
这个结构体和进程虚拟地址空间的vma非常相识,值得注意;
下面这个结构体是用来管理kvm地址的
struct vmap_area {
unsigned long va_start;
unsigned long va_end;
unsigned long flags;
struct rb_node rb_node; /* address sorted rbtree */
struct list_head list; /* address sorted list */
struct list_head purge_list; /* "lazy purge" list */
struct vm_struct *vm;
struct rcu_head rcu_head;
};
/**
* vmalloc - allocate virtually contiguous memory
* @size: allocation size
* Allocate enough pages to cover @size from the page level
* allocator and map them into contiguous kernel virtual space.
*
* For tight control over page level allocator and protection flags
* use __vmalloc() instead.
*/
void *vmalloc(unsigned long size)
{
return __vmalloc_node_flags(size, NUMA_NO_NODE,
GFP_KERNEL | __GFP_HIGHMEM);//从高内存分配
}
static inline void *__vmalloc_node_flags(unsigned long size,
int node, gfp_t flags)
{
return __vmalloc_node(size, 1, flags, PAGE_KERNEL,
node, __builtin_return_address(0));
}
__builtin_return_address(0)的含义是,得到当前函数返回地址,即此函数被别的函数调用,然后此函数执行完毕后,返回,所谓返回地址就是那时候的地址。__builtin_return_address(1)的含义是,得到当前函数的调用者的返回地址。注意是调用者的返回地址,而不是函数起始地址。
/**
* __vmalloc_node - allocate virtually contiguous memory
* @size: allocation size
* @align: desired alignment
* @gfp_mask: flags for the page level allocator
* @prot: protection mask for