Skip to content

Commit

Permalink
x86: optimize page faults like all other achitectures and kill notifi…
Browse files Browse the repository at this point in the history
…er cruft

x86(-64) are the last architectures still using the page fault notifier
cruft for the kprobes page fault hook.  This patch converts them to the
proper direct calls, and removes the now unused pagefault notifier bits
aswell as the cruft in kprobes.c that was related to this mess.

I know Andi didn't really like this, but all other architecture maintainers
agreed the direct calls are much better and besides the obvious cruft
removal a common way of dealing with kprobes across architectures is
important aswell.

[akpm@linux-foundation.org: build fix]
[akpm@linux-foundation.org: fix sparc64]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: Andi Kleen <ak@suse.de>
Cc: <linux-arch@vger.kernel.org>
Cc: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Christoph Hellwig authored and Linus Torvalds committed Oct 16, 2007
1 parent d5a7430 commit 74a0b57
Show file tree
Hide file tree
Showing 20 changed files with 44 additions and 192 deletions.
3 changes: 1 addition & 2 deletions arch/x86/kernel/kprobes_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,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();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
Expand Down Expand Up @@ -666,7 +666,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
ret = NOTIFY_STOP;
break;
case DIE_GPF:
case DIE_PAGE_FAULT:
/* kprobe_running() needs smp_processor_id() */
preempt_disable();
if (kprobe_running() &&
Expand Down
1 change: 0 additions & 1 deletion arch/x86/kernel/kprobes_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
ret = NOTIFY_STOP;
break;
case DIE_GPF:
case DIE_PAGE_FAULT:
/* kprobe_running() needs smp_processor_id() */
preempt_disable();
if (kprobe_running() &&
Expand Down
43 changes: 19 additions & 24 deletions arch/x86/mm/fault_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,40 +25,35 @@
#include <linux/kprobes.h>
#include <linux/uaccess.h>
#include <linux/kdebug.h>
#include <linux/kprobes.h>

#include <asm/system.h>
#include <asm/desc.h>
#include <asm/segment.h>

extern void die(const char *,struct pt_regs *,long);

static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);

int register_page_fault_notifier(struct notifier_block *nb)
#ifdef CONFIG_KPROBES
static inline int notify_page_fault(struct pt_regs *regs)
{
vmalloc_sync_all();
return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
}
EXPORT_SYMBOL_GPL(register_page_fault_notifier);
int ret = 0;

/* kprobe_running() needs smp_processor_id() */
if (!user_mode_vm(regs)) {
preempt_disable();
if (kprobe_running() && kprobe_fault_handler(regs, 14))
ret = 1;
preempt_enable();
}

int unregister_page_fault_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
return ret;
}
EXPORT_SYMBOL_GPL(unregister_page_fault_notifier);

static inline int notify_page_fault(struct pt_regs *regs, long err)
#else
static inline int notify_page_fault(struct pt_regs *regs)
{
struct die_args args = {
.regs = regs,
.str = "page fault",
.err = err,
.trapnr = 14,
.signr = SIGSEGV
};
return atomic_notifier_call_chain(&notify_page_fault_chain,
DIE_PAGE_FAULT, &args);
return 0;
}
#endif

/*
* Return EIP plus the CS segment base. The segment limit is also
Expand Down Expand Up @@ -331,7 +326,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs,
if (unlikely(address >= TASK_SIZE)) {
if (!(error_code & 0x0000000d) && vmalloc_fault(address) >= 0)
return;
if (notify_page_fault(regs, error_code) == NOTIFY_STOP)
if (notify_page_fault(regs))
return;
/*
* Don't take the mm semaphore here. If we fixup a prefetch
Expand All @@ -340,7 +335,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs,
goto bad_area_nosemaphore;
}

if (notify_page_fault(regs, error_code) == NOTIFY_STOP)
if (notify_page_fault(regs))
return;

/* It's safe to allow irq's after cr2 has been saved and the vmalloc
Expand Down
44 changes: 19 additions & 25 deletions arch/x86/mm/fault_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/kprobes.h>
#include <linux/uaccess.h>
#include <linux/kdebug.h>
#include <linux/kprobes.h>

#include <asm/system.h>
#include <asm/pgalloc.h>
Expand All @@ -40,34 +41,27 @@
#define PF_RSVD (1<<3)
#define PF_INSTR (1<<4)

static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);

/* Hook to register for page fault notifications */
int register_page_fault_notifier(struct notifier_block *nb)
#ifdef CONFIG_KPROBES
static inline int notify_page_fault(struct pt_regs *regs)
{
vmalloc_sync_all();
return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
}
EXPORT_SYMBOL_GPL(register_page_fault_notifier);
int ret = 0;

/* kprobe_running() needs smp_processor_id() */
if (!user_mode(regs)) {
preempt_disable();
if (kprobe_running() && kprobe_fault_handler(regs, 14))
ret = 1;
preempt_enable();
}

int unregister_page_fault_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
return ret;
}
EXPORT_SYMBOL_GPL(unregister_page_fault_notifier);

static inline int notify_page_fault(struct pt_regs *regs, long err)
#else
static inline int notify_page_fault(struct pt_regs *regs)
{
struct die_args args = {
.regs = regs,
.str = "page fault",
.err = err,
.trapnr = 14,
.signr = SIGSEGV
};
return atomic_notifier_call_chain(&notify_page_fault_chain,
DIE_PAGE_FAULT, &args);
return 0;
}
#endif

