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));
(具体的流程就是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));
相关文章推荐
- 关于kmalloc、vmalloc及kmap
- kmap/kmalloc/ioremap/kmalloc/kzalloc/kcalloc/vmalloc
- 关于kmalloc、vmalloc及kmap
- 关于kmalloc、vmalloc及kmap
- kmalloc、vmalloc、kmap、malloc的区别
- 关于kmalloc、vmalloc及kmap
- kmap/kmalloc/ioremap/kmalloc/kzalloc/kcalloc/vmalloc
- copy_to_user的实现以及get_user_pages/kmap_atomic/kmalloc
- Linux笔记记录4 kmalloc/vmalloc
- kmalloc与vmalloc区别
- kmalloc与vmalloc的对比
- kmalloc和vmalloc的区别
- kmalloc kzalloc vmalloc malloc 和get_free_page()的区别
- 关于kmalloc vmalloc 和malloc
- linux 共享内存映射原理 vmalloc kmalloc getfreepage
- kmalloc、vmalloc、__get_free_pages()的区别
- kmalloc、vmalloc、malloc的区别
- [Happy Coding] malloc/kmalloc/vmalloc/slab cache/__get_free_page
- kmalloc/kfree,vmalloc/vfree
- malloc kmalloc vmalloc