现在的位置: 首页 > 综合 > 正文

kmalloc,vmalloc,kmap 缺页的讨论

2013年02月25日 ⁄ 综合 ⁄ 共 1004字 ⁄ 字号 评论关闭

 kmap 类似vmalloc ,但是他不会缺页。为什么?
(具体的流程就是fork或者execv时拷贝了内核主页表的pgd条目(可理解为指针)。至于具体的pgd条目,指向的都是共享的pmd,pte)
kmap在系统初始化时,就会一直分配到pte级,
所以后面fork或者execv出来的进程访问kmap空间都不缺页,
但vmalloc是会重新生成新的pgd条目 ,
所有后面的进程内核空间里没有这个地址空间,就会缺页。
那么如果有多个进程同时执行kmap_atomic会不会冲突呢?答案是不会。
因为虽然多个kmap_atomic流程都尝试去修改内核主页表,但是kmap_atomic
获取的虚拟地址是每个cpu互相不冲突的,因为虚拟地址不冲突,从而修改的主页表
的pte位置也不同,也就没有同步的必要。

每个进程被新生成的时候调用的是fork, fork先复制内核页表,再遍历父进程vma区间所在的页表,即用户态页表,然后复制一份。
于是就有两个时机可能复制内核页表:
fork时,以及execv时,前者调用链是do_fork->dup_mm->mm_init->mm_alloc_pgd->pgd_alloc
后者是do_execve->mm_alloc->mm_init->mm_alloc_pgd->pgd_alloc

那既然fork能拷贝内核页表,为什么还要exec里再拷贝一遍?
其实,如果父进程是内核线程,那么fork并没有必要拷贝一份内核页表,它直接用共享的那个主页表就行了,即切换到内核线程时,直接把页表基地址设置
成内核主页表就行了。所以dup_mm会判断如果current->mm为空的话,就没有必要调用mm_init了。
那如果新生成的内核线程突然想执行一个用户态程序,就会调用execv, 这个时候,就需要给用户态程序拷贝一下内核页表了。
两者最终调用的都是pgd_alloc

根据内核态下界地址0xc000 0000计算出pdg中的index,这之上的index都是内核态pdg
boundary = pgd_index(__PAGE_OFFSET);

清空用户态映射
memset(pgd, 0, boundary * sizeof(pgd_t));

拷贝内核态页表pgd指针
memcpy(pgd + boundary,
init_level4_pgt + boundary,
  (PTRS_PER_PGD - boundary) * sizeof(pgd_t));

抱歉!评论已关闭.