linux内核页表

来源:互联网 发布:尚品奥莱软件 编辑:程序博客网 时间:2024/05/16 06:11

曾 几何时,我一直被迷惑着,我知道所有进程和所有内核线程共享内核页表,也就是在页全局目录的768项以上的目录项指向的页表,我一直以为在创建新的进程的 时候创建新进程的页全局目录的时候会连带的把内核的基础全局目录复制过去,实际上这是合理的,当我看到网上很多文章都这么说时,我似乎感到一种欣慰:我太有才了!但是当我读到2.6.17的源代码时, 梦被打碎了,在pgd_alloc里面没有上述的动作,代码如下:

pgd_t *pgd_alloc(struct mm_struct *mm)
{
int i;
pgd_t *pgd = quicklist_alloc(0, GFP_KERNEL, pgd_ctor);
if (PTRS_PER_PMD == 1 || !pgd)
return pgd;
for (i = 0; i < UNSHARED_PTRS_PER_PGD; ++i) {
pmd_t *pmd = pmd_cache_alloc(i);
if (!pmd)
goto out_oom;
paravirt_alloc_pd(__pa(pmd) >> PAGE_SHIFT);
set_pgd(&pgd[i], __pgd(1 + __pa(pmd)));
}
return pgd;
out_oom:
for (i--; i >= 0; i--) {
pgd_t pgdent = pgd[i];
void* pmd = (void *)__va(pgd_val(pgdent)-1);
paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
pmd_cache_free(pmd, i);
}
quicklist_free(0, pgd_dtor, pgd);
return NULL;
}
我们看到,仅仅初始化了768之前的页目录项,没有内核页目录的踪迹,怎么回事呢?网上的那么多文章的依据又是什么呢?迷茫中,我想到了版本问题,于是我查阅了2.4的系列内核源代码,果然是那么回事:
172 pgd_t *pgd_alloc(struct mm_struct *mm)
{
int i;
pgd_t *pgd = kmem_cache_alloc(pae_pgd_cachep, GFP_KERNEL);
if (pgd) {
unsigned long pmd;
for (i = 0; i < USER_PTRS_PER_PGD; i++) {
pmd = __get_free_page(GFP_KERNEL);
if (!pmd)
goto out_oom;
clear_page(pmd);
set_pgd(pgd + i, __pgd(1 + __pa(pmd)));
}
memcpy(pgd + USER_PTRS_PER_PGD,
swapper_pg_dir + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
}
return pgd;
out_oom:
for (i--; i >= 0; i--)
free_page((unsigned long)__va(pgd_val(pgd[i])-1));
kmem_cache_free(pae_pgd_cachep, pgd);
return NULL;
}
看起来比2.6的内核长很多,这么做合理是合理,但是有必要吗?用户进程真的会那么频繁的进入内核从而访问内核吗?想想malloc库函数,再想想库提供用户io缓冲区,如果你没有研究过前面的两个,那么mmap总该知道吧,为什么要用到前面的库函数,而且他们的库级别实现非常复杂,有自己的一套策略,有何诱惑可以值得库设计者付出这么大的代价呢?究其原因就是为了尽可能少的进行系统调用从而进入内核空间,要知道计算机的目的是为人服务,为人服务就是运行用户的程序,也就是用户进程,并不是为了让人去研究操作系统,操作系统内核只是提供服务,进行全局统筹管理,遗憾的是,他和用户进程是共享
处理器资源的,这就要求它必须在最短的时间内完成自己的任务,全程只需分清一个主次关系,用户进程为主,内核运行为辅,用户不求助,内核别插手用户事务,只有当用户真正要内核时,内核再挺身而出,这样就把内核事务拖到了不能再拖为止,于是乎再拷掠前面的问题时我想到了缺页中断,下面看看缺页中断是怎么处理的:
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
......
if (unlikely(address >= TASK_SIZE)) {
if (!(error_code & 5))
goto vmalloc_fault;
......
vmalloc_fault:
{
......
int index = pgd_index(address);//得到缺页地址应该所在的页全局目录的目录项索引
pgd_t *pgd, *pgd_k;
pmd_t *pmd, *pmd_k;
pte_t *pte_k;
asm("movl %%cr3,%0":"=r" (pgd));//读出当前进程的页全局目录的位置
pgd = index + (pgd_t *)__va(pgd);//得到具体的对应于缺页地址的目录项
pgd_k = init_mm.pgd + index;//swapper_pgd_dir中队应的目录项
if (!pgd_present(*pgd_k))//如果swapper_pgd_dir模板中都没有,准备后事吧
goto no_context;//善后
......
pmd = pmd_offset(pgd, address);//以下的分析方法同上
pmd_k = pmd_offset(pgd_k, address);
if (!pmd_present(*pmd_k))
goto no_context;//善后
set_pmd(pmd, *pmd_k);
pte_k = pte_offset_kernel(pmd_k, address);//内核和用户进程共享内核页表,因此以下也就没有set_pmd(pmd, *pmd_k)之类的了
if (!pte_present(*pte_k))
goto no_context;
return;//最终引起缺页的地址的MMU元素被创建,访问重新开始
}
}
以上的分析应该很明了了,在此再小声说一句,网上的文章只是作者的理解,仅仅可以帮你理解问题,真正解决问题,你还得自己来,比如读内核,你必须自亲自阅读才能悟道。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 英雄联盟进入游戏界面黑屏怎么办 英雄联盟经常未响应怎么办 英雄联盟总是无响应怎么办 英雄联盟新客户端太卡怎么办 win10英雄联盟fps低怎么办 lol登游戏闪退怎么办 lol读取界面很慢怎么办 玩lol卡死黑屏怎么办 lol黑屏退不出来怎么办 电脑分辨率调高了黑屏怎么办 电脑设置分辨率黑屏了怎么办 分辨率调高了黑屏怎么办 电脑调分辨率黑屏了怎么办 科沃斯cr120遥控器丢了怎么办 买了kl色的钻戒怎么办 qq旋风没有蓝钻怎么办 手机桌面短信图标不见了怎么办 手机桌面qq音乐图标不见了怎么办 电脑显示器图标变大了怎么办 手机卡信号好但是网络不好怎么办 陌陌功能被限制怎么办 陌陌设备封了怎么办 荣耀v8手机开机键不灵怎么办 联通积分换的腾讯会员怎么办 小米6手机变卡了怎么办 微信绑定银行卡次数太多怎么办 银行卡绑定太多微信了怎么办 怎样给qq设密码怎么办 吃了心悦胶囊上火怎么办 qq暂时被冻结了怎么办 部落群审核未通过怎么办 qq被限制解封该怎么办 微信提现成功但没到账怎么办 拍拍贷登录不上怎么办 京东店铺出租保证金怎么办 所选地区无货怎么办 闲鱼七天没发货怎么办 续贷密码忘了怎么办 微店商家不发货怎么办 微店商家不退钱怎么办 维修车辆被拍违章停车怎么办