[PATCH 3.16 044/346] MIPS: Fix page table corruption on THP permission changes.

From: Ben Hutchings
Date: Sun Nov 13 2016 - 22:55:36 EST


3.16.39-rc1 review patch. If anyone has any objections, please let me know.

------------------

From: David Daney <david.daney@xxxxxxxxxx>

commit acd168c0bf2ce709f056a6b1bf21634b1207d7a5 upstream.

When the core THP code is modifying the permissions of a huge page it
calls pmd_modify(), which unfortunately was clearing the _PAGE_HUGE bit
of the page table entry. The result can be kernel messages like:

mm/memory.c:397: bad pmd 000000040080004d.
mm/memory.c:397: bad pmd 00000003ff00004d.
mm/memory.c:397: bad pmd 000000040100004d.

or:

------------[ cut here ]------------
WARNING: at mm/mmap.c:3200 exit_mmap+0x150/0x158()
Modules linked in: ipv6 at24 octeon3_ethernet octeon_srio_nexus m25p80
CPU: 12 PID: 1295 Comm: pmderr Not tainted 3.10.87-rt80-Cavium-Octeon #4
Stack : 0000000040808000 0000000014009ce1 0000000000400004 ffffffff81076ba0
0000000000000000 0000000000000000 ffffffff85110000 0000000000000119
0000000000000004 0000000000000000 0000000000000119 43617669756d2d4f
0000000000000000 ffffffff850fda40 ffffffff85110000 0000000000000000
0000000000000000 0000000000000009 ffffffff809207a0 0000000000000c80
ffffffff80f1bf20 0000000000000001 000000ffeca36828 0000000000000001
0000000000000000 0000000000000001 000000ffeca7e700 ffffffff80886924
80000003fd7a0000 80000003fd7a39b0 80000003fdea8000 ffffffff80885780
80000003fdea8000 ffffffff80f12218 000000000000000c 000000000000050f
0000000000000000 ffffffff80865c4c 0000000000000000 0000000000000000
...
Call Trace:
[<ffffffff80865c4c>] show_stack+0x6c/0xf8
[<ffffffff80885780>] warn_slowpath_common+0x78/0xa8
[<ffffffff809207a0>] exit_mmap+0x150/0x158
[<ffffffff80882d44>] mmput+0x5c/0x110
[<ffffffff8088b450>] do_exit+0x230/0xa68
[<ffffffff8088be34>] do_group_exit+0x54/0x1d0
[<ffffffff8088bfc0>] __wake_up_parent+0x0/0x18

---[ end trace c7b38293191c57dc ]---
BUG: Bad rss-counter state mm:80000003fa168000 idx:1 val:1536

Fix by not clearing _PAGE_HUGE bit.

Signed-off-by: David Daney <david.daney@xxxxxxxxxx>
Tested-by: Aaro Koskinen <aaro.koskinen@xxxxxxxxx>
Cc: linux-mips@xxxxxxxxxxxxxx
Patchwork: https://patchwork.linux-mips.org/patch/13687/
Signed-off-by: Ralf Baechle <ralf@xxxxxxxxxxxxxx>
[bwh: Backported to 3.16:
- Adjust context
- _PAGE_HUGE might not be defined]
Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
---
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -572,7 +572,11 @@ static inline struct page *pmd_page(pmd_

static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
{
- pmd_val(pmd) = (pmd_val(pmd) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+ pmd_val(pmd) = (pmd_val(pmd) & (_PAGE_CHG_MASK
+#ifdef _PAGE_HUGE
+ | _PAGE_HUGE
+#endif
+ )) | pgprot_val(newprot);
return pmd;
}