mm: dirty page accounting vs VM_MIXEDMAP
Dirty page accounting accurately measures the amound of dirty pages in writable shared mappings by mapping the pages RO (as indicated by vma_wants_writenotify). We then trap on first write and call set_page_dirty() on the page, after which we map the page RW and continue execution. When we launder dirty pages, we call clear_page_dirty_for_io() which clears both the dirty flag, and maps the page RO again before we start writeout so that the story can repeat itself. vma_wants_writenotify() excludes VM_PFNMAP on the basis that we cannot do the regular dirty page stuff on raw PFNs and the memory isn't going anywhere anyway. The recently introduced VM_MIXEDMAP mixes both !pfn_valid() and pfn_valid() pages in a single mapping. We can't do dirty page accounting on !pfn_valid() pages as stated above, and mapping them RO causes them to be COW'ed on write, which breaks VM_SHARED semantics. Excluding VM_MIXEDMAP in vma_wants_writenotify() would mean we don't do the regular dirty page accounting for the pfn_valid() pages, which would bring back all the head-aches from inaccurate dirty page accounting. So instead, we let the !pfn_valid() pages get mapped RO, but fix them up unconditionally in the fault path. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Nick Piggin <nickpiggin@yahoo.com.au> Acked-by: Hugh Dickins <hugh@veritas.com> Cc: "Jared Hulbert" <jaredeh@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
cde5353599
commit
251b97f552
14
mm/memory.c
14
mm/memory.c
|
@ -1697,8 +1697,19 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||||
struct page *dirty_page = NULL;
|
struct page *dirty_page = NULL;
|
||||||
|
|
||||||
old_page = vm_normal_page(vma, address, orig_pte);
|
old_page = vm_normal_page(vma, address, orig_pte);
|
||||||
if (!old_page)
|
if (!old_page) {
|
||||||
|
/*
|
||||||
|
* VM_MIXEDMAP !pfn_valid() case
|
||||||
|
*
|
||||||
|
* We should not cow pages in a shared writeable mapping.
|
||||||
|
* Just mark the pages writable as we can't do any dirty
|
||||||
|
* accounting on raw pfn maps.
|
||||||
|
*/
|
||||||
|
if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) ==
|
||||||
|
(VM_WRITE|VM_SHARED))
|
||||||
|
goto reuse;
|
||||||
goto gotten;
|
goto gotten;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Take out anonymous pages first, anonymous shared vmas are
|
* Take out anonymous pages first, anonymous shared vmas are
|
||||||
|
@ -1751,6 +1762,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reuse) {
|
if (reuse) {
|
||||||
|
reuse:
|
||||||
flush_cache_page(vma, address, pte_pfn(orig_pte));
|
flush_cache_page(vma, address, pte_pfn(orig_pte));
|
||||||
entry = pte_mkyoung(orig_pte);
|
entry = pte_mkyoung(orig_pte);
|
||||||
entry = maybe_mkwrite(pte_mkdirty(entry), vma);
|
entry = maybe_mkwrite(pte_mkdirty(entry), vma);
|
||||||
|
|
Loading…
Reference in New Issue