linux内存管理之非连续物理地址分配(vmalloc)

欢迎进入Linux社区论坛,与200万技术人员互动交流 >>进入

  static int map_area_pmd(pmd_t *pmd, unsigned long address,

  unsigned long size, pgprot_t prot,

  struct page ***pages)

  {

  unsigned long base, end;

  base = address & PGDIR_MASK;

  address &= ~PGDIR_MASK;

  end = address + size;

  if (end > PGDIR_SIZE)

  end = PGDIR_SIZE;

  do {

  pte_t * pte = pte_alloc_kernel(&init_mm, pmd, base + address);

  if (!pte)

  return -ENOMEM;

  //轮到pte了 ^_^

  if (map_area_pte(pte, address, end – address, prot, pages))

  return -ENOMEM;

  address = (address + PMD_SIZE) & PMD_MASK;

  pmd++;

  } while (address < end);

  return 0;

  }

  //为页表页建立映射关系

  static int map_area_pte(pte_t *pte, unsigned long address,

  unsigned long size, pgprot_t prot,

  struct page ***pages)

  {

  unsigned long end;

  address &= ~PMD_MASK;

  end = address + size;

  if (end > PMD_SIZE)

  end = PMD_SIZE;

  do {

  struct page *page = **pages;

  WARN_ON(!pte_none(*pte));

  if (!page)

  return -ENOMEM;

  //具体的映射在这里了 ^_^

  set_pte(pte, mk_pte(page, prot));

  address += PAGE_SIZE;

  pte++;

  (*pages)++;

  } while (address < end);

  return 0;

  }

  只要理解了断开映射的过程,这段代码是很好理解的.

  总而言之:linux在建立映射的时候,从pgd 到pte相应的建立映射关系,最后将pte映射到分配得到的物理内存.而在断开映射的时候,linux内核从pgd找到pte,然后将pte置为none,表示pte末建立映射关系.

  四:vfree的实现:

  代码如下:

  void vfree(void *addr)

  {

  BUG_ON(in_interrupt());

  __vunmap(addr, 1);

  }

  跟踪至__vunmap:

  void __vunmap(void *addr, int deallocate_pages)

  {

  struct vm_struct *area;

  //参数有效性检查

  if (!addr)

  return;

  //判断addr是否是按页框对齐的

  if ((PAGE_SIZE-1) & (unsigned long)addr) {

  printk(KERN_ERR “Trying to vfree() bad address (%p)\n”, addr);

  WARN_ON(1);

  return;

  }

  //remove_vm_area:这个函数我们在之前已经分析过了 ^_^

  area = remove_vm_area(addr);

  if (unlikely(!area)) {

  //没有找到起始地址为addr的vm.则无效,退出

  printk(KERN_ERR “Trying to vfree() nonexistent vm area (%p)\n”,

  addr);

  WARN_ON(1);

  return;

  }

  if (deallocate_pages) {

  int i;

  for (i = 0; i < area->nr_pages; i++) {

  if (unlikely(!area->pages[i]))

  BUG();

  //释放请求获得的页面

  __free_page(area->pages[i]);

  }

  //释放分配的page 描述符

  kfree(area->pages);

  }

  //释放内核的vm 描述符

  kfree(area);

  return;

  }

  五:总结

  经过上面的分析,我们可以看到,vmalloc分配内存的过程是十分低效的,不仅要从伙伴系统中取内存而且要建立映射关系,显然,用vmalloc分配较小的内存是不合算的。此外。有个问题值得思考一下:为什么用__get_free_page不需要建立映射关系,而vmalloc就需要呢?

  其实,不管使用何种方式。线性地址到物理地址的转换最终都要经过硬件的页式管理去完成。所不同的是__get_free_page返回的线性地址是属于(PAGE_OFFSET,HIGH_MEMORY)之间的,这段线性地址在内核初始化的时候就完成了映射。而vmalloc使用的线性地址是属于(VMALLOC_START VMALLOC_END)之间的,也就是说属于一个临时映射区,所以必须为其建立映射关系。

http://ericxiao.cublog.cn/

[1][2][3][4]

德高培身,财多伤身。

linux内存管理之非连续物理地址分配(vmalloc)

相关文章:

你感兴趣的文章:

标签云: