diff options
author | Peter Feiner <pfeiner@google.com> | 2014-10-13 18:55:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-13 20:18:28 -0400 |
commit | 64e455079e1bd7787cc47be30b7f601ce682a5f6 (patch) | |
tree | 05193bd91be3ffc0d33ddd3ffb654ef4c23778f9 /mm/memory.c | |
parent | 63a12d9d01831208a47f5c0fbbf93f503d1fb162 (diff) |
mm: softdirty: enable write notifications on VMAs after VM_SOFTDIRTY cleared
For VMAs that don't want write notifications, PTEs created for read faults
have their write bit set. If the read fault happens after VM_SOFTDIRTY is
cleared, then the PTE's softdirty bit will remain clear after subsequent
writes.
Here's a simple code snippet to demonstrate the bug:
char* m = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_SHARED, -1, 0);
system("echo 4 > /proc/$PPID/clear_refs"); /* clear VM_SOFTDIRTY */
assert(*m == '\0'); /* new PTE allows write access */
assert(!soft_dirty(x));
*m = 'x'; /* should dirty the page */
assert(soft_dirty(x)); /* fails */
With this patch, write notifications are enabled when VM_SOFTDIRTY is
cleared. Furthermore, to avoid unnecessary faults, write notifications
are disabled when VM_SOFTDIRTY is set.
As a side effect of enabling and disabling write notifications with
care, this patch fixes a bug in mprotect where vm_page_prot bits set by
drivers were zapped on mprotect. An analogous bug was fixed in mmap by
commit c9d0bf241451 ("mm: uncached vma support with writenotify").
Signed-off-by: Peter Feiner <pfeiner@google.com>
Reported-by: Peter Feiner <pfeiner@google.com>
Suggested-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Cc: Pavel Emelyanov <xemul@parallels.com>
Cc: Jamie Liu <jamieliu@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/memory.c')
-rw-r--r-- | mm/memory.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/mm/memory.c b/mm/memory.c index e229970e4223..1cc6bfbd872e 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -2053,7 +2053,8 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2053 | old_page = vm_normal_page(vma, address, orig_pte); | 2053 | old_page = vm_normal_page(vma, address, orig_pte); |
2054 | if (!old_page) { | 2054 | if (!old_page) { |
2055 | /* | 2055 | /* |
2056 | * VM_MIXEDMAP !pfn_valid() case | 2056 | * VM_MIXEDMAP !pfn_valid() case, or VM_SOFTDIRTY clear on a |
2057 | * VM_PFNMAP VMA. | ||
2057 | * | 2058 | * |
2058 | * We should not cow pages in a shared writeable mapping. | 2059 | * We should not cow pages in a shared writeable mapping. |
2059 | * Just mark the pages writable as we can't do any dirty | 2060 | * Just mark the pages writable as we can't do any dirty |