Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1176875
  • 博文数量: 573
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 66
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-28 16:21
文章分类

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: LINUX

2015-12-04 09:38:12

vmalloc代码

vmalloc()->__vmalloc_node_flags()->__vmalloc_node()->__vmalloc_node_range()->__vmalloc_area_node()->alloc_page()

 

mm/vmalloc.c

void *vmalloc(unsigned long size)
{
 return __vmalloc_node_flags(size, -1, 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));
}

 

static void *__vmalloc_node(unsigned long size, unsigned long align,
       gfp_t gfp_mask, pgprot_t prot,
       int node, void *caller)
{
 return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
    gfp_mask, prot, node, caller);
}

 

void *__vmalloc_node_range(unsigned long size, unsigned long align,
   unsigned long start, unsigned long end, 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;

 area = __get_vm_area_node(size, align, VM_ALLOC | VM_UNLIST,
      start, end, node, gfp_mask, caller);

 if (!area)
  return NULL;

 addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller);

 /*
  * In this function, newly allocated vm_struct is not added
  * to vmlist at __get_vm_area_node(). so, it is added here.
  */
 insert_vmalloc_vmlist(area);

 /*
  * 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)
{
 const int order = 0;
 struct page **pages;
 unsigned int nr_pages, array_size, i;
 gfp_t nested_gfp = (gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO;

 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, nested_gfp|__GFP_HIGHMEM,
    PAGE_KERNEL, node, caller);
  area->flags |= VM_VPAGES;
 } else {
  pages = kmalloc_node(array_size, nested_gfp, 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;
  gfp_t tmp_mask = gfp_mask | __GFP_NOWARN;

  if (node < 0)
   page = alloc_page(tmp_mask);
  else
   page = alloc_pages_node(node, tmp_mask, order);

  if (unlikely(!page)) {
   /* Successfully allocated i pages, free them in __vunmap() */
   area->nr_pages = i;
   goto fail;
  }
  area->pages[i] = page;
 }

 if (map_vm_area(area, prot, &pages))
  goto fail;
 return area->addr;

fail:
 warn_alloc_failed(gfp_mask, order, "vmalloc: allocation failure, "
     "allocated %ld of %ld bytes\n",
     (area->nr_pages*PAGE_SIZE), area->size);
 vfree(area->addr);
 return NULL;
}

 

阅读(759) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~