[AVR32] optimize pagefault path
Christoph Hellwig [Sat, 12 May 2007 15:56:11 +0000 (17:56 +0200)]
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>

arch/avr32/kernel/kprobes.c
arch/avr32/mm/fault.c
include/asm-avr32/kdebug.h
include/asm-avr32/kprobes.h

index 004c94b..4942ee6 100644 (file)
@@ -179,7 +179,7 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
        return 1;
 }
 
-static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
        struct kprobe *cur = kprobe_running();
 
@@ -216,11 +216,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
                if (post_kprobe_handler(args->regs))
                        ret = NOTIFY_STOP;
                break;
-       case DIE_FAULT:
-               if (kprobe_running()
-                   && kprobe_fault_handler(args->regs, args->trapnr))
-                       ret = NOTIFY_STOP;
-               break;
        default:
                break;
        }
index 88b00b1..e011f1c 100644 (file)
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
-
 #include <linux/kdebug.h>
+#include <linux/kprobes.h>
+
 #include <asm/mmu_context.h>
 #include <asm/sysreg.h>
 #include <asm/tlb.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_KPROBES
-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
-
-/* Hook to register for page fault notifications */
-int register_page_fault_notifier(struct notifier_block *nb)
+static inline int notify_page_fault(struct pt_regs *regs, int trap)
 {
-       return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
-}
+       int ret = 0;
 
-int unregister_page_fault_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
-}
+       if (!user_mode(regs)) {
+               if (kprobe_running() && kprobe_fault_handler(regs, trap))
+                       ret = 1;
+       }
 
-static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
-                                   int trap, int sig)
-{
-       struct die_args args = {
-               .regs = regs,
-               .trapnr = trap,
-       };
-       return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+       return ret;
 }
 #else
-static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
-                                   int trap, int sig)
+static inline int notify_page_fault(struct pt_regs *regs, int trap)
 {
-       return NOTIFY_DONE;
+       return 0;
 }
 #endif
 
@@ -76,8 +65,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
        long signr;
        int code;
 
-       if (notify_page_fault(DIE_PAGE_FAULT, regs,
-                             ecr, SIGSEGV) == NOTIFY_STOP)
+       if (notify_page_fault(regs, ecr))
                return;
 
        address = sysreg_read(TLBEAR);
index de41927..7f54e2b 100644 (file)
@@ -5,13 +5,22 @@
 
 /* Grossly misnamed. */
 enum die_val {
-       DIE_FAULT,
        DIE_BREAKPOINT,
        DIE_SSTEP,
-       DIE_PAGE_FAULT,
 };
 
-int register_page_fault_notifier(struct notifier_block *nb);
-int unregister_page_fault_notifier(struct notifier_block *nb);
+/*
+ * These are only here because kprobes.c wants them to implement a
+ * blatant layering violation.  Will hopefully go away soon once all
+ * architectures are updated.
+ */
+static inline int register_page_fault_notifier(struct notifier_block *nb)
+{
+       return 0;
+}
+static inline int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+       return 0;
+}
 
 #endif /* __ASM_AVR32_KDEBUG_H */
index 09a5cbe..190a637 100644 (file)
@@ -26,6 +26,7 @@ struct arch_specific_insn {
        kprobe_opcode_t insn[MAX_INSN_SIZE];
 };
 
+extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
 extern int kprobe_exceptions_notify(struct notifier_block *self,
                                    unsigned long val, void *data);