免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2826 | 回复: 7
打印 上一主题 下一主题

[内存管理] 内核页表如何同步? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-07-16 16:37 |只看该作者 |倒序浏览
我的想法很简单,就是内核页表如何同步,当执行vmalloc时,是在init_mm中操作的,分配页表,物理页等,这些如何同步到其他进程的页表中

其他进程访问该vm区域时,发生do_page_fault异常,系统通过比较init_mm的pgd和当前的pgd,进行同步
只需要将init_mm的pgd_t设置到当前进程的pgd中,就搞定了,应该不需要往下到pmd的

但实际不是这样,why?

kernel 3.0

#ifdef CONFIG_X86_32
static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
{
...

        if (!pmd_present(*pmd))
                set_pmd(pmd, *pmd_k);
        else
                BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
...
}

论坛徽章:
0
2 [报告]
发表于 2013-07-16 17:10 |只看该作者
本帖最后由 blake326 于 2013-07-16 17:22 编辑

do_DataAbort(fsr,section fault)
do_translation_fault  

哥早就有这个问题了,没人niao
http://bbs.chinaunix.net/thread-4074212-1-1.html

论坛徽章:
0
3 [报告]
发表于 2013-07-17 10:53 |只看该作者
我的意思如下:

v2.4.32

vmalloc_fault:
        {
                /*
                 * Synchronize this task's top level page-table
                 * with the 'reference' page table.
                 *
                 * Do _not_ use "tsk" here. We might be inside
                 * an interrupt in the middle of a task switch..
                 */
                int offset = __pgd_offset(address);
                pgd_t *pgd, *pgd_k;
                pmd_t *pmd, *pmd_k;
                pte_t *pte_k;

                asm("movl %%cr3,%0":"=r" (pgd));
                pgd = offset + (pgd_t *)__va(pgd);
                pgd_k = init_mm.pgd + offset;

                if (!pgd_present(*pgd_k))
                        goto no_context;
                set_pgd(pgd, *pgd_k);
               
                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(pmd_k, address);
                if (!pte_present(*pte_k))
                        goto no_context;
                return;
        }

这段代码应该这样写
vmalloc_fault:
        {
                /*
                 * Synchronize this task's top level page-table
                 * with the 'reference' page table.
                 *
                 * Do _not_ use "tsk" here. We might be inside
                 * an interrupt in the middle of a task switch..
                 */
                int offset = __pgd_offset(address);
                pgd_t *pgd, *pgd_k;
                pmd_t *pmd, *pmd_k;
                pte_t *pte_k;

                asm("movl %%cr3,%0":"=r" (pgd));
                pgd = offset + (pgd_t *)__va(pgd);
                pgd_k = init_mm.pgd + offset;

                if (!pgd_present(*pgd_k))
                        goto no_context;
               
                 if(!pgd_present(*pgd)){//未同步
                    set_pgd(pgd, *pgd_k);//同步
                }
                else{
                      goto no_context;//pgd已同步,肯定是访问了不存在的页,error
                }
               //后面的废话可以cut掉

                return;
        }

不知可以有问题??

论坛徽章:
0
4 [报告]
发表于 2013-07-17 12:33 |只看该作者
效果是一样的,但是你的代码不具有伸缩性(体系机构的适应性)

论坛徽章:
0
5 [报告]
发表于 2013-07-17 16:02 |只看该作者
static noinline __kprobes int vmalloc_fault(unsigned long address)
{
        pgd_t *pgd, *pgd_ref;
        pud_t *pud, *pud_ref;
        pmd_t *pmd, *pmd_ref;
        pte_t *pte, *pte_ref;

        /* Make sure we are in vmalloc area: */
        if (!(address >= VMALLOC_START && address < VMALLOC_END))
                return -1;

        WARN_ON_ONCE(in_nmi());

        /*
         * Copy kernel mappings over when needed. This can also
         * happen within a race in page table update. In the later
         * case just flush:
         */
        pgd = pgd_offset(current->active_mm, address);
        pgd_ref = pgd_offset_k(address);
        if (pgd_none(*pgd_ref))
                return -1;

        if (pgd_none(*pgd)) {
                set_pgd(pgd, *pgd_ref);
                arch_flush_lazy_mmu_mode();
        } else {
                BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
        }

        /*
         * Below here mismatches are bugs because these lower tables
         * are shared:
         */

        pud = pud_offset(pgd, address);
        pud_ref = pud_offset(pgd_ref, address);
        if (pud_none(*pud_ref))
                return -1;

        if (pud_none(*pud) || pud_page_vaddr(*pud) != pud_page_vaddr(*pud_ref))
                BUG();

        pmd = pmd_offset(pud, address);
        pmd_ref = pmd_offset(pud_ref, address);
        if (pmd_none(*pmd_ref))
                return -1;

        if (pmd_none(*pmd) || pmd_page(*pmd) != pmd_page(*pmd_ref))
                BUG();

        pte_ref = pte_offset_kernel(pmd_ref, address);
        if (!pte_present(*pte_ref))
                return -1;

        pte = pte_offset_kernel(pmd, address);

        /*
         * Don't use pte_page here, because the mappings can point
         * outside mem_map, and the NUMA hash lookup cannot handle
         * that:
         */
        if (!pte_present(*pte) || pte_pfn(*pte) != pte_pfn(*pte_ref))
                BUG();

        return 0;
}
这个是3.9中的代码,不再刷了,只是访问了下.

说明前面的判断是正确的,

还可以一开始比较一下是不是就是init_mm的页表,这样后面都可以pass掉了

论坛徽章:
16
2015亚冠之吉达阿赫利
日期:2015-08-17 11:21:462015年迎新春徽章
日期:2015-03-04 09:58:11酉鸡
日期:2014-12-07 09:06:19水瓶座
日期:2014-11-04 14:23:29天秤座
日期:2014-03-02 08:57:52双鱼座
日期:2014-02-22 13:07:56午马
日期:2014-02-14 11:08:18双鱼座
日期:2014-02-13 11:09:37卯兔
日期:2014-02-06 15:10:34子鼠
日期:2014-01-20 14:48:19戌狗
日期:2013-12-19 09:37:46射手座
日期:2013-12-19 09:33:47
6 [报告]
发表于 2013-07-17 16:18 |只看该作者
本帖最后由 embeddedlwp 于 2013-07-17 16:18 编辑

LZ现在哪里高就?

论坛徽章:
0
7 [报告]
发表于 2013-07-18 17:17 |只看该作者
blake326 发表于 2013-07-16 17:10
do_DataAbort(fsr,section fault)
do_translation_fault  



- -,
内核页表同步就是这里处理的啊。
do_translation_fault  section错误走这个分支,里面处理页表同步。
pte错误走do_page_fault分支。里面肯定没有页表同步的处理了。

论坛徽章:
16
2015亚冠之吉达阿赫利
日期:2015-08-17 11:21:462015年迎新春徽章
日期:2015-03-04 09:58:11酉鸡
日期:2014-12-07 09:06:19水瓶座
日期:2014-11-04 14:23:29天秤座
日期:2014-03-02 08:57:52双鱼座
日期:2014-02-22 13:07:56午马
日期:2014-02-14 11:08:18双鱼座
日期:2014-02-13 11:09:37卯兔
日期:2014-02-06 15:10:34子鼠
日期:2014-01-20 14:48:19戌狗
日期:2013-12-19 09:37:46射手座
日期:2013-12-19 09:33:47
8 [报告]
发表于 2013-07-31 09:52 |只看该作者
本帖最后由 embeddedlwp 于 2013-07-31 10:07 编辑

回复 1# qtdszws

你贴code时候有个混乱,你把x86_32与x86_64的代码进行了比较。
x86_32由于支持PAE会有不同的处理。
正常情况下应该如x86_64这样,sync pgd就可以了。
但是如果是x86_32开启PAE的情况,pgd实际为PDPT表的index,sync pgd是没有意义的,所以sync的是pmd.
如果是x86_32没有开启PAGE的情况,那么对于x86_32来说又sync了一下pmd确实冗余.
这个在vmalloc_sync_one代码的comments中也有解释。
        /*
         * set_pgd(pgd, *pgd_k); here would be useless on PAE
         * and redundant with the set_pmd() on non-PAE. As would
         * set_pud.
         */
在x86_32未开启PAE的时候,各级映射的表项数为1024,1,1,1024,所以设置sync pgd跟sync pmd是一个意思。





   

评分

参与人数 1可用积分 +6 收起 理由
瀚海书香 + 6 赞一个!

查看全部评分

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP