LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Martin Schwidefsky <schwidefsky@de.ibm.com>
To: linux-kernel@vger.kernel.org, linux-s390@vger.kernel.org
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>,
Heiko Carstens <heiko.carstens@de.ibm.com>
Subject: [patch 20/38] Minor fault path optimization.
Date: Fri, 27 Apr 2007 16:05:23 +0200 [thread overview]
Message-ID: <20070427140516.523272684@de.ibm.com> (raw)
In-Reply-To: <20070427140503.087958775@de.ibm.com>
[-- Attachment #1: 123-minor-fault.diff --]
[-- Type: text/plain, Size: 10626 bytes --]
From: Martin Schwidefsky <schwidefsky@de.ibm.com>
The minor fault path has grown a lot in terms of cycles. In particular
the kprobes hook is very costly. Optimize the path to save a couple of
cycles. If kprobes is enabled more than 300 cycles can be avoided if
kprobes_running() is false.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
---
arch/s390/mm/fault.c | 259 +++++++++++++++++++++++++++------------------------
1 files changed, 141 insertions(+), 118 deletions(-)
Index: quilt-2.6/arch/s390/mm/fault.c
===================================================================
--- quilt-2.6.orig/arch/s390/mm/fault.c 2007-04-27 16:01:49.000000000 +0200
+++ quilt-2.6/arch/s390/mm/fault.c 2007-04-27 16:04:57.000000000 +0200
@@ -63,21 +63,25 @@
return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb);
}
-static inline int notify_page_fault(enum die_val val, const char *str,
- struct pt_regs *regs, long err, int trap, int sig)
+static int __kprobes __notify_page_fault(struct pt_regs *regs, long err)
{
- struct die_args args = {
- .regs = regs,
- .str = str,
- .err = err,
- .trapnr = trap,
- .signr = sig
- };
- return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args);
+ struct die_args args = { .str = "page fault",
+ .trapnr = 14,
+ .signr = SIGSEGV };
+ args.regs = regs;
+ args.err = err;
+ return atomic_notifier_call_chain(¬ify_page_fault_chain,
+ DIE_PAGE_FAULT, &args);
+}
+
+static inline int notify_page_fault(struct pt_regs *regs, long err)
+{
+ if (unlikely(kprobe_running()))
+ return __notify_page_fault(regs, err);
+ return NOTIFY_DONE;
}
#else
-static inline int notify_page_fault(enum die_val val, const char *str,
- struct pt_regs *regs, long err, int trap, int sig)
+static inline int notify_page_fault(struct pt_regs *regs, long err)
{
return NOTIFY_DONE;
}
@@ -170,6 +174,89 @@
force_sig_info(SIGSEGV, &si, current);
}
+static void do_no_context(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+{
+ const struct exception_table_entry *fixup;
+
+ /* Are we prepared to handle this kernel fault? */
+ fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK);
+ if (fixup) {
+ regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+ return;
+ }
+
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ if (check_space(current) == 0)
+ printk(KERN_ALERT "Unable to handle kernel pointer dereference"
+ " at virtual kernel address %p\n", (void *)address);
+ else
+ printk(KERN_ALERT "Unable to handle kernel paging request"
+ " at virtual user address %p\n", (void *)address);
+
+ die("Oops", regs, error_code);
+ do_exit(SIGKILL);
+}
+
+static void do_low_address(struct pt_regs *regs, unsigned long error_code)
+{
+ /* Low-address protection hit in kernel mode means
+ NULL pointer write access in kernel mode. */
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ /* Low-address protection hit in user mode 'cannot happen'. */
+ die ("Low-address protection", regs, error_code);
+ do_exit(SIGKILL);
+ }
+
+ do_no_context(regs, error_code, 0);
+}
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+static int do_out_of_memory(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+{
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
+
+ up_read(&mm->mmap_sem);
+ if (is_init(tsk)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ return 1;
+ }
+ printk("VM: killing process %s\n", tsk->comm);
+ if (regs->psw.mask & PSW_MASK_PSTATE)
+ do_exit(SIGKILL);
+ do_no_context(regs, error_code, address);
+ return 0;
+}
+
+static void do_sigbus(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+{
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
+
+ up_read(&mm->mmap_sem);
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ tsk->thread.prot_addr = address;
+ tsk->thread.trap_no = error_code;
+ force_sig(SIGBUS, tsk);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!(regs->psw.mask & PSW_MASK_PSTATE))
+ do_no_context(regs, error_code, address);
+}
+
#ifdef CONFIG_S390_EXEC_PROTECT
extern long sys_sigreturn(struct pt_regs *regs);
extern long sys_rt_sigreturn(struct pt_regs *regs);
@@ -253,49 +340,23 @@
* 3b Region third trans. -> Not present (nullification)
*/
static inline void
-do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
+do_exception(struct pt_regs *regs, unsigned long error_code, int write)
{
- struct task_struct *tsk;
- struct mm_struct *mm;
- struct vm_area_struct * vma;
- unsigned long address;
- const struct exception_table_entry *fixup;
- int si_code;
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ unsigned long address;
int space;
+ int si_code;
- tsk = current;
- mm = tsk->mm;
-
- if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
- SIGSEGV) == NOTIFY_STOP)
+ if (notify_page_fault(regs, error_code) == NOTIFY_STOP)
return;
- /*
- * Check for low-address protection. This needs to be treated
- * as a special case because the translation exception code
- * field is not guaranteed to contain valid data in this case.
- */
- if (is_protection && !(S390_lowcore.trans_exc_code & 4)) {
-
- /* Low-address protection hit in kernel mode means
- NULL pointer write access in kernel mode. */
- if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
- address = 0;
- space = 0;
- goto no_context;
- }
-
- /* Low-address protection hit in user mode 'cannot happen'. */
- die ("Low-address protection", regs, error_code);
- do_exit(SIGKILL);
- }
+ tsk = current;
+ mm = tsk->mm;
- /*
- * get the failing address
- * more specific the segment and page table portion of
- * the address
- */
- address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
+ /* get the failing address and the affected space */
+ address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
space = check_space(tsk);
/*
@@ -313,7 +374,7 @@
*/
local_irq_enable();
- down_read(&mm->mmap_sem);
+ down_read(&mm->mmap_sem);
si_code = SEGV_MAPERR;
vma = find_vma(mm, address);
@@ -330,19 +391,19 @@
return;
#endif
- if (vma->vm_start <= address)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if (expand_stack(vma, address))
- goto bad_area;
+ if (vma->vm_start <= address)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (expand_stack(vma, address))
+ goto bad_area;
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
good_area:
si_code = SEGV_ACCERR;
- if (!is_protection) {
+ if (!write) {
/* page not present, check vm flags */
if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
goto bad_area;
@@ -357,7 +418,7 @@
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- switch (handle_mm_fault(mm, vma, address, is_protection)) {
+ switch (handle_mm_fault(mm, vma, address, write)) {
case VM_FAULT_MINOR:
tsk->min_flt++;
break;
@@ -365,9 +426,12 @@
tsk->maj_flt++;
break;
case VM_FAULT_SIGBUS:
- goto do_sigbus;
+ do_sigbus(regs, error_code, address);
+ return;
case VM_FAULT_OOM:
- goto out_of_memory;
+ if (do_out_of_memory(regs, error_code, address))
+ goto survive;
+ return;
default:
BUG();
}
@@ -385,75 +449,34 @@
* Fix it, but check if it's kernel or user first..
*/
bad_area:
- up_read(&mm->mmap_sem);
+ up_read(&mm->mmap_sem);
- /* User mode accesses just cause a SIGSEGV */
- if (regs->psw.mask & PSW_MASK_PSTATE) {
- tsk->thread.prot_addr = address;
- tsk->thread.trap_no = error_code;
+ /* User mode accesses just cause a SIGSEGV */
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ tsk->thread.prot_addr = address;
+ tsk->thread.trap_no = error_code;
do_sigsegv(regs, error_code, si_code, address);
- return;
+ return;
}
no_context:
- /* Are we prepared to handle this kernel fault? */
- fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK);
- if (fixup) {
- regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
- return;
- }
-
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
- if (space == 0)
- printk(KERN_ALERT "Unable to handle kernel pointer dereference"
- " at virtual kernel address %p\n", (void *)address);
- else
- printk(KERN_ALERT "Unable to handle kernel paging request"
- " at virtual user address %p\n", (void *)address);
-
- die("Oops", regs, error_code);
- do_exit(SIGKILL);
-
-
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
-*/
-out_of_memory:
- up_read(&mm->mmap_sem);
- if (is_init(tsk)) {
- yield();
- down_read(&mm->mmap_sem);
- goto survive;
- }
- printk("VM: killing process %s\n", tsk->comm);
- if (regs->psw.mask & PSW_MASK_PSTATE)
- do_exit(SIGKILL);
- goto no_context;
-
-do_sigbus:
- up_read(&mm->mmap_sem);
-
- /*
- * Send a sigbus, regardless of whether we were in kernel
- * or user mode.
- */
- tsk->thread.prot_addr = address;
- tsk->thread.trap_no = error_code;
- force_sig(SIGBUS, tsk);
-
- /* Kernel mode? Handle exceptions or die */
- if (!(regs->psw.mask & PSW_MASK_PSTATE))
- goto no_context;
+ do_no_context(regs, error_code, address);
}
void __kprobes do_protection_exception(struct pt_regs *regs,
unsigned long error_code)
{
+ /* Protection exception is supressing, decrement psw address. */
regs->psw.addr -= (error_code >> 16);
+ /*
+ * Check for low-address protection. This needs to be treated
+ * as a special case because the translation exception code
+ * field is not guaranteed to contain valid data in this case.
+ */
+ if (unlikely(!(S390_lowcore.trans_exc_code & 4))) {
+ do_low_address(regs, error_code);
+ return;
+ }
do_exception(regs, 4, 1);
}
--
blue skies,
Martin.
"Reality continues to ruin my life." - Calvin.
next prev parent reply other threads:[~2007-04-27 14:14 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-27 14:05 [patch 00/38] s390 patches for 2.6.22 Martin Schwidefsky
2007-04-27 14:05 ` [patch 01/38] memory detection: stop at first memory hole Martin Schwidefsky
2007-04-27 14:05 ` [patch 02/38] cio/ipl: Clean interface between cio and ipl code Martin Schwidefsky
2007-04-27 14:05 ` [patch 03/38] cio: Introduce struct chp_id Martin Schwidefsky
2007-04-27 14:05 ` [patch 04/38] cio: Allow 0 and 1 as input for channel path status attribute Martin Schwidefsky
2007-04-27 14:05 ` [patch 05/38] cio: Introduce separate files for channel-path related code Martin Schwidefsky
2007-04-27 14:05 ` [patch 06/38] cio: observe chpid valid flag Martin Schwidefsky
2007-04-27 14:05 ` [patch 07/38] cio: Clean up online_store Martin Schwidefsky
2007-04-27 14:05 ` [patch 08/38] cio: Channel-path configure function Martin Schwidefsky
2007-04-27 14:05 ` [patch 09/38] cio: Use add_uevent_var Martin Schwidefsky
2007-04-27 14:05 ` [patch 10/38] cio: Re-start path verification after aborting internal I/O Martin Schwidefsky
2007-04-27 14:05 ` [patch 11/38] cio: replace subchannel evaluation queue with bitmap Martin Schwidefsky
2007-04-27 14:05 ` [patch 12/38] cio: fix subchannel channel-path data usage Martin Schwidefsky
2007-04-27 14:05 ` [patch 13/38] cio: Dont call css_update_ssd_info from interrupt context Martin Schwidefsky
2007-04-27 14:05 ` [patch 14/38] cio: ccwgroup register vs. unregister Martin Schwidefsky
2007-04-27 14:05 ` [patch 15/38] cio: cm_enable memory leak Martin Schwidefsky
2007-04-27 14:05 ` [patch 16/38] cio: Unregister ccw devices directly Martin Schwidefsky
2007-04-27 14:05 ` [patch 17/38] System call cleanup Martin Schwidefsky
2007-04-27 14:05 ` [patch 18/38] Improved oops output Martin Schwidefsky
2007-04-27 14:25 ` Christoph Hellwig
2007-04-27 15:24 ` Martin Schwidefsky
2007-04-27 16:01 ` Chuck Ebbert
2007-04-27 16:15 ` Martin Schwidefsky
2007-04-27 16:21 ` Chuck Ebbert
2007-04-27 18:14 ` Andi Kleen
2007-04-27 20:56 ` Martin Schwidefsky
2007-04-27 21:10 ` Chuck Ebbert
2007-04-27 14:05 ` [patch 19/38] Use generic bug Martin Schwidefsky
2007-04-27 14:05 ` Martin Schwidefsky [this message]
2007-04-28 4:49 ` [patch 20/38] Minor fault path optimization Paul Mackerras
2007-04-28 8:34 ` Christoph Hellwig
2007-04-30 0:57 ` Paul Mackerras
2007-04-30 10:56 ` [PATCH] powerpc: minor " Christoph Hellwig
2007-05-02 10:45 ` [patch 20/38] Minor " Martin Schwidefsky
2007-05-02 10:49 ` Christoph Hellwig
2007-04-27 14:05 ` [patch 21/38] No execute support cleanup Martin Schwidefsky
2007-04-27 14:05 ` [patch 22/38] Get rid of console setup functions Martin Schwidefsky
2007-04-27 14:05 ` [patch 23/38] Improved kernel stack overflow checking Martin Schwidefsky
2007-04-27 14:05 ` [patch 24/38] dasd: Add sysfs attribute status and generate uevents Martin Schwidefsky
2007-04-27 14:05 ` [patch 25/38] dasd: Add ipldev parameter Martin Schwidefsky
2007-04-27 14:05 ` [patch 26/38] zfcpdump support Martin Schwidefsky
2007-04-27 14:05 ` [patch 27/38] ctc: kmalloc->kzalloc/casting cleanups Martin Schwidefsky
2007-04-27 14:05 ` [patch 28/38] sclp: initialize early Martin Schwidefsky
2007-04-27 14:05 ` [patch 29/38] vmlogrdr: stop IUCV connection in vmlogrdr_release Martin Schwidefsky
2007-04-27 14:05 ` [patch 30/38] sclp: fix coding style Martin Schwidefsky
2007-04-27 14:05 ` [patch 31/38] crypto: cleanup Martin Schwidefsky
2007-04-27 14:05 ` [patch 32/38] vtime: cleanup per_cpu usage Martin Schwidefsky
2007-04-27 14:05 ` [patch 33/38] Processor degradation notification Martin Schwidefsky
2007-04-27 14:05 ` [patch 34/38] split page_test_and_clear_dirty Martin Schwidefsky
2007-04-27 14:05 ` [patch 35/38] Switch etr from tasklet to workqueue Martin Schwidefsky
2007-04-27 14:05 ` [patch 36/38] Remove debugging junk Martin Schwidefsky
2007-04-27 14:05 ` [patch 37/38] Clean up smp code in preparation for some larger changes Martin Schwidefsky
2007-04-27 14:05 ` [patch 38/38] SPIN_LOCK_UNLOCKED cleanup in drivers/s390 Martin Schwidefsky
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070427140516.523272684@de.ibm.com \
--to=schwidefsky@de.ibm.com \
--cc=heiko.carstens@de.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--subject='Re: [patch 20/38] Minor fault path optimization.' \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).