一:vmalloc
http://www.360doc.com/content/14/0614/13/18127083_386524093.shtml
1,vmalloc()的内核入口函数是kernel/mm/Vmalloc.c里的void *vmalloc(unsigned long size),size表示的是请求内核分配的字节数目。
从以上代码可知,vmalloc()主要是从高端内存区域去分配内存。
vmalloc()函数最终会调用到__vmalloc_node_range(unsigned long size,unsigned long align,unsigned long start,unsigned long end,gfp_t gfp_mask,,,,)函数
以上函数size表示的是具体分配的字节的大小,align表示对齐的大小,默认为1,start和end分别表示vmalloc分区区域的起始地址和结束地址,arm体系结构上默认如下:
__vmalloc_node_range所做的事情如下:
1. 首先检查请求分配的内存大小有没有超过最大的物理页面数。如果超过返回0,表示分配失败。
size = PAGE_ALIGN(size);
if (!size || (size >> PAGE_SHIFT) > num_physpages)
return NULL;
2,调用__get_vm_area_node()函数,
该函数作用,使用kmalloc在slab中,分配vm_struct数据结构。
接下来在单链表vmlist中查找适合的位置,并将新的vm节点插入到单链表中。
3,调用__vmalloc_area_node()函数
接下来初始化vm_struct结构中的pages和nr_pages字段。
a) 初始化nr_pages字段
nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;
b) 初始化pages数组
计算数组大小
array_size = (nr_pages * sizeof(struct page *));
如果数组大小大于1个页面,在非连续区进行分配,否则在连续区进行分配
从伙伴系统中进行物理内存页面的分配
最后根据实际申请到的物理内存情况建立页表映射。刷新TLB标志
4,调用insert_vmalloc_vmlist()函数
将vm_struct结构体插入到vmlist链表中
5,调用kmemleak_alloc()函数。
http://www.360doc.com/content/14/0614/13/18127083_386524093.shtml
1,vmalloc()的内核入口函数是kernel/mm/Vmalloc.c里的void *vmalloc(unsigned long size),size表示的是请求内核分配的字节数目。
void *vmalloc(unsigned long size)
{
return __vmalloc_node_flags(size,-1,GFP_KERNEL|__GFP_HIGHMEM);
}
从以上代码可知,vmalloc()主要是从高端内存区域去分配内存。
vmalloc()函数最终会调用到__vmalloc_node_range(unsigned long size,unsigned long align,unsigned long start,unsigned long end,gfp_t gfp_mask,,,,)函数
以上函数size表示的是具体分配的字节的大小,align表示对齐的大小,默认为1,start和end分别表示vmalloc分区区域的起始地址和结束地址,arm体系结构上默认如下:
#define VMALLOC_OFFSET (8*1024*1024)
#define VMALLOC_START (((unsigned long)high_memory+VMALLOC_OFFSET)&~(VMALLOC_OFFSET-1))
#define VMALLOC_END 0Xff000000UL //4080M
__vmalloc_node_range所做的事情如下:
1. 首先检查请求分配的内存大小有没有超过最大的物理页面数。如果超过返回0,表示分配失败。
size = PAGE_ALIGN(size);
if (!size || (size >> PAGE_SHIFT) > num_physpages)
return NULL;
2,调用__get_vm_area_node()函数,
该函数作用,使用kmalloc在slab中,分配vm_struct数据结构。
area = kmalloc_node(sizeof(*area), GFP_KERNEL, node);
struct vm_struct {
void *addr; // 虚拟地址的开始
unsigned long size; // 分配大小
unsigned long flags; // 标志位
struct page **pages; // 对应的页面
unsigned int nr_pages; // 页面数量
unsigned long phys_addr; // 物理地址
struct vm_struct *next; // 单链表,指向下一个vm节点
};
接下来在单链表vmlist中查找适合的位置,并将新的vm节点插入到单链表中。
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, 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; // 地址越界
}
// 插入新的vm节点到vmlist中去。
area->next = *p;
*p = area;
// 初始化新结点
area->flags = flags;
area->addr = (void *)addr;
area->size = size;
// 物理内存还未分配。
area->pages = NULL;
area->nr_pages = 0;
area->phys_addr = 0;
3,调用__vmalloc_area_node()函数
接下来初始化vm_struct结构中的pages和nr_pages字段。
a) 初始化nr_pages字段
nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;
b) 初始化pages数组
计算数组大小
array_size = (nr_pages * sizeof(struct page *));
如果数组大小大于1个页面,在非连续区进行分配,否则在连续区进行分配
if (array_size > PAGE_SIZE)
pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node);
else
pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node);
area->pages = pages;
从伙伴系统中进行物理内存页面的分配
for (i = 0; i < area->nr_pages; i++) {
if (node < 0)
area->pages[i] = alloc_page(gfp_mask); // 针对UMA
else
area->pages[i] = alloc_pages_node(node, gfp_mask, 0); // 针对NUMA
if (unlikely(!area->pages[i])) {
/* Successfully allocated i pages, free them in __vunmap() */
area->nr_pages = i;
goto fail;
}
}
最后根据实际申请到的物理内存情况建立页表映射。刷新TLB标志
4,调用insert_vmalloc_vmlist()函数
将vm_struct结构体插入到vmlist链表中
5,调用kmemleak_alloc()函数。