[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>
This commit is contained in:
parent
5d1938c83c
commit
9caebec7b8
|
@ -179,7 +179,7 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
|
||||||
return 1;
|
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();
|
struct kprobe *cur = kprobe_running();
|
||||||
|
|
||||||
|
@ -216,11 +216,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
|
||||||
if (post_kprobe_handler(args->regs))
|
if (post_kprobe_handler(args->regs))
|
||||||
ret = NOTIFY_STOP;
|
ret = NOTIFY_STOP;
|
||||||
break;
|
break;
|
||||||
case DIE_FAULT:
|
|
||||||
if (kprobe_running()
|
|
||||||
&& kprobe_fault_handler(args->regs, args->trapnr))
|
|
||||||
ret = NOTIFY_STOP;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,41 +12,30 @@
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
|
|
||||||
#include <linux/kdebug.h>
|
#include <linux/kdebug.h>
|
||||||
|
#include <linux/kprobes.h>
|
||||||
|
|
||||||
#include <asm/mmu_context.h>
|
#include <asm/mmu_context.h>
|
||||||
#include <asm/sysreg.h>
|
#include <asm/sysreg.h>
|
||||||
#include <asm/tlb.h>
|
#include <asm/tlb.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
#ifdef CONFIG_KPROBES
|
#ifdef CONFIG_KPROBES
|
||||||
ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
|
static inline int notify_page_fault(struct pt_regs *regs, int trap)
|
||||||
|
|
||||||
/* Hook to register for page fault notifications */
|
|
||||||
int register_page_fault_notifier(struct notifier_block *nb)
|
|
||||||
{
|
{
|
||||||
return atomic_notifier_chain_register(¬ify_page_fault_chain, nb);
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!user_mode(regs)) {
|
||||||
|
if (kprobe_running() && kprobe_fault_handler(regs, trap))
|
||||||
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unregister_page_fault_notifier(struct notifier_block *nb)
|
return ret;
|
||||||
{
|
|
||||||
return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb);
|
|
||||||
}
|
|
||||||
|
|
||||||
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(¬ify_page_fault_chain, val, &args);
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
|
static inline int notify_page_fault(struct pt_regs *regs, int trap)
|
||||||
int trap, int sig)
|
|
||||||
{
|
{
|
||||||
return NOTIFY_DONE;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -76,8 +65,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
|
||||||
long signr;
|
long signr;
|
||||||
int code;
|
int code;
|
||||||
|
|
||||||
if (notify_page_fault(DIE_PAGE_FAULT, regs,
|
if (notify_page_fault(regs, ecr))
|
||||||
ecr, SIGSEGV) == NOTIFY_STOP)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
address = sysreg_read(TLBEAR);
|
address = sysreg_read(TLBEAR);
|
||||||
|
|
|
@ -5,13 +5,22 @@
|
||||||
|
|
||||||
/* Grossly misnamed. */
|
/* Grossly misnamed. */
|
||||||
enum die_val {
|
enum die_val {
|
||||||
DIE_FAULT,
|
|
||||||
DIE_BREAKPOINT,
|
DIE_BREAKPOINT,
|
||||||
DIE_SSTEP,
|
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 */
|
#endif /* __ASM_AVR32_KDEBUG_H */
|
||||||
|
|
|
@ -26,6 +26,7 @@ struct arch_specific_insn {
|
||||||
kprobe_opcode_t insn[MAX_INSN_SIZE];
|
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,
|
extern int kprobe_exceptions_notify(struct notifier_block *self,
|
||||||
unsigned long val, void *data);
|
unsigned long val, void *data);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue