免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: yangPSO
打印 上一主题 下一主题

[内存管理] mmap和msync相关的一个问题 [复制链接]

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
11 [报告]
发表于 2014-12-01 16:14 |只看该作者
yangPSO 发表于 2014-11-28 16:35
回复 9# humjb_1983

之前我提供的流程有点问题(因为只有已经有dirty标记的page才能进入到那个流程),writeback中应该不会根据pte的dirty标志来设置page的dirty标记。
真正保证mmap dirty page被写入磁盘的机制应该是这样的:
mmap后,第一次写入,此时会page fault,然后mkdirty,此后,pte和page中都同时设置好了dirty标记,相应的dirty page能保证被写入磁盘。(这个流程没有疑问,之前已经清楚)
后续再次写入时,分两种情况:
1、再次写入时,原来的dirty page还没来得及写入,此时应该直接修改掉原有page中的内容即可,由于原有的pte和page中dirty标记都还在,所以,此时肯定也能保证相应dirty page被写入。
2、再次写入时,原理的dirty page已经writeback过了,相应的dirty标记都已经清除,就是我们这里正讨论的情况。这种情况应该是通过如下机制保证的:
在第一次写入后的dirty page的wirteback流程中会设置该page为页保护,就是楼上兄弟说的:
clear_page_dirty_for_io
  page_mkclean
    page_mkclean_file
      page_mkclean_one
       entry = pte_wrprotect(entry);

然后,当该page被再次修改时,会触发page fault,而在page fault的流程中,会判断mmap页写保护的情况,这种情况下,会根据pte的dirty标记设置page的dirty标记,并将该page重新设置为可写的:
__do_page_fault
  handle_pte_fault
    do_wp_page

...
        else if (unlikely((vma->vm_flags & (VM_WRITE|VM_SHARED)) ==
                                        (VM_WRITE|VM_SHARED))) {
                /*
                 * Only catch write-faults on shared writable pages,
                 * read-only shared pages can get COWed by
                 * get_user_pages(.write=1, .force=1).
                 */
                if (vma->vm_ops && vma->vm_ops->page_mkwrite) {
                        struct vm_fault vmf;
                        int tmp;

                        vmf.virtual_address = (void __user *)(address &
                                                                PAGE_MASK);
                        vmf.pgoff = old_page->index;
                        vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE;
                        vmf.page = old_page;

                        /*
                         * Notify the address space that the page is about to
                         * become writable so that it can prohibit this or wait
                         * for the page to get into an appropriate state.
                         *
                         * We do this without the lock held, so that it can
                         * sleep if it needs to.
                         */
                        page_cache_get(old_page);
                        pte_unmap_unlock(page_table, ptl);

                        tmp = vma->vm_ops->page_mkwrite(vma, &vmf);
...

用systemTap打点,相应的堆栈如下:
Returning from:  0xffffffff811292b0 : set_page_dirty+0x0/0x70 [kernel]
Returning to  :  0xffffffff811b0a1f : __block_page_mkwrite+0xdf/0x120 [kernel]
0xffffffffa022d39a : ext4_page_mkwrite+0x17a/0x390 [ext4]
0xffffffff8113f89e : do_wp_page+0x5ee/0x8d0 [kernel]
0xffffffff8114036d : handle_pte_fault+0x2dd/0xb70 [kernel]
0xffffffff81140de4 : handle_mm_fault+0x1e4/0x2b0 [kernel]
0xffffffff81042b39 : __do_page_fault+0x139/0x490 [kernel]
0xffffffff814fbfce : do_page_fault+0x3e/0xa0 [kernel]
0xffffffff814f9325 : page_fault+0x25/0x30 [kernel]
ffffea0003b22398


论坛徽章:
1
15-16赛季CBA联赛之北控
日期:2016-03-15 22:53:29
12 [报告]
发表于 2014-12-01 22:54 |只看该作者
本帖最后由 yangPSO 于 2014-12-01 23:23 编辑

回复 11# humjb_1983

我在4楼时也想过是通过写保护实现的,但当时错误的认为是memcopy一次发生一次写保护,这样效率也太差了。
现在看来内核的设计是很巧妙的,page cache每次回写后,当再次写入时才再次设置脏标志,这样既保证了
效率,也保证了可靠性(即使CPU不会设置pte的dirty位也可以捕获了page已经被写了)。谢谢humjb_1983兄。


呵呵,说实话,还有好多的疑问,估计这里讨论不完,比如函数do_wp_page中下面的注释啥意思:
unlock:
        pte_unmap_unlock(page_table, ptl);
        if (dirty_page) {
                /*
                 * Yes, Virginia, this is actually required to prevent a race
                 * with clear_page_dirty_for_io() from clearing the page dirty
                 * bit after it clear all dirty ptes, but before a racing
                 * do_wp_page installs a dirty pte.
                 *
                 * do_no_page is protected similarly.
                 */

                if (!page_mkwrite) {
                        wait_on_page_locked(dirty_page);
                        set_page_dirty_balance(dirty_page, page_mkwrite);
                }

   

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
13 [报告]
发表于 2014-12-02 09:04 |只看该作者
yangPSO 发表于 2014-12-01 22:54
回复 11# humjb_1983

我在4楼时也想过是通过写保护实现的,但当时错误的认为是memcopy一次发生一次写保 ...

呵呵,不用客气,问题多探讨就清晰了~
do_wp_page和writeback流程是相关的,相关注释需要结合起来看,还没有时间仔细去研究,有兴趣可以去翻一翻相应的补丁~~
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP