欢迎进入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]
德高培身,财多伤身。