Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm/fault, arch: Use pagefault_disable() to check for disabled pagefaults in the handler

Introduce faulthandler_disabled() and use it to check for irq context and
disabled pagefaults (via pagefault_disable()) in the pagefault handlers.

Please note that we keep the in_atomic() checks in place - to detect
whether in irq context (in which case preemption is always properly
disabled).

In contrast, preempt_disable() should never be used to disable pagefaults.
With !CONFIG_PREEMPT_COUNT, preempt_disable() doesn't modify the preempt
counter, and therefore the result of in_atomic() differs.
We validate that condition by using might_fault() checks when calling
might_sleep().

Therefore, add a comment to faulthandler_disabled(), describing why this
is needed.

faulthandler_disabled() and pagefault_disable() are defined in
linux/uaccess.h, so let's properly add that include to all relevant files.

This patch is based on a patch from Thomas Gleixner.

Reviewed-and-tested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: David.Laight@ACULAB.COM
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: airlied@linux.ie
Cc: akpm@linux-foundation.org
Cc: benh@kernel.crashing.org
Cc: bigeasy@linutronix.de
Cc: borntraeger@de.ibm.com
Cc: daniel.vetter@intel.com
Cc: heiko.carstens@de.ibm.com
Cc: herbert@gondor.apana.org.au
Cc: hocko@suse.cz
Cc: hughd@google.com
Cc: mst@redhat.com
Cc: paulus@samba.org
Cc: ralf@linux-mips.org
Cc: schwidefsky@de.ibm.com
Cc: yang.shi@windriver.com
Link: http://lkml.kernel.org/r/1431359540-32227-7-git-send-email-dahi@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

David Hildenbrand and committed by
Ingo Molnar
70ffdb93 ce01948e

+72 -57
+2 -3
arch/alpha/mm/fault.c
··· 23 23 #include <linux/smp.h> 24 24 #include <linux/interrupt.h> 25 25 #include <linux/module.h> 26 - 27 - #include <asm/uaccess.h> 26 + #include <linux/uaccess.h> 28 27 29 28 extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *); 30 29 ··· 106 107 107 108 /* If we're in an interrupt context, or have no user context, 108 109 we must not take the fault. */ 109 - if (!mm || in_atomic()) 110 + if (!mm || faulthandler_disabled()) 110 111 goto no_context; 111 112 112 113 #ifdef CONFIG_ALPHA_LARGE_VMALLOC
+1 -1
arch/arc/mm/fault.c
··· 86 86 * If we're in an interrupt or have no user 87 87 * context, we must not take the fault.. 88 88 */ 89 - if (in_atomic() || !mm) 89 + if (faulthandler_disabled() || !mm) 90 90 goto no_context; 91 91 92 92 if (user_mode(regs))
+1 -1
arch/arm/mm/fault.c
··· 276 276 * If we're in an interrupt or have no user 277 277 * context, we must not take the fault.. 278 278 */ 279 - if (in_atomic() || !mm) 279 + if (faulthandler_disabled() || !mm) 280 280 goto no_context; 281 281 282 282 if (user_mode(regs))
+1 -1
arch/arm64/mm/fault.c
··· 211 211 * If we're in an interrupt or have no user context, we must not take 212 212 * the fault. 213 213 */ 214 - if (in_atomic() || !mm) 214 + if (faulthandler_disabled() || !mm) 215 215 goto no_context; 216 216 217 217 if (user_mode(regs))
+2 -2
arch/avr32/mm/fault.c
··· 14 14 #include <linux/pagemap.h> 15 15 #include <linux/kdebug.h> 16 16 #include <linux/kprobes.h> 17 + #include <linux/uaccess.h> 17 18 18 19 #include <asm/mmu_context.h> 19 20 #include <asm/sysreg.h> 20 21 #include <asm/tlb.h> 21 - #include <asm/uaccess.h> 22 22 23 23 #ifdef CONFIG_KPROBES 24 24 static inline int notify_page_fault(struct pt_regs *regs, int trap) ··· 81 81 * If we're in an interrupt or have no user context, we must 82 82 * not take the fault... 83 83 */ 84 - if (in_atomic() || !mm || regs->sr & SYSREG_BIT(GM)) 84 + if (faulthandler_disabled() || !mm || regs->sr & SYSREG_BIT(GM)) 85 85 goto no_context; 86 86 87 87 local_irq_enable();
+3 -3
arch/cris/mm/fault.c
··· 8 8 #include <linux/interrupt.h> 9 9 #include <linux/module.h> 10 10 #include <linux/wait.h> 11 - #include <asm/uaccess.h> 11 + #include <linux/uaccess.h> 12 12 #include <arch/system.h> 13 13 14 14 extern int find_fixup_code(struct pt_regs *); ··· 109 109 info.si_code = SEGV_MAPERR; 110 110 111 111 /* 112 - * If we're in an interrupt or "atomic" operation or have no 112 + * If we're in an interrupt, have pagefaults disabled or have no 113 113 * user context, we must not take the fault. 114 114 */ 115 115 116 - if (in_atomic() || !mm) 116 + if (faulthandler_disabled() || !mm) 117 117 goto no_context; 118 118 119 119 if (user_mode(regs))
+2 -2
arch/frv/mm/fault.c
··· 19 19 #include <linux/kernel.h> 20 20 #include <linux/ptrace.h> 21 21 #include <linux/hardirq.h> 22 + #include <linux/uaccess.h> 22 23 23 24 #include <asm/pgtable.h> 24 - #include <asm/uaccess.h> 25 25 #include <asm/gdb-stub.h> 26 26 27 27 /*****************************************************************************/ ··· 78 78 * If we're in an interrupt or have no user 79 79 * context, we must not take the fault.. 80 80 */ 81 - if (in_atomic() || !mm) 81 + if (faulthandler_disabled() || !mm) 82 82 goto no_context; 83 83 84 84 if (user_mode(__frame))
+2 -2
arch/ia64/mm/fault.c
··· 11 11 #include <linux/kprobes.h> 12 12 #include <linux/kdebug.h> 13 13 #include <linux/prefetch.h> 14 + #include <linux/uaccess.h> 14 15 15 16 #include <asm/pgtable.h> 16 17 #include <asm/processor.h> 17 - #include <asm/uaccess.h> 18 18 19 19 extern int die(char *, struct pt_regs *, long); 20 20 ··· 96 96 /* 97 97 * If we're in an interrupt or have no user context, we must not take the fault.. 98 98 */ 99 - if (in_atomic() || !mm) 99 + if (faulthandler_disabled() || !mm) 100 100 goto no_context; 101 101 102 102 #ifdef CONFIG_VIRTUAL_MEM_MAP
+4 -4
arch/m32r/mm/fault.c
··· 24 24 #include <linux/vt_kern.h> /* For unblank_screen() */ 25 25 #include <linux/highmem.h> 26 26 #include <linux/module.h> 27 + #include <linux/uaccess.h> 27 28 28 29 #include <asm/m32r.h> 29 - #include <asm/uaccess.h> 30 30 #include <asm/hardirq.h> 31 31 #include <asm/mmu_context.h> 32 32 #include <asm/tlbflush.h> ··· 111 111 mm = tsk->mm; 112 112 113 113 /* 114 - * If we're in an interrupt or have no user context or are running in an 115 - * atomic region then we must not take the fault.. 114 + * If we're in an interrupt or have no user context or have pagefaults 115 + * disabled then we must not take the fault. 116 116 */ 117 - if (in_atomic() || !mm) 117 + if (faulthandler_disabled() || !mm) 118 118 goto bad_area_nosemaphore; 119 119 120 120 if (error_code & ACE_USERMODE)
+2 -2
arch/m68k/mm/fault.c
··· 10 10 #include <linux/ptrace.h> 11 11 #include <linux/interrupt.h> 12 12 #include <linux/module.h> 13 + #include <linux/uaccess.h> 13 14 14 15 #include <asm/setup.h> 15 16 #include <asm/traps.h> 16 - #include <asm/uaccess.h> 17 17 #include <asm/pgalloc.h> 18 18 19 19 extern void die_if_kernel(char *, struct pt_regs *, long); ··· 81 81 * If we're in an interrupt or have no user 82 82 * context, we must not take the fault.. 83 83 */ 84 - if (in_atomic() || !mm) 84 + if (faulthandler_disabled() || !mm) 85 85 goto no_context; 86 86 87 87 if (user_mode(regs))
+1 -1
arch/metag/mm/fault.c
··· 105 105 106 106 mm = tsk->mm; 107 107 108 - if (in_atomic() || !mm) 108 + if (faulthandler_disabled() || !mm) 109 109 goto no_context; 110 110 111 111 if (user_mode(regs))
+4 -4
arch/microblaze/mm/fault.c
··· 107 107 if ((error_code & 0x13) == 0x13 || (error_code & 0x11) == 0x11) 108 108 is_write = 0; 109 109 110 - if (unlikely(in_atomic() || !mm)) { 110 + if (unlikely(faulthandler_disabled() || !mm)) { 111 111 if (kernel_mode(regs)) 112 112 goto bad_area_nosemaphore; 113 113 114 - /* in_atomic() in user mode is really bad, 114 + /* faulthandler_disabled() in user mode is really bad, 115 115 as is current->mm == NULL. */ 116 - pr_emerg("Page fault in user mode with in_atomic(), mm = %p\n", 117 - mm); 116 + pr_emerg("Page fault in user mode with faulthandler_disabled(), mm = %p\n", 117 + mm); 118 118 pr_emerg("r15 = %lx MSR = %lx\n", 119 119 regs->r15, regs->msr); 120 120 die("Weird page fault", regs, SIGSEGV);
+2 -2
arch/mips/mm/fault.c
··· 21 21 #include <linux/module.h> 22 22 #include <linux/kprobes.h> 23 23 #include <linux/perf_event.h> 24 + #include <linux/uaccess.h> 24 25 25 26 #include <asm/branch.h> 26 27 #include <asm/mmu_context.h> 27 - #include <asm/uaccess.h> 28 28 #include <asm/ptrace.h> 29 29 #include <asm/highmem.h> /* For VMALLOC_END */ 30 30 #include <linux/kdebug.h> ··· 94 94 * If we're in an interrupt or have no user 95 95 * context, we must not take the fault.. 96 96 */ 97 - if (in_atomic() || !mm) 97 + if (faulthandler_disabled() || !mm) 98 98 goto bad_area_nosemaphore; 99 99 100 100 if (user_mode(regs))
+2 -2
arch/mn10300/mm/fault.c
··· 23 23 #include <linux/interrupt.h> 24 24 #include <linux/init.h> 25 25 #include <linux/vt_kern.h> /* For unblank_screen() */ 26 + #include <linux/uaccess.h> 26 27 27 - #include <asm/uaccess.h> 28 28 #include <asm/pgalloc.h> 29 29 #include <asm/hardirq.h> 30 30 #include <asm/cpu-regs.h> ··· 168 168 * If we're in an interrupt or have no user 169 169 * context, we must not take the fault.. 170 170 */ 171 - if (in_atomic() || !mm) 171 + if (faulthandler_disabled() || !mm) 172 172 goto no_context; 173 173 174 174 if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR)
+1 -1
arch/nios2/mm/fault.c
··· 77 77 * If we're in an interrupt or have no user 78 78 * context, we must not take the fault.. 79 79 */ 80 - if (in_atomic() || !mm) 80 + if (faulthandler_disabled() || !mm) 81 81 goto bad_area_nosemaphore; 82 82 83 83 if (user_mode(regs))
+2 -2
arch/parisc/kernel/traps.c
··· 26 26 #include <linux/console.h> 27 27 #include <linux/bug.h> 28 28 #include <linux/ratelimit.h> 29 + #include <linux/uaccess.h> 29 30 30 31 #include <asm/assembly.h> 31 - #include <asm/uaccess.h> 32 32 #include <asm/io.h> 33 33 #include <asm/irq.h> 34 34 #include <asm/traps.h> ··· 800 800 * unless pagefault_disable() was called before. 801 801 */ 802 802 803 - if (fault_space == 0 && !in_atomic()) 803 + if (fault_space == 0 && !faulthandler_disabled()) 804 804 { 805 805 pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC); 806 806 parisc_terminate("Kernel Fault", regs, code, fault_address);
+2 -2
arch/parisc/mm/fault.c
··· 15 15 #include <linux/sched.h> 16 16 #include <linux/interrupt.h> 17 17 #include <linux/module.h> 18 + #include <linux/uaccess.h> 18 19 19 - #include <asm/uaccess.h> 20 20 #include <asm/traps.h> 21 21 22 22 /* Various important other fields */ ··· 207 207 int fault; 208 208 unsigned int flags; 209 209 210 - if (in_atomic()) 210 + if (pagefault_disabled()) 211 211 goto no_context; 212 212 213 213 tsk = current;
+5 -4
arch/powerpc/mm/fault.c
··· 33 33 #include <linux/ratelimit.h> 34 34 #include <linux/context_tracking.h> 35 35 #include <linux/hugetlb.h> 36 + #include <linux/uaccess.h> 36 37 37 38 #include <asm/firmware.h> 38 39 #include <asm/page.h> 39 40 #include <asm/pgtable.h> 40 41 #include <asm/mmu.h> 41 42 #include <asm/mmu_context.h> 42 - #include <asm/uaccess.h> 43 43 #include <asm/tlbflush.h> 44 44 #include <asm/siginfo.h> 45 45 #include <asm/debug.h> ··· 272 272 if (!arch_irq_disabled_regs(regs)) 273 273 local_irq_enable(); 274 274 275 - if (in_atomic() || mm == NULL) { 275 + if (faulthandler_disabled() || mm == NULL) { 276 276 if (!user_mode(regs)) { 277 277 rc = SIGSEGV; 278 278 goto bail; 279 279 } 280 - /* in_atomic() in user mode is really bad, 280 + /* faulthandler_disabled() in user mode is really bad, 281 281 as is current->mm == NULL. */ 282 282 printk(KERN_EMERG "Page fault in user mode with " 283 - "in_atomic() = %d mm = %p\n", in_atomic(), mm); 283 + "faulthandler_disabled() = %d mm = %p\n", 284 + faulthandler_disabled(), mm); 284 285 printk(KERN_EMERG "NIP = %lx MSR = %lx\n", 285 286 regs->nip, regs->msr); 286 287 die("Weird page fault", regs, SIGSEGV);
+1 -1
arch/s390/mm/fault.c
··· 399 399 * user context. 400 400 */ 401 401 fault = VM_FAULT_BADCONTEXT; 402 - if (unlikely(!user_space_fault(regs) || in_atomic() || !mm)) 402 + if (unlikely(!user_space_fault(regs) || faulthandler_disabled() || !mm)) 403 403 goto out; 404 404 405 405 address = trans_exc_code & __FAIL_ADDR_MASK;
+2 -1
arch/score/mm/fault.c
··· 34 34 #include <linux/string.h> 35 35 #include <linux/types.h> 36 36 #include <linux/ptrace.h> 37 + #include <linux/uaccess.h> 37 38 38 39 /* 39 40 * This routine handles page faults. It determines the address, ··· 74 73 * If we're in an interrupt or have no user 75 74 * context, we must not take the fault.. 76 75 */ 77 - if (in_atomic() || !mm) 76 + if (pagefault_disabled() || !mm) 78 77 goto bad_area_nosemaphore; 79 78 80 79 if (user_mode(regs))
+3 -2
arch/sh/mm/fault.c
··· 17 17 #include <linux/kprobes.h> 18 18 #include <linux/perf_event.h> 19 19 #include <linux/kdebug.h> 20 + #include <linux/uaccess.h> 20 21 #include <asm/io_trapped.h> 21 22 #include <asm/mmu_context.h> 22 23 #include <asm/tlbflush.h> ··· 439 438 440 439 /* 441 440 * If we're in an interrupt, have no user context or are running 442 - * in an atomic region then we must not take the fault: 441 + * with pagefaults disabled then we must not take the fault: 443 442 */ 444 - if (unlikely(in_atomic() || !mm)) { 443 + if (unlikely(faulthandler_disabled() || !mm)) { 445 444 bad_area_nosemaphore(regs, error_code, address); 446 445 return; 447 446 }
+2 -2
arch/sparc/mm/fault_32.c
··· 21 21 #include <linux/perf_event.h> 22 22 #include <linux/interrupt.h> 23 23 #include <linux/kdebug.h> 24 + #include <linux/uaccess.h> 24 25 25 26 #include <asm/page.h> 26 27 #include <asm/pgtable.h> ··· 30 29 #include <asm/setup.h> 31 30 #include <asm/smp.h> 32 31 #include <asm/traps.h> 33 - #include <asm/uaccess.h> 34 32 35 33 #include "mm_32.h" 36 34 ··· 196 196 * If we're in an interrupt or have no user 197 197 * context, we must not take the fault.. 198 198 */ 199 - if (in_atomic() || !mm) 199 + if (pagefault_disabled() || !mm) 200 200 goto no_context; 201 201 202 202 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
+2 -2
arch/sparc/mm/fault_64.c
··· 22 22 #include <linux/kdebug.h> 23 23 #include <linux/percpu.h> 24 24 #include <linux/context_tracking.h> 25 + #include <linux/uaccess.h> 25 26 26 27 #include <asm/page.h> 27 28 #include <asm/pgtable.h> 28 29 #include <asm/openprom.h> 29 30 #include <asm/oplib.h> 30 - #include <asm/uaccess.h> 31 31 #include <asm/asi.h> 32 32 #include <asm/lsu.h> 33 33 #include <asm/sections.h> ··· 330 330 * If we're in an interrupt or have no user 331 331 * context, we must not take the fault.. 332 332 */ 333 - if (in_atomic() || !mm) 333 + if (faulthandler_disabled() || !mm) 334 334 goto intr_or_no_mm; 335 335 336 336 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
+1 -1
arch/sparc/mm/init_64.c
··· 2706 2706 struct mm_struct *mm = current->mm; 2707 2707 struct tsb_config *tp; 2708 2708 2709 - if (in_atomic() || !mm) { 2709 + if (faulthandler_disabled() || !mm) { 2710 2710 const struct exception_table_entry *entry; 2711 2711 2712 2712 entry = search_exception_tables(regs->tpc);
+2 -2
arch/tile/mm/fault.c
··· 354 354 355 355 /* 356 356 * If we're in an interrupt, have no user context or are running in an 357 - * atomic region then we must not take the fault. 357 + * region with pagefaults disabled then we must not take the fault. 358 358 */ 359 - if (in_atomic() || !mm) { 359 + if (pagefault_disabled() || !mm) { 360 360 vma = NULL; /* happy compiler */ 361 361 goto bad_area_nosemaphore; 362 362 }
+2 -2
arch/um/kernel/trap.c
··· 35 35 *code_out = SEGV_MAPERR; 36 36 37 37 /* 38 - * If the fault was during atomic operation, don't take the fault, just 38 + * If the fault was with pagefaults disabled, don't take the fault, just 39 39 * fail. 40 40 */ 41 - if (in_atomic()) 41 + if (faulthandler_disabled()) 42 42 goto out_nosemaphore; 43 43 44 44 if (is_user)
+1 -1
arch/unicore32/mm/fault.c
··· 218 218 * If we're in an interrupt or have no user 219 219 * context, we must not take the fault.. 220 220 */ 221 - if (in_atomic() || !mm) 221 + if (faulthandler_disabled() || !mm) 222 222 goto no_context; 223 223 224 224 if (user_mode(regs))
+3 -2
arch/x86/mm/fault.c
··· 13 13 #include <linux/hugetlb.h> /* hstate_index_to_shift */ 14 14 #include <linux/prefetch.h> /* prefetchw */ 15 15 #include <linux/context_tracking.h> /* exception_enter(), ... */ 16 + #include <linux/uaccess.h> /* faulthandler_disabled() */ 16 17 17 18 #include <asm/traps.h> /* dotraplinkage, ... */ 18 19 #include <asm/pgalloc.h> /* pgd_*(), ... */ ··· 1127 1126 1128 1127 /* 1129 1128 * If we're in an interrupt, have no user context or are running 1130 - * in an atomic region then we must not take the fault: 1129 + * in a region with pagefaults disabled then we must not take the fault 1131 1130 */ 1132 - if (unlikely(in_atomic() || !mm)) { 1131 + if (unlikely(faulthandler_disabled() || !mm)) { 1133 1132 bad_area_nosemaphore(regs, error_code, address); 1134 1133 return; 1135 1134 }
+2 -2
arch/xtensa/mm/fault.c
··· 15 15 #include <linux/mm.h> 16 16 #include <linux/module.h> 17 17 #include <linux/hardirq.h> 18 + #include <linux/uaccess.h> 18 19 #include <asm/mmu_context.h> 19 20 #include <asm/cacheflush.h> 20 21 #include <asm/hardirq.h> 21 - #include <asm/uaccess.h> 22 22 #include <asm/pgalloc.h> 23 23 24 24 DEFINE_PER_CPU(unsigned long, asid_cache) = ASID_USER_FIRST; ··· 57 57 /* If we're in an interrupt or have no user 58 58 * context, we must not take the fault.. 59 59 */ 60 - if (in_atomic() || !mm) { 60 + if (faulthandler_disabled() || !mm) { 61 61 bad_page_fault(regs, address, SIGSEGV); 62 62 return; 63 63 }
+12
include/linux/uaccess.h
··· 59 59 */ 60 60 #define pagefault_disabled() (current->pagefault_disabled != 0) 61 61 62 + /* 63 + * The pagefault handler is in general disabled by pagefault_disable() or 64 + * when in irq context (via in_atomic()). 65 + * 66 + * This function should only be used by the fault handlers. Other users should 67 + * stick to pagefault_disabled(). 68 + * Please NEVER use preempt_disable() to disable the fault handler. With 69 + * !CONFIG_PREEMPT_COUNT, this is like a NOP. So the handler won't be disabled. 70 + * in_atomic() will report different values based on !CONFIG_PREEMPT_COUNT. 71 + */ 72 + #define faulthandler_disabled() (pagefault_disabled() || in_atomic()) 73 + 62 74 #ifndef ARCH_HAS_NOCACHE_UACCESS 63 75 64 76 static inline unsigned long __copy_from_user_inatomic_nocache(void *to,