Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74a0b576 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Linus Torvalds
Browse files

x86: optimize page faults like all other achitectures and kill notifier 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: default avatarChristoph 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d5a7430d
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -584,7 +584,7 @@ out:
	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();
@@ -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() &&
+0 −1
Original line number Diff line number Diff line
@@ -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() &&
+19 −24
Original line number Diff line number Diff line
@@ -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/desc.h>
@@ -32,33 +33,27 @@

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;

int unregister_page_fault_notifier(struct notifier_block *nb)
{
	return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
	/* 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();
	}
EXPORT_SYMBOL_GPL(unregister_page_fault_notifier);

static inline int notify_page_fault(struct pt_regs *regs, long err)
	return ret;
}
#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
@@ -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
@@ -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
+19 −25
Original line number Diff line number Diff line
@@ -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>
@@ -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);
	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();
	}
EXPORT_SYMBOL_GPL(register_page_fault_notifier);

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.
@@ -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
@@ -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))
+0 −16
Original line number Diff line number Diff line
#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 */
Loading