vm_normal_page() is never called in this case, since prot_numa is always
zero.
I tracked the bug down. It's a sparc bug. The commit only triggers it,
because affect how GCC optimize the code around faulty point.
Please, test.
From 5b9232753217412116a4cdc2897be0db818371ca Mon Sep 17 00:00:00 2001From: "Kirill A. Shutemov" <kirill.shutemov@xxxxxxxxxxxxxxx>
Date: Thu, 22 Jan 2015 18:42:13 +0200
Subject: [PATCH] sparc32: fix broken set_pte()
32-bit sparc uses swap instruction to implement set_pte(). It called
using GCC inline assembler. But it misses the "memory" clobber to
indicate that pte value will be updated in memory.
As result GCC doesn't know that it cannot postpone pte pointer
dereference which occurs before set_pte() to post-set_pte() time.
It leads to real-world bugs -- [1]. In this situation we have code:
ptent = ptep_modify_prot_start(mm, addr, pte);
ptent = pte_modify(ptent, newprot);
...
ptep_modify_prot_commit(mm, addr, pte, ptent);
ptep_modify_prot_start() in sparc case is just 'pte' dereference plus
pte_clear(). pte_clear() calls broken set_pte(). GCC thinks it's valid
to dereference 'pte' again on pte_modify() and gets cleared pte.
ptep_modify_prot_commit() puts 'pteent' with pfn==0 back to page table,
which eventually leads to the crash.
[1] http://lkml.kernel.org/r/54C06B19.8060305@xxxxxxxxxxxx
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@xxxxxxxxxxxxxxx>
Reported-by: Guenter Roeck <linux@xxxxxxxxxxxx>