From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757879Ab1KRLim (ORCPT ); Fri, 18 Nov 2011 06:38:42 -0500 Received: from e28smtp04.in.ibm.com ([122.248.162.4]:45078 "EHLO e28smtp04.in.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757835Ab1KRLij (ORCPT ); Fri, 18 Nov 2011 06:38:39 -0500 From: Srikar Dronamraju To: Peter Zijlstra , Linus Torvalds Cc: Oleg Nesterov , Andrew Morton , LKML , Linux-mm , Ingo Molnar , Andi Kleen , Christoph Hellwig , Steven Rostedt , Roland McGrath , Thomas Gleixner , Masami Hiramatsu , Arnaldo Carvalho de Melo , Anton Arapov , Ananth N Mavinakayanahalli , Jim Keniston , Stephen Wilson Date: Fri, 18 Nov 2011 16:42:29 +0530 Message-Id: <20111118111229.10512.51316.sendpatchset@srdronam.in.ibm.com> In-Reply-To: <20111118110631.10512.73274.sendpatchset@srdronam.in.ibm.com> References: <20111118110631.10512.73274.sendpatchset@srdronam.in.ibm.com> Subject: [PATCH v7 3.2-rc2 29/30] uprobes: Introduce uprobe flags x-cbid: 11111811-5564-0000-0000-00000028D6C8 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org While registering a probe, there is a timelag between the time the register request is given all probes are inserted in different processes. If the probe register fails after inserting a probe in couple of processes; the installed probes are reverted. However the probes could have hit and triggered handler before the probes are reverted. Avoids running the handler until the register is complete or as soon as the last unregister kicks in. Also this patch - enables skipping singlestep where possible. - uses a flag to denote if a copy of instruction is made. Signed-off-by: Srikar Dronamraju --- include/linux/uprobes.h | 11 ++++++++++- kernel/uprobes.c | 32 ++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index 6a84332..20bdd0a 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h @@ -46,6 +46,14 @@ struct uprobe_task_arch_info {}; /* arch specific task info */ /* Adjust the return address of a call insn */ #define UPROBES_FIX_CALL 0x2 +/* flags that denote/change uprobes behaviour */ +/* Have a copy of original instruction */ +#define UPROBES_COPY_INSN 0x1 +/* Dont run handlers when first register/ last unregister in progress*/ +#define UPROBES_RUN_HANDLER 0x2 +/* Can skip singlestep */ +#define UPROBES_SKIP_SSTEP 0x4 + struct uprobe_consumer { int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); /* @@ -66,7 +74,7 @@ struct uprobe { struct uprobe_consumer *consumers; struct inode *inode; /* Also hold a ref to inode */ loff_t offset; - int copy; + int flags; u16 fixups; u8 insn[MAX_UINSN_BYTES]; }; @@ -131,6 +139,7 @@ extern int uprobe_post_notifier(struct pt_regs *regs); extern int uprobe_bkpt_notifier(struct pt_regs *regs); extern void uprobe_notify_resume(struct pt_regs *regs); extern bool uprobe_deny_signal(void); +extern bool __weak can_skip_xol(struct pt_regs *regs, struct uprobe *u); #else /* CONFIG_UPROBES is not defined */ static inline int register_uprobe(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) diff --git a/kernel/uprobes.c b/kernel/uprobes.c index f8c0f7c..2493191 100644 --- a/kernel/uprobes.c +++ b/kernel/uprobes.c @@ -436,6 +436,9 @@ static struct uprobe *insert_uprobe(struct uprobe *uprobe) spin_lock_irqsave(&uprobes_treelock, flags); u = __insert_uprobe(uprobe); spin_unlock_irqrestore(&uprobes_treelock, flags); + + /* For now assume that the instruction need not be single-stepped */ + uprobe->flags |= UPROBES_SKIP_SSTEP; return u; } @@ -475,6 +478,9 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs) { struct uprobe_consumer *consumer; + if (!(uprobe->flags & UPROBES_RUN_HANDLER)) + return; + down_read(&uprobe->consumer_rwsem); consumer = uprobe->consumers; for (consumer = uprobe->consumers; consumer; @@ -594,7 +600,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, return -EEXIST; addr = (unsigned long)vaddr; - if (!uprobe->copy) { + if (!(uprobe->flags & UPROBES_COPY_INSN)) { ret = copy_insn(uprobe, vma, addr); if (ret) return ret; @@ -606,7 +612,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, if (ret) return ret; - uprobe->copy = 1; + uprobe->flags |= UPROBES_COPY_INSN; } ret = set_bkpt(mm, uprobe, addr); if (!ret) @@ -850,7 +856,8 @@ int register_uprobe(struct inode *inode, loff_t offset, if (ret) { uprobe->consumers = NULL; __unregister_uprobe(inode, offset, uprobe); - } + } else + uprobe->flags |= UPROBES_RUN_HANDLER; } mutex_unlock(uprobes_hash(inode)); @@ -886,9 +893,10 @@ void unregister_uprobe(struct inode *inode, loff_t offset, goto unreg_out; } - if (!uprobe->consumers) + if (!uprobe->consumers) { __unregister_uprobe(inode, offset, uprobe); - + uprobe->flags &= ~UPROBES_RUN_HANDLER; + } mutex_unlock(uprobes_hash(inode)); unreg_out: @@ -1337,6 +1345,12 @@ bool uprobe_deny_signal(void) return true; } +bool __weak can_skip_xol(struct pt_regs *regs, struct uprobe *u) +{ + u->flags &= ~UPROBES_SKIP_SSTEP; + return false; +} + /* * uprobe_notify_resume gets called in task context just before returning * to userspace. @@ -1378,6 +1392,10 @@ void uprobe_notify_resume(struct pt_regs *regs) } utask->active_uprobe = u; handler_chain(u, regs); + + if (u->flags & UPROBES_SKIP_SSTEP && can_skip_xol(regs, u)) + goto cleanup_ret; + utask->state = UTASK_SSTEP; if (!pre_ssout(u, regs, probept)) user_enable_single_step(current); @@ -1411,8 +1429,10 @@ void uprobe_notify_resume(struct pt_regs *regs) utask->state = UTASK_RUNNING; } if (u) { + if (!(u->flags & UPROBES_SKIP_SSTEP)) + set_instruction_pointer(regs, probept); + put_uprobe(u); - set_instruction_pointer(regs, probept); } else send_sig(SIGTRAP, current, 0); }