vmalloc是内核中非连续内存分配接口,返回高端的线性地址,而且处于VMALLOC_START ---VMALLOC_END之间。物理地址通过伙伴算法来获取,利用page_alloc来获取每个page,这样在线性地址上看是连续的,但是实际上物理地址是离散分布的,通过页表来实现连续的线性地址到非连续的物理地址的映射。
下面分析整个vmalloc的流程:__vmalloc->vmallc_node->
1.__get_vm_area_node,返回线性地址
用于从VMALLOC_START ---VMALLOC_END之间获取一个VMA结构,其大小是SIZE。
2. 利用alloc_page获取足够的物理地址,保存在struct page **数组中。
3.map_vm_area
在页表中映射 线性地址和物理地址,这里使用initmm.pgd作为页全局目录,并没有修改current->mm->pgd中的页全局目录。
因此可能出现3G-4G的vmalloc错误,这个错误在page_fault中修正,将initmm.pgd中对应的addr页全局表项项拷贝到current->mm->pgd中的addr对应的页全局表项
下面引用:
|
[Original] [Print] [Top] |
由于在生成新进程的时候,是将父进程映射表中的值直接拷贝过来的(从而内核部分的映射间接来自init_mm),因而他们的pgd指向的是同样一个地方。如果在init_mm中通过vmalloc建立了一个映射区间,但是在别的mm_struct中访问该区间地址时发生pagefault,那只有一种情况:该mm_struct中pgd表中对应vmalloc的那段区间尚未从init_mm中拷贝过来,也即是说本mm_struct实在vmalloc调用之前就创建了的。 在这样的情况下,如果新mm_struct中pte表中的某项不存在,那么相应init_mm中的该项也不存在,那就说明当前访问的这个地址不在vmalloc申请的空间中,因而是一个非法访问。 总结一下: 第一个问题:pte不用拷贝,因为新mm_struct中的pgd和init_mm中对应的pgd指向相同的地方,因而内核地址空间的映射上只会在pgd的层面上不一致,如果某项pgd一致,则该pgd和init_mm中对应pgd指向同一个pmd页面,因而pmd和pte肯定一致; 第二个问题:是这样的,当要去搜索exception table的时候,就说明系统已经访问了非法地址,而exception table只不过是一种补救措施。 |