Commit 87e6d49a000fa6148bd539f632706b02c3485c5d
Committed by
Linus Torvalds
1 parent
5760a97c71
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
mm: softdirty: addresses before VMAs in PTE holes aren't softdirty
In PTE holes that contain VM_SOFTDIRTY VMAs, unmapped addresses before VM_SOFTDIRTY VMAs are reported as softdirty by /proc/pid/pagemap. This bug was introduced in commit 68b5a6524856 ("mm: softdirty: respect VM_SOFTDIRTY in PTE holes"). That commit made /proc/pid/pagemap look at VM_SOFTDIRTY in PTE holes but neglected to observe the start of VMAs returned by find_vma. Tested: Wrote a selftest that creates a PMD-sized VMA then unmaps the first page and asserts that the page is not softdirty. I'm going to send the pagemap selftest in a later commit. Signed-off-by: Peter Feiner <pfeiner@google.com> Cc: Cyrill Gorcunov <gorcunov@openvz.org> Cc: Pavel Emelyanov <xemul@parallels.com> Cc: Hugh Dickins <hughd@google.com> Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Cc: "Kirill A. Shutemov" <kirill@shutemov.name> Cc: Jamie Liu <jamieliu@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 18 additions and 9 deletions Side-by-side Diff
fs/proc/task_mmu.c
... | ... | @@ -931,23 +931,32 @@ |
931 | 931 | while (addr < end) { |
932 | 932 | struct vm_area_struct *vma = find_vma(walk->mm, addr); |
933 | 933 | pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2)); |
934 | - unsigned long vm_end; | |
934 | + /* End of address space hole, which we mark as non-present. */ | |
935 | + unsigned long hole_end; | |
935 | 936 | |
936 | - if (!vma) { | |
937 | - vm_end = end; | |
938 | - } else { | |
939 | - vm_end = min(end, vma->vm_end); | |
940 | - if (vma->vm_flags & VM_SOFTDIRTY) | |
941 | - pme.pme |= PM_STATUS2(pm->v2, __PM_SOFT_DIRTY); | |
937 | + if (vma) | |
938 | + hole_end = min(end, vma->vm_start); | |
939 | + else | |
940 | + hole_end = end; | |
941 | + | |
942 | + for (; addr < hole_end; addr += PAGE_SIZE) { | |
943 | + err = add_to_pagemap(addr, &pme, pm); | |
944 | + if (err) | |
945 | + goto out; | |
942 | 946 | } |
943 | 947 | |
944 | - for (; addr < vm_end; addr += PAGE_SIZE) { | |
948 | + if (!vma) | |
949 | + break; | |
950 | + | |
951 | + /* Addresses in the VMA. */ | |
952 | + if (vma->vm_flags & VM_SOFTDIRTY) | |
953 | + pme.pme |= PM_STATUS2(pm->v2, __PM_SOFT_DIRTY); | |
954 | + for (; addr < min(end, vma->vm_end); addr += PAGE_SIZE) { | |
945 | 955 | err = add_to_pagemap(addr, &pme, pm); |
946 | 956 | if (err) |
947 | 957 | goto out; |
948 | 958 | } |
949 | 959 | } |
950 | - | |
951 | 960 | out: |
952 | 961 | return err; |
953 | 962 | } |