From: Greg Kroah-Hartman Date: Sun, 26 Apr 2015 11:47:12 +0000 (+0200) Subject: 3.14-stable patches X-Git-Tag: v4.0.1~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=72323a9cca8c55c120d17be508635e6e7f158747;p=thirdparty%2Fkernel%2Fstable-queue.git 3.14-stable patches added patches: mm-softdirty-unmapped-addresses-between-vmas-are-clean.patch proc-pagemap-walk-page-tables-under-pte-lock.patch --- diff --git a/queue-3.14/mm-softdirty-unmapped-addresses-between-vmas-are-clean.patch b/queue-3.14/mm-softdirty-unmapped-addresses-between-vmas-are-clean.patch new file mode 100644 index 00000000000..ea4e46436f6 --- /dev/null +++ b/queue-3.14/mm-softdirty-unmapped-addresses-between-vmas-are-clean.patch @@ -0,0 +1,139 @@ +From 81d0fa623c5b8dbd5279d9713094b0f9b0a00fb4 Mon Sep 17 00:00:00 2001 +From: Peter Feiner +Date: Thu, 9 Oct 2014 15:28:32 -0700 +Subject: mm: softdirty: unmapped addresses between VMAs are clean + +From: Peter Feiner + +commit 81d0fa623c5b8dbd5279d9713094b0f9b0a00fb4 upstream. + +If a /proc/pid/pagemap read spans a [VMA, an unmapped region, then a +VM_SOFTDIRTY VMA], the virtual pages in the unmapped region are reported +as softdirty. Here's a program to demonstrate the bug: + +int main() { + const uint64_t PAGEMAP_SOFTDIRTY = 1ul << 55; + uint64_t pme[3]; + int fd = open("/proc/self/pagemap", O_RDONLY);; + char *m = mmap(NULL, 3 * getpagesize(), PROT_READ, + MAP_ANONYMOUS | MAP_SHARED, -1, 0); + munmap(m + getpagesize(), getpagesize()); + pread(fd, pme, 24, (unsigned long) m / getpagesize() * 8); + assert(pme[0] & PAGEMAP_SOFTDIRTY); /* passes */ + assert(!(pme[1] & PAGEMAP_SOFTDIRTY)); /* fails */ + assert(pme[2] & PAGEMAP_SOFTDIRTY); /* passes */ + return 0; +} + +(Note that all pages in new VMAs are softdirty until cleared). + +Tested: + Used the program given above. I'm going to include this code in + a selftest in the future. + +[n-horiguchi@ah.jp.nec.com: prevent pagemap_pte_range() from overrunning] +Signed-off-by: Peter Feiner +Cc: "Kirill A. Shutemov" +Cc: Cyrill Gorcunov +Cc: Pavel Emelyanov +Cc: Jamie Liu +Cc: Hugh Dickins +Cc: Naoya Horiguchi +Signed-off-by: Naoya Horiguchi +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/proc/task_mmu.c | 59 +++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 39 insertions(+), 20 deletions(-) + +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -995,7 +995,6 @@ static int pagemap_pte_range(pmd_t *pmd, + spinlock_t *ptl; + pte_t *pte; + int err = 0; +- pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2)); + + /* find the first VMA at or above 'addr' */ + vma = find_vma(walk->mm, addr); +@@ -1009,6 +1008,7 @@ static int pagemap_pte_range(pmd_t *pmd, + + for (; addr != end; addr += PAGE_SIZE) { + unsigned long offset; ++ pagemap_entry_t pme; + + offset = (addr & ~PAGEMAP_WALK_MASK) >> + PAGE_SHIFT; +@@ -1023,32 +1023,51 @@ static int pagemap_pte_range(pmd_t *pmd, + + if (pmd_trans_unstable(pmd)) + return 0; +- for (; addr != end; addr += PAGE_SIZE) { +- int flags2; + +- /* check to see if we've left 'vma' behind +- * and need a new, higher one */ +- if (vma && (addr >= vma->vm_end)) { +- vma = find_vma(walk->mm, addr); +- if (vma && (vma->vm_flags & VM_SOFTDIRTY)) +- flags2 = __PM_SOFT_DIRTY; +- else +- flags2 = 0; +- pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, flags2)); ++ while (1) { ++ /* End of address space hole, which we mark as non-present. */ ++ unsigned long hole_end; ++ ++ if (vma) ++ hole_end = min(end, vma->vm_start); ++ else ++ hole_end = end; ++ ++ for (; addr < hole_end; addr += PAGE_SIZE) { ++ pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2)); ++ ++ err = add_to_pagemap(addr, &pme, pm); ++ if (err) ++ return err; + } + +- /* check that 'vma' actually covers this address, +- * and that it isn't a huge page vma */ +- if (vma && (vma->vm_start <= addr) && +- !is_vm_hugetlb_page(vma)) { ++ if (!vma || vma->vm_start >= end) ++ break; ++ /* ++ * We can't possibly be in a hugetlb VMA. In general, ++ * for a mm_walk with a pmd_entry and a hugetlb_entry, ++ * the pmd_entry can only be called on addresses in a ++ * hugetlb if the walk starts in a non-hugetlb VMA and ++ * spans a hugepage VMA. Since pagemap_read walks are ++ * PMD-sized and PMD-aligned, this will never be true. ++ */ ++ BUG_ON(is_vm_hugetlb_page(vma)); ++ ++ /* Addresses in the VMA. */ ++ for (; addr < min(end, vma->vm_end); addr += PAGE_SIZE) { ++ pagemap_entry_t pme; + pte = pte_offset_map(pmd, addr); + pte_to_pagemap_entry(&pme, pm, vma, addr, *pte); +- /* unmap before userspace copy */ + pte_unmap(pte); ++ err = add_to_pagemap(addr, &pme, pm); ++ if (err) ++ return err; + } +- err = add_to_pagemap(addr, &pme, pm); +- if (err) +- return err; ++ ++ if (addr == end) ++ break; ++ ++ vma = find_vma(walk->mm, addr); + } + + cond_resched(); diff --git a/queue-3.14/proc-pagemap-walk-page-tables-under-pte-lock.patch b/queue-3.14/proc-pagemap-walk-page-tables-under-pte-lock.patch new file mode 100644 index 00000000000..c53401393a0 --- /dev/null +++ b/queue-3.14/proc-pagemap-walk-page-tables-under-pte-lock.patch @@ -0,0 +1,78 @@ +From 05fbf357d94152171bc50f8a369390f1f16efd89 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Wed, 11 Feb 2015 15:27:31 -0800 +Subject: proc/pagemap: walk page tables under pte lock + +From: Konstantin Khlebnikov + +commit 05fbf357d94152171bc50f8a369390f1f16efd89 upstream. + +Lockless access to pte in pagemap_pte_range() might race with page +migration and trigger BUG_ON(!PageLocked()) in migration_entry_to_page(): + +CPU A (pagemap) CPU B (migration) + lock_page() + try_to_unmap(page, TTU_MIGRATION...) + make_migration_entry() + set_pte_at() + +pte_to_pagemap_entry() + remove_migration_ptes() + unlock_page() + if(is_migration_entry()) + migration_entry_to_page() + BUG_ON(!PageLocked(page)) + +Also lockless read might be non-atomic if pte is larger than wordsize. +Other pte walkers (smaps, numa_maps, clear_refs) already lock ptes. + +Fixes: 052fb0d635df ("proc: report file/anon bit in /proc/pid/pagemap") +Signed-off-by: Konstantin Khlebnikov +Reported-by: Andrey Ryabinin +Reviewed-by: Cyrill Gorcunov +Acked-by: Naoya Horiguchi +Acked-by: Kirill A. Shutemov +Cc: [3.5+] +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/proc/task_mmu.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -993,7 +993,7 @@ static int pagemap_pte_range(pmd_t *pmd, + struct vm_area_struct *vma; + struct pagemapread *pm = walk->private; + spinlock_t *ptl; +- pte_t *pte; ++ pte_t *pte, *orig_pte; + int err = 0; + + /* find the first VMA at or above 'addr' */ +@@ -1054,15 +1054,19 @@ static int pagemap_pte_range(pmd_t *pmd, + BUG_ON(is_vm_hugetlb_page(vma)); + + /* Addresses in the VMA. */ +- for (; addr < min(end, vma->vm_end); addr += PAGE_SIZE) { ++ orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); ++ for (; addr < min(end, vma->vm_end); pte++, addr += PAGE_SIZE) { + pagemap_entry_t pme; +- pte = pte_offset_map(pmd, addr); ++ + pte_to_pagemap_entry(&pme, pm, vma, addr, *pte); +- pte_unmap(pte); + err = add_to_pagemap(addr, &pme, pm); + if (err) +- return err; ++ break; + } ++ pte_unmap_unlock(orig_pte, ptl); ++ ++ if (err) ++ return err; + + if (addr == end) + break; diff --git a/queue-3.14/series b/queue-3.14/series index b9427979653..c6c4f2dd85d 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -38,3 +38,5 @@ arm-8108-1-mm-introduce-pte-pmd-_isset-and-pte-pmd-_isclear.patch arm-8109-1-mm-modify-pte_write-and-pmd_write-logic-for-lpae.patch x86-mm-move-mmap_sem-unlock-from-mm_fault_error-to-caller.patch sb_edac-avoid-internal-error-message-in-edac-with-unspecified-channel.patch +mm-softdirty-unmapped-addresses-between-vmas-are-clean.patch +proc-pagemap-walk-page-tables-under-pte-lock.patch