/* Sometimes the CPU reports invalid exceptions on prefetch.
Check that here and ignore.
Expand Down Expand Up @@ -345,7 +339,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
if (vmalloc_fault(address) >= 0)
return;
}
if (notify_page_fault(regs, error_code) == NOTIFY_STOP)
if (notify_page_fault(regs))
return;
/*
* Don't take the mm semaphore here. If we fixup a prefetch
Expand All @@ -354,7 +348,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
goto bad_area_nosemaphore;
}

if (notify_page_fault(regs, error_code) == NOTIFY_STOP)
if (notify_page_fault(regs))
return;

if (likely(regs->eflags & X86_EFLAGS_IF))
Expand Down
16 changes: 0 additions & 16 deletions include/asm-avr32/kdebug.h
Original file line number Diff line number Diff line change
@@ -1,26 +1,10 @@
#ifndef __ASM_AVR32_KDEBUG_H
#define __ASM_AVR32_KDEBUG_H

#include <linux/notifier.h>

/* Grossly misnamed. */
enum die_val {
DIE_BREAKPOINT,
DIE_SSTEP,
};

/*
* 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 */
2 changes: 0 additions & 2 deletions include/asm-avr32/kprobes.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ typedef u16 kprobe_opcode_t;
#define BREAKPOINT_INSTRUCTION 0xd673 /* breakpoint */
#define MAX_INSN_SIZE 2

#define ARCH_INACTIVE_KPROBE_COUNT 1

#define arch_remove_kprobe(p) do { } while (0)

/* Architecture specific copy of original instruction */
Expand Down
15 changes: 0 additions & 15 deletions include/asm-ia64/kdebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,6 @@
* 2005-Oct Keith Owens <kaos@sgi.com>. Expand notify_die to cover more
* events.
*/
#include <linux/notifier.h>

/*
* 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;
}

enum die_val {
DIE_BREAK = 1,
Expand Down
1 change: 0 additions & 1 deletion include/asm-ia64/kprobes.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ struct kprobe_ctlblk {
};

#define ARCH_SUPPORTS_KRETPROBES
#define ARCH_INACTIVE_KPROBE_COUNT 1

#define SLOT0_OPCODE_SHIFT (37)
#define SLOT1_p1_OPCODE_SHIFT (37 - (64-46))
Expand Down
19 changes: 0 additions & 19 deletions include/asm-powerpc/kdebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,6 @@
#define _ASM_POWERPC_KDEBUG_H
#ifdef __KERNEL__

/* nearly identical to x86_64/i386 code */

#include <linux/notifier.h>

/*
* 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;
}
extern struct atomic_notifier_head powerpc_die_chain;

/* Grossly misnamed. */
enum die_val {
DIE_OOPS = 1,
Expand Down
1 change: 0 additions & 1 deletion include/asm-powerpc/kprobes.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ typedef unsigned int kprobe_opcode_t;
#endif

#define ARCH_SUPPORTS_KRETPROBES
#define ARCH_INACTIVE_KPROBE_COUNT 1
#define flush_insn_slot(p) do { } while (0)

void kretprobe_trampoline(void);
Expand Down
15 changes: 0 additions & 15 deletions include/asm-s390/kdebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,9 @@
/*
* Feb 2006 Ported to s390 <grundym@us.ibm.com>
*/
#include <linux/notifier.h>

struct pt_regs;

/*
* 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;
}

enum die_val {
DIE_OOPS = 1,
DIE_BPT,
Expand Down
1 change: 0 additions & 1 deletion include/asm-s390/kprobes.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ typedef u16 kprobe_opcode_t;
: (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))

#define ARCH_SUPPORTS_KRETPROBES
#define ARCH_INACTIVE_KPROBE_COUNT 0

#define KPROBE_SWAP_INST 0x10

Expand Down
2 changes: 0 additions & 2 deletions include/asm-sh/kdebug.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef __ASM_SH_KDEBUG_H
#define __ASM_SH_KDEBUG_H

#include <linux/notifier.h>

/* Grossly misnamed. */
enum die_val {
DIE_TRAP,
Expand Down
18 changes: 0 additions & 18 deletions include/asm-sparc64/kdebug.h
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
#ifndef _SPARC64_KDEBUG_H
#define _SPARC64_KDEBUG_H

/* Nearly identical to x86_64/i386 code. */

#include <linux/notifier.h>

struct pt_regs;

/*
* 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;
}

extern void bad_trap(struct pt_regs *, long);

/* Grossly misnamed. */
Expand Down
1 change: 0 additions & 1 deletion include/asm-sparc64/kprobes.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ typedef u32 kprobe_opcode_t;
#define MAX_INSN_SIZE 2

#define arch_remove_kprobe(p) do {} while (0)
#define ARCH_INACTIVE_KPROBE_COUNT 0

#define flush_insn_slot(p) \
do { flushi(&(p)->ainsn.insn[0]); \
Expand Down
6 changes: 0 additions & 6 deletions include/asm-x86/kdebug_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@
* Aug-05 2004 Ported by Prasanna S Panchamukhi <prasanna@in.ibm.com>
* from x86_64 architecture.
*/
#include <linux/notifier.h>

struct pt_regs;

extern int register_page_fault_notifier(struct notifier_block *);
extern int unregister_page_fault_notifier(struct notifier_block *);


/* Grossly misnamed. */
enum die_val {
DIE_OOPS = 1,
Expand All @@ -27,7 +22,6 @@ enum die_val {
DIE_GPF,
DIE_CALL,
DIE_NMI_IPI,
DIE_PAGE_FAULT,
};

#endif
Loading

0 comments on commit 74a0b57

Please sign in to comment.