[AVR32] optimize pagefault path

Avoid the costly notifier list in the pagefault path and call
the kprobes code directly. The same change went into the 2.6.22
cycle for powerpc, 2s390 and sparc64 already.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

authored by Christoph Hellwig and committed by Haavard Skinnemoen 9caebec7 5d1938c8

+27 -34
+1 -6
arch/avr32/kernel/kprobes.c
··· 179 179 return 1; 180 180 } 181 181 182 - static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) 182 + int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) 183 183 { 184 184 struct kprobe *cur = kprobe_running(); 185 185 ··· 214 214 break; 215 215 case DIE_SSTEP: 216 216 if (post_kprobe_handler(args->regs)) 217 - ret = NOTIFY_STOP; 218 - break; 219 - case DIE_FAULT: 220 - if (kprobe_running() 221 - && kprobe_fault_handler(args->regs, args->trapnr)) 222 217 ret = NOTIFY_STOP; 223 218 break; 224 219 default:
+12 -24
arch/avr32/mm/fault.c
··· 12 12 #include <linux/mm.h> 13 13 #include <linux/module.h> 14 14 #include <linux/pagemap.h> 15 - 16 15 #include <linux/kdebug.h> 16 + #include <linux/kprobes.h> 17 + 17 18 #include <asm/mmu_context.h> 18 19 #include <asm/sysreg.h> 19 20 #include <asm/tlb.h> 20 21 #include <asm/uaccess.h> 21 22 22 23 #ifdef CONFIG_KPROBES 23 - ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); 24 - 25 - /* Hook to register for page fault notifications */ 26 - int register_page_fault_notifier(struct notifier_block *nb) 24 + static inline int notify_page_fault(struct pt_regs *regs, int trap) 27 25 { 28 - return atomic_notifier_chain_register(&notify_page_fault_chain, nb); 29 - } 26 + int ret = 0; 30 27 31 - int unregister_page_fault_notifier(struct notifier_block *nb) 32 - { 33 - return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb); 34 - } 28 + if (!user_mode(regs)) { 29 + if (kprobe_running() && kprobe_fault_handler(regs, trap)) 30 + ret = 1; 31 + } 35 32 36 - static inline int notify_page_fault(enum die_val val, struct pt_regs *regs, 37 - int trap, int sig) 38 - { 39 - struct die_args args = { 40 - .regs = regs, 41 - .trapnr = trap, 42 - }; 43 - return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args); 33 + return ret; 44 34 } 45 35 #else 46 - static inline int notify_page_fault(enum die_val val, struct pt_regs *regs, 47 - int trap, int sig) 36 + static inline int notify_page_fault(struct pt_regs *regs, int trap) 48 37 { 49 - return NOTIFY_DONE; 38 + return 0; 50 39 } 51 40 #endif 52 41 ··· 65 76 long signr; 66 77 int code; 67 78 68 - if (notify_page_fault(DIE_PAGE_FAULT, regs, 69 - ecr, SIGSEGV) == NOTIFY_STOP) 79 + if (notify_page_fault(regs, ecr)) 70 80 return; 71 81 72 82 address = sysreg_read(TLBEAR);
+13 -4
include/asm-avr32/kdebug.h
··· 5 5 6 6 /* Grossly misnamed. */ 7 7 enum die_val { 8 - DIE_FAULT, 9 8 DIE_BREAKPOINT, 10 9 DIE_SSTEP, 11 - DIE_PAGE_FAULT, 12 10 }; 13 11 14 - int register_page_fault_notifier(struct notifier_block *nb); 15 - int unregister_page_fault_notifier(struct notifier_block *nb); 12 + /* 13 + * These are only here because kprobes.c wants them to implement a 14 + * blatant layering violation. Will hopefully go away soon once all 15 + * architectures are updated. 16 + */ 17 + static inline int register_page_fault_notifier(struct notifier_block *nb) 18 + { 19 + return 0; 20 + } 21 + static inline int unregister_page_fault_notifier(struct notifier_block *nb) 22 + { 23 + return 0; 24 + } 16 25 17 26 #endif /* __ASM_AVR32_KDEBUG_H */
+1
include/asm-avr32/kprobes.h
··· 26 26 kprobe_opcode_t insn[MAX_INSN_SIZE]; 27 27 }; 28 28 29 + extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); 29 30 extern int kprobe_exceptions_notify(struct notifier_block *self, 30 31 unsigned long val, void *data); 31 32