aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVineet Gupta <Vineet.Gupta1@synopsys.com>2013-11-02 08:17:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-02 13:27:04 -0400
commit9c41f4eeb9d51f3ece20428d35a3ea32cf3b5622 (patch)
tree18750e6cadeacd1bcb5e7e1b0ccf49ec6b9396de
parent9581b7d2689ad9a0a20ddaec0427b46ad774585b (diff)
ARC: Incorrect mm reference used in vmalloc fault handler
A vmalloc fault needs to sync up PGD/PTE entry from init_mm to current task's "active_mm". ARC vmalloc fault handler however was using mm. A vmalloc fault for non user task context (actually pre-userland, from init thread's open for /dev/console) caused the handler to deref NULL mm (for mm->pgd) The reasons it worked so far is amazing: 1. By default (!SMP), vmalloc fault handler uses a cached value of PGD. In SMP that MMU register is repurposed hence need for mm pointer deref. 2. In pre-3.12 SMP kernel, the problem triggering vmalloc didn't exist in pre-userland code path - it was introduced with commit 20bafb3d23d108bc "n_tty: Move buffers into n_tty_data" Signed-off-by: Vineet Gupta <vgupta@synopsys.com> Cc: Gilad Ben-Yossef <gilad@benyossef.com> Cc: Noam Camus <noamc@ezchip.com> Cc: stable@vger.kernel.org #3.10 and 3.11 Cc: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/arc/mm/fault.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c
index d63f3de0cd5b..0c14d8a52683 100644
--- a/arch/arc/mm/fault.c
+++ b/arch/arc/mm/fault.c
@@ -17,7 +17,7 @@
17#include <asm/pgalloc.h> 17#include <asm/pgalloc.h>
18#include <asm/mmu.h> 18#include <asm/mmu.h>
19 19
20static int handle_vmalloc_fault(struct mm_struct *mm, unsigned long address) 20static int handle_vmalloc_fault(unsigned long address)
21{ 21{
22 /* 22 /*
23 * Synchronize this task's top level page-table 23 * Synchronize this task's top level page-table
@@ -27,7 +27,7 @@ static int handle_vmalloc_fault(struct mm_struct *mm, unsigned long address)
27 pud_t *pud, *pud_k; 27 pud_t *pud, *pud_k;
28 pmd_t *pmd, *pmd_k; 28 pmd_t *pmd, *pmd_k;
29 29
30 pgd = pgd_offset_fast(mm, address); 30 pgd = pgd_offset_fast(current->active_mm, address);
31 pgd_k = pgd_offset_k(address); 31 pgd_k = pgd_offset_k(address);
32 32
33 if (!pgd_present(*pgd_k)) 33 if (!pgd_present(*pgd_k))
@@ -72,7 +72,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address)
72 * nothing more. 72 * nothing more.
73 */ 73 */
74 if (address >= VMALLOC_START && address <= VMALLOC_END) { 74 if (address >= VMALLOC_START && address <= VMALLOC_END) {
75 ret = handle_vmalloc_fault(mm, address); 75 ret = handle_vmalloc_fault(address);
76 if (unlikely(ret)) 76 if (unlikely(ret))
77 goto bad_area_nosemaphore; 77 goto bad_area_nosemaphore;
78 else 78 else