Chinaunix首页 | 论坛 | 博客
  • 博客访问: 732551
  • 博文数量: 79
  • 博客积分: 2671
  • 博客等级: 少校
  • 技术积分: 1247
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-02 15:26
个人简介

宅男

文章分类

全部博文(79)

文章存档

2017年(11)

2016年(12)

2015年(6)

2012年(10)

2011年(33)

2010年(7)

分类: LINUX

2011-06-27 11:52:30

  1. void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
  2. {
  3.     return __vmalloc_node(size, 1, gfp_mask, prot, -1,
  4.                 __builtin_return_address(0));
  5. }
  6. 关于__builtin_return_address在此不再赘述。
static void *__vmalloc_node(unsigned long size, unsigned long align,
   gfp_t gfp_mask, pgprot_t prot,
   int node, void *caller)
{
struct vm_struct *area;
void *addr;
unsigned long real_size = size;

size = PAGE_ALIGN(size);
if (!size || (size >> PAGE_SHIFT) > totalram_pages)
return NULL;
//首先在VMALLOC_START与VMALLOC_END之间找到一块未设备的地址空间。
area = __get_vm_area_node(size, align, VM_ALLOC, VMALLOC_START,
 VMALLOC_END, node, gfp_mask, caller);

if (!area)
return NULL;
//分配空间,并建立映射
addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller);

/*
* A ref_count = 3 is needed because the vm_struct and vmap_area
* structures allocated in the __get_vm_area_node() function contain
* references to the virtual address of the vmalloc'ed block.
*/
kmemleak_alloc(addr, real_size, 3, gfp_mask);

return addr;
}
static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
pgprot_t prot, int node, void *caller)
{
struct page **pages;
unsigned int nr_pages, array_size, i;

nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;
array_size = (nr_pages * sizeof(struct page *));

area->nr_pages = nr_pages;
/* Please note that the recursion is strictly bounded. */
if (array_size > PAGE_SIZE) {
pages = __vmalloc_node(array_size, 1, gfp_mask | __GFP_ZERO,
PAGE_KERNEL, node, caller);
area->flags |= VM_VPAGES;
} else {
pages = kmalloc_node(array_size,
(gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO,
node);
}
area->pages = pages;
area->caller = caller;
if (!area->pages) {
remove_vm_area(area->addr);
kfree(area);
return NULL;
}

for (i = 0; i < area->nr_pages; i++) {
struct page *page;
//分配空间,注意这儿是一个一个页的分配的,所以vmalloc分配的空间在物理地址上不一定连续,这是与kmalloc的一点区别
if (node < 0)
page = alloc_page(gfp_mask);
else
page = alloc_pages_node(node, gfp_mask, 0);

if (unlikely(!page)) {
/* Successfully allocated i pages, free them in __vunmap() */
area->nr_pages = i;
goto fail;
}
area->pages[i] = page;
}
//通过map_vm_area为area的虚拟地址空间与分配的物理页面建立映射关系
if (map_vm_area(area, prot, &pages))
goto fail;
return area->addr;

fail:
vfree(area->addr);
return NULL;
}


所以说vmalloc的整个过程就是在VMALLOC_START与VMALLOC_END之间找到一段符合size的地址空间,并分配相应的物理页面,由于这些物理页面是一页一页的分别分配的,所以在物理上不一定连续。最后将地址空间与这些分配的物理页面建立映射关系。
阅读(2848) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~