您的位置:首页 > 其它

kmalloc,vmalloc,kmap 缺页的讨论

2013-05-12 14:59 274 查看
 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));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: