Chinaunix

标题: 内存操作时如何保证mmap相关的页回写到磁盘 [打印本页]

作者: humjb_1983    时间: 2014-06-18 14:59
标题: 内存操作时如何保证mmap相关的页回写到磁盘
内存操作,比如memcpy,直接修改指定虚拟地址区的内容,如果被修改的虚拟地址区为mmap相关的区域,如何能保证相关修改最终会回写到磁盘中去?
个人理解,直接操作虚拟地址时,对应的指令应该就是mov之类,虚拟地址到物理地址直接的转换由mmu和页表自动完成,整个过程应该不涉及对page的操作,
也不区分目的vma是否有file map。在这个过程中,并没有设置相关page为dirty的操作,那么如何能保证相关page能进行回写呢?
请大家指点。
作者: 塑料袋    时间: 2014-06-18 15:10
回写前,会通过反向映射,找到各个pte,并清其pte_dirty位。
作者: asuka2001    时间: 2014-06-18 15:17
回复 1# humjb_1983

个人认为,pte中的 dirty位应该是硬件自动置位吧!
作者: njuzhyf    时间: 2014-06-18 15:25
回复 1# humjb_1983


ls两个说的都对。。。

你说的自动完成是,内核在修改页时,MMU会自动置位页表项中脏位。在回收和回写时,会通过逆向映射把
这个位转移到page描述符的标志中去。。。。。然后内核就能检查到页是不是脏页了。
   
作者: chenyu105    时间: 2014-06-18 16:34
1.第一次访问mmap区间时,会触发缺页流程,分配一个page cache,将pfn写pte里,然后显示的pte_mkdirty置该页为脏;
2.接下来用户态不管怎么写这个页,都写的是page cache的页;
3.回写线程,将脏页写回磁盘后,置pte无效,这样,下次用户态再访问mmap区间后,又回到流程1
作者: gaojl0728    时间: 2014-06-18 17:41
回复 5# chenyu105


完全正解, mmap后read, write 的内存其实就是page cache.
其实看看代码就明白了。


作者: asuka2001    时间: 2014-06-18 20:12
本帖最后由 asuka2001 于 2014-06-18 20:14 编辑

回复 5# chenyu105

1. page fault流程中在 __do_fault() @ mm/memory.c中看到有 pte_mkdirty(),不知道你是不是指这里?

__do_fault()
{
......
        if (likely(pte_same(*page_table, orig_pte))) {
                flush_icache_page(vma, page);
                entry = mk_pte(page, vma->vm_page_prot);
                if (flags & FAULT_FLAG_WRITE)
                        entry = maybe_mkwrite(pte_mkdirty(entry), vma);
......
}

3. 对 write back流程不熟悉,请教下 page write back的入口函数和 置pte无效的位置,万分感谢!
   
作者: humjb_1983    时间: 2014-06-18 21:41
感谢各位大拿!@塑料袋 @asuka2001 @chenyu105 @gaojl0728 @njuzhyf
其实我的最大疑问,就是:谁来置相关page为dirty,有兄弟说是mmu硬件置的(我看网上也有这个说法),但也有兄弟说是 page fault中置的,这个各位大拿们再确认下?
谢谢!
作者: humjb_1983    时间: 2014-06-18 21:43
chenyu105 发表于 2014-06-18 16:34
1.第一次访问mmap区间时,会触发缺页流程,分配一个page cache,将pfn写pte里,然后显示的pte_mkdirty置该页 ...

确认是在page fault中设置dirty的?呵呵,代码贴一下?
作者: humjb_1983    时间: 2014-06-18 21:46
njuzhyf 发表于 2014-06-18 15:25
回复 1# humjb_1983

今天看了下代码,也是这么想的,但dirty标记设置的地方看似还有争议~
作者: humjb_1983    时间: 2014-06-18 21:47
塑料袋 发表于 2014-06-18 15:10
回写前,会通过反向映射,找到各个pte,并清其pte_dirty位。

感谢!
疑问还在于dirty设置的地方~

作者: humjb_1983    时间: 2014-06-18 21:47
asuka2001 发表于 2014-06-18 15:17
回复 1# humjb_1983

个人认为,pte中的 dirty位应该是硬件自动置位吧!

感谢兄弟,我以前也是怎么猜的~
作者: sundrop    时间: 2014-06-19 00:08
记得好像有个回调函数,在写页面缺页的时候回调用,然后把页面置脏吧。。
vma->vm_ops->page_mkwrite ?
作者: njuzhyf    时间: 2014-06-19 09:50
回复 8# humjb_1983

额。。。。。

你混淆了。脏位有两个地方:页表项中有一个脏位;page描述符的flags标志中有一个PG_dirty位。

页表项中的脏位在写这个页表项时由MMU自动置位,但硬件不会清除这个位。这个位的清除是要由内核
来完成的。而且内核也可以在适当的时候主动置这个位。比如缺页*写*异常时,他们上面列了代码了,
内核会自己先置这个位。

page描述符里面的那个脏位就由内核管理了,这个位就是用来判断这个页是不是脏页。比如说,有多个
进程mmap了这个页,其中一个进程修改了这个页,那么那个进程的页表项中的脏位就会由MMU置位。
但page描述符里的脏位还未置位啊。所以在回收周期扫描到这个页时,会通过逆向映射查找映射这个页的
页表项,如果发现页表项中脏位被置位了,那么就会将page描述符的脏位置位表明这是一个脏页。
   
作者: chenyu105    时间: 2014-06-19 10:10
回复 14# njuzhyf

我看的是mips的实现,手册里没说写地址,会使硬件自动给mmu对应的tlb条目置脏,不知道x86的是不是这样。
总觉得如果是这样的话,那硬件频繁置脏这个效率比较低了。

作者: chenyu105    时间: 2014-06-19 10:10
回复 7# asuka2001
1. 就是这里。

2.  之前我说的有错,不是回写,是回收流程:
try_to_unmap_file -> try_to_unmap_one
->page_remove_rmap ->ptep_clear_flush  
如果是回写,只把dirty位清除,没有置无效。



   
作者: njuzhyf    时间: 2014-06-19 10:28
回复 15# chenyu105

From Intel Spec

Whenever there is a write to a linear address, the processor sets the dirty flag (if it is
not already set) in the paging-structure entry that identifies the final physical
address for the linear address (either a PTE or a paging-structure entry in which the
PS flag is 1).

...These flags are “sticky,” meaning that,
once set, the processor does not clear them; only software can clear them.

   
作者: chenyu105    时间: 2014-06-19 10:37
回复 17# njuzhyf
哦好的 长见识
作者: humjb_1983    时间: 2014-06-19 10:52
njuzhyf 发表于 2014-06-19 09:50
回复 8# humjb_1983

额。。。。。

确认mmu会自动设置pte中dirty标志?如果是这样那page fault中再设置一次是否就多余了?
作者: humjb_1983    时间: 2014-06-19 11:01
njuzhyf 发表于 2014-06-19 10:28
回复 15# chenyu105

From Intel Spec

“paging-structure entry that identifies the final physical
address for the linear address (either a PTE or a paging-structure entry in which the
PS flag is 1).”
这里说的paging-structure entry应该是指pte吧?跟内核管理的page结构没啥关系吧?

作者: chenyu105    时间: 2014-06-19 11:05
回复 20# humjb_1983


这个pte我觉得是当前进程的页表,硬件通过cr3的pgd找到对应的pte给他置脏,pte放的就是page的pfn + page的一些属性
pte的属性和page的属性会共享一部分

作者: chenyu105    时间: 2014-06-19 11:12
回复 19# humjb_1983
对intel的x86是多余的 ,不过其他架构没这个硬件置脏,至少mips没有。
不知道其他架构是怎么设计的,powerpc arm
作者: humjb_1983    时间: 2014-06-19 11:12
chenyu105 发表于 2014-06-19 11:05
回复 20# humjb_1983

呵呵,对硬件来说,它不知道page struct的存在吧?
作者: njuzhyf    时间: 2014-06-19 11:13
回复 19# humjb_1983

上面回复了一段Intel Spec里的说明。MMU确实会主动置*页表项*中的脏位,但不负责清除。内核负责清除。

而且内核确实也会主动设置*页表项*中的脏位。就像缺页*写*异常那样。不会重复,是因为MMU只有在
脏位未被置位的时候才会置位。

或者我举个例子。进程第一次读文件中的内容,内核会fault进对应页面到pagecache中去,因为是读异常,
所以内核不会置脏位吧。接下来进程又要对同一页内容进行修改了,那么此时页已经在pagecache中了,也
不需要进行什么缺页异常了,直接由MMU进行虚拟地址到物理地址的转换去写pagecache了,那么这个时候
内核都不“参与”了,谁去置页表项的脏位呢?MMU自己
   
作者: njuzhyf    时间: 2014-06-19 11:17
回复 23# humjb_1983


是的。硬件不关心page_struct。它只会置***页表项***中的脏位。前面说了,页表项中的脏位
会在回收周期中通过逆向映射找到,并设置到page_struct的flags标志中去,这样,内核就知道这
是一个脏页
作者: humjb_1983    时间: 2014-06-19 11:27
njuzhyf 发表于 2014-06-19 11:13
回复 19# humjb_1983

上面回复了一段Intel Spec里的说明。MMU确实会主动置*页表项*中的脏位,但不负责清 ...

这下搞明白了,感谢兄台指点!
作者: 塑料袋    时间: 2014-06-19 12:36
这个分CPU
像Intel,是硬件自动至PTE_Dirty
像ARM,是清PTE_Dirty时,置为只读;清PTE_Access时,置为未映射。 反之,映射前置上PTE_Access;写映射前置上PTE_Dirty。
作者: humjb_1983    时间: 2014-06-19 12:41
塑料袋 发表于 2014-06-19 12:36
这个分CPU
像Intel,是硬件自动至PTE_Dirty
像ARM,是清PTE_Dirty时,置为只读;清PTE_Access时,置为未映 ...

感谢,又涨姿势了~
作者: wth0722    时间: 2014-06-19 14:33
回复 像ARM,是清PTE_Dirty時,置為只讀;清PTE_Access時,置為未映射。 反之,映射前置上PTE_Access;寫映射前置上PTE_Dirty。27# 塑料袋

你得到他了

在ARM mmu這邊完全不知到有dirty bit存在,所以才會有hw pte跟linux pte存在

以下是ARM的註解
/*
* Hardware-wise, we have a two level page table structure, where the first
* level has 4096 entries, and the second level has 256 entries.  Each entry
* is one 32-bit word.  Most of the bits in the second level entry are used
* by hardware, and there aren't any "accessed" and "dirty" bits.
   




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2