免费注册 查看新帖 |

Chinaunix

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

[内存管理] page cache问题 [复制链接]

论坛徽章:
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
61 [报告]
发表于 2012-05-30 10:15 |只看该作者
本帖最后由 embeddedlwp 于 2012-05-30 10:50 编辑

回复 59# firkraag

这个do_wp_page函数我有两个疑惑的地方,如下代码中红色部分

1.如56楼的那种 raw PFN mapping的情况,此时vm_normal_page返回NULL,直接goto 到gotten,
   但是gotten的地方为什么要判断是否可以分配anon_vma呢,这个raw PFN mapping明显是filemap啊?
2.红色部分为什么要判断page_table与orig_pte是否相等,感觉就是相等啊

static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                unsigned long address, pte_t *page_table, pmd_t *pmd,
                spinlock_t *ptl, pte_t orig_pte)
{
        struct page *old_page, *new_page;
        pte_t entry;
        int reuse = 0, ret = 0;
        int page_mkwrite = 0;
        struct page *dirty_page = NULL;

        old_page = vm_normal_page(vma, address, orig_pte);
        if (!old_page)
                goto gotten;

        /*
         * Take out anonymous pages first, anonymous shared vmas are
         * not dirty accountable.
         */
        if (PageAnon(old_page)) {
                if (!TestSetPageLocked(old_page)) {
                        reuse = can_share_swap_page(old_page);
                        unlock_page(old_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) {
                        /*
                         * 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);

                        if (vma->vm_ops->page_mkwrite(vma, old_page) < 0)
                                goto unwritable_page;

                        /*
                         * Since we dropped the lock we need to revalidate
                         * the PTE as someone else may have changed it.  If
                         * they did, we just return, as we can count on the
                         * MMU to tell us if they didn't also make it writable.
                         */
                        page_table = pte_offset_map_lock(mm, pmd, address,
                                                         &ptl);
                        page_cache_release(old_page);
                        if (!pte_same(*page_table, orig_pte))
                                goto unlock;

                        page_mkwrite = 1;
                }
                dirty_page = old_page;
                get_page(dirty_page);
                reuse = 1;
        }

        if (reuse) {
                flush_cache_page(vma, address, pte_pfn(orig_pte));
                entry = pte_mkyoung(orig_pte);
                entry = maybe_mkwrite(pte_mkdirty(entry), vma);
                if (ptep_set_access_flags(vma, address, page_table, entry,1))
                        update_mmu_cache(vma, address, entry);
                ret |= VM_FAULT_WRITE;
                goto unlock;
        }

        /*
         * Ok, we need to copy. Oh, well..
         */
        page_cache_get(old_page);
gotten:
        pte_unmap_unlock(page_table, ptl);

        if (unlikely(anon_vma_prepare(vma)))
                goto oom;

        VM_BUG_ON(old_page == ZERO_PAGE(0));
        new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
        if (!new_page)
                goto oom;
        cow_user_page(new_page, old_page, address, vma);
    /*
         * Re-check the pte - we dropped the lock
         */
        page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
        if (likely(pte_same(*page_table, orig_pte))) {
                if (old_page) {
                        page_remove_rmap(old_page, vma);
                        if (!PageAnon(old_page)) {
                                dec_mm_counter(mm, file_rss);
                                inc_mm_counter(mm, anon_rss);
                        }
                } else
                        inc_mm_counter(mm, anon_rss);
                flush_cache_page(vma, address, pte_pfn(orig_pte));
                entry = mk_pte(new_page, vma->vm_page_prot);
                entry = maybe_mkwrite(pte_mkdirty(entry), vma);
                /*
                 * Clear the pte entry and flush it first, before updating the
                 * pte with the new entry. This will avoid a race condition
                 * seen in the presence of one thread doing SMC and another
                 * thread doing COW.
                 */
                ptep_clear_flush(vma, address, page_table);
                set_pte_at(mm, address, page_table, entry);
                update_mmu_cache(vma, address, entry);
                lru_cache_add_active(new_page);
                page_add_new_anon_rmap(new_page, vma, address);

                /* Free the old page.. */
                new_page = old_page;
                ret |= VM_FAULT_WRITE;
        }
        if (new_page)
                page_cache_release(new_page);
        if (old_page)
                page_cache_release(old_page);
unlock:
        pte_unmap_unlock(page_table, ptl);
        if (dirty_page) {
                if (vma->vm_file)
                        file_update_time(vma->vm_file);

                /*
                 * 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.
                 */
                wait_on_page_locked(dirty_page);
                set_page_dirty_balance(dirty_page, page_mkwrite);
                put_page(dirty_page);
        }
        return ret;
oom:
        if (old_page)
                page_cache_release(old_page);
        return VM_FAULT_OOM;

unwritable_page:
        page_cache_release(old_page);
        return VM_FAULT_SIGBUS;
}

论坛徽章:
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
62 [报告]
发表于 2012-05-30 10:25 |只看该作者
回复 60# firkraag

恩,这里的raw应该就是不通过struct page结构啦,pte直接存放pfn

在fbmem.c中有使用的例子,以前还分析过,竟然忘记了。

Linux驱动修炼之道-内存映射.pdf (127.4 KB, 下载次数: 209)

论坛徽章:
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
63 [报告]
发表于 2012-05-30 10:29 |只看该作者
本帖最后由 embeddedlwp 于 2012-05-30 10:29 编辑

回复 60# firkraag

在ULK3讲解vm_operations_struct结构部分:

有个populate函数,对其描述如下:

populate Invoked to set the page table entries corresponding to the linear addresses of the
memory region (prefaulting). Mainly used for non-linear file memory mappings.

不知这里的prefaulting是干嘛的,还有貌似在新版本的kernel中没了这个函数,那它被那个函数取代了?




   

论坛徽章:
1
双鱼座
日期:2013-08-28 13:47:26
64 [报告]
发表于 2012-05-30 10:45 |只看该作者
回复 61# embeddedlwp
问题1:应该和该filemap是否是private有关。
问题2:如注释中说的,就是该处可能已经发生过cow,所以不相等。只有相等才是raw mapping情况。
   

论坛徽章:
1
双鱼座
日期:2013-08-28 13:47:26
65 [报告]
发表于 2012-05-30 11:05 |只看该作者
回复 63# embeddedlwp
具体用处见ulk3中16.2.6. Non-Linear Memory Mappings节
filemap_populate被populate_range取代了。vm_ops中也没有populate指针了。


   

论坛徽章:
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
66 [报告]
发表于 2012-05-30 11:14 |只看该作者
回复 65# firkraag


其实我还是不知到这个populate翻译过来是啥意思啊!


   

论坛徽章:
1
双鱼座
日期:2013-08-28 13:47:26
67 [报告]
发表于 2012-05-30 11:19 |只看该作者
回复 66# embeddedlwp
populate == 填充

   

论坛徽章:
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
68 [报告]
发表于 2012-05-30 11:22 |只看该作者
回复 67# firkraag

我在63楼说的那个prefaulting是干嘛呢


   

论坛徽章:
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
69 [报告]
发表于 2012-05-30 11:30 |只看该作者
回复 64# firkraag


在do_nonlinear_fault函数中,如果发现vma->vm_flags的VM_NONLINEAR标志没有设置为什么return 的是VM_FAULT_OOM,nonlinear fault应该与oom没有关系啊!

static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                unsigned long address, pte_t *page_table, pmd_t *pmd,
                int write_access, pte_t orig_pte)
{
        unsigned int flags = FAULT_FLAG_NONLINEAR |
                                (write_access ? FAULT_FLAG_WRITE : 0);
        pgoff_t pgoff;

        if (!pte_unmap_same(mm, pmd, page_table, orig_pte))
                return 0;

        if (unlikely(!(vma->vm_flags & VM_NONLINEAR) ||
                        !(vma->vm_flags & VM_CAN_NONLINEAR))) {
                /*
                 * Page table corrupted: show pte and kill process.
                 */
                print_bad_pte(vma, orig_pte, address);
                return VM_FAULT_OOM;
        }

        pgoff = pte_to_pgoff(orig_pte);
        return __do_fault(mm, vma, address, pmd, pgoff, flags, orig_pte);
}

   

论坛徽章:
1
双鱼座
日期:2013-08-28 13:47:26
70 [报告]
发表于 2012-05-30 11:38 |只看该作者
本帖最后由 firkraag 于 2012-05-31 20:21 编辑

回复 68# embeddedlwp
我觉得就是在页错误之前,设置pte。

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

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP