Hi, This patch moves the memory allocation required by kprobes outside spin lock as suggested by Andi Kleen. Please let me know your comments.
Thanks Prasanna Minor changes to the kprobes code to provide memory allocation for x86_64 architecture outside kprobes spin lock. Signed-off-by: Prasanna S Panchamukhi <[EMAIL PROTECTED]> --- --- linux-2.6.11-rc1-prasanna/arch/i386/kernel/kprobes.c | 6 +++++- linux-2.6.11-rc1-prasanna/arch/ppc64/kernel/kprobes.c | 10 ++++++++-- linux-2.6.11-rc1-prasanna/arch/sparc64/kernel/kprobes.c | 6 +++++- linux-2.6.11-rc1-prasanna/arch/x86_64/kernel/kprobes.c | 16 +++++++++++++--- linux-2.6.11-rc1-prasanna/include/linux/kprobes.h | 1 + linux-2.6.11-rc1-prasanna/kernel/kprobes.c | 13 ++++++++----- 6 files changed, 40 insertions(+), 12 deletions(-) diff -puN arch/i386/kernel/kprobes.c~kprobes-x86_64-changes arch/i386/kernel/kprobes.c --- linux-2.6.11-rc1/arch/i386/kernel/kprobes.c~kprobes-x86_64-changes 2005-01-19 19:46:23.000000000 +0530 +++ linux-2.6.11-rc1-prasanna/arch/i386/kernel/kprobes.c 2005-01-19 19:46:23.000000000 +0530 @@ -61,10 +61,14 @@ static inline int is_IF_modifier(kprobe_ int arch_prepare_kprobe(struct kprobe *p) { - memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); return 0; } +void arch_copy_kprobe(struct kprobe *p) +{ + memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); +} + void arch_remove_kprobe(struct kprobe *p) { } diff -puN arch/sparc64/kernel/kprobes.c~kprobes-x86_64-changes arch/sparc64/kernel/kprobes.c --- linux-2.6.11-rc1/arch/sparc64/kernel/kprobes.c~kprobes-x86_64-changes 2005-01-19 19:46:23.000000000 +0530 +++ linux-2.6.11-rc1-prasanna/arch/sparc64/kernel/kprobes.c 2005-01-19 19:46:23.000000000 +0530 @@ -40,9 +40,13 @@ int arch_prepare_kprobe(struct kprobe *p) { + return 0; +} + +void arch_copy_kprobe(struct kprobe *p) +{ p->ainsn.insn[0] = *p->addr; p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2; - return 0; } void arch_remove_kprobe(struct kprobe *p) diff -puN arch/x86_64/kernel/kprobes.c~kprobes-x86_64-changes arch/x86_64/kernel/kprobes.c --- linux-2.6.11-rc1/arch/x86_64/kernel/kprobes.c~kprobes-x86_64-changes 2005-01-19 19:46:23.000000000 +0530 +++ linux-2.6.11-rc1-prasanna/arch/x86_64/kernel/kprobes.c 2005-01-19 19:46:23.000000000 +0530 @@ -39,6 +39,8 @@ #include <asm/pgtable.h> #include <asm/kdebug.h> +static DECLARE_MUTEX(kprobe_mutex); + /* kprobe_status settings */ #define KPROBE_HIT_ACTIVE 0x00000001 #define KPROBE_HIT_SS 0x00000002 @@ -75,17 +77,25 @@ static inline int is_IF_modifier(kprobe_ int arch_prepare_kprobe(struct kprobe *p) { /* insn: must be on special executable page on x86_64. */ + up(&kprobe_mutex); p->ainsn.insn = get_insn_slot(); + down(&kprobe_mutex); if (!p->ainsn.insn) { return -ENOMEM; } - memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE); return 0; } +void arch_copy_kprobe(struct kprobe *p) +{ + memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE); +} + void arch_remove_kprobe(struct kprobe *p) { + up(&kprobe_mutex); free_insn_slot(p->ainsn.insn); + down(&kprobe_mutex); } static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) @@ -425,12 +435,12 @@ static kprobe_opcode_t *get_insn_slot(vo } /* All out of space. Need to allocate a new page. Use slot 0.*/ - kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_ATOMIC); + kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL); if (!kip) { return NULL; } kip->insns = (kprobe_opcode_t*) __vmalloc(PAGE_SIZE, - GFP_ATOMIC|__GFP_HIGHMEM, __pgprot(__PAGE_KERNEL_EXEC)); + GFP_KERNEL|__GFP_HIGHMEM, __pgprot(__PAGE_KERNEL_EXEC)); if (!kip->insns) { kfree(kip); return NULL; diff -puN include/linux/kprobes.h~kprobes-x86_64-changes include/linux/kprobes.h --- linux-2.6.11-rc1/include/linux/kprobes.h~kprobes-x86_64-changes 2005-01-19 19:46:23.000000000 +0530 +++ linux-2.6.11-rc1-prasanna/include/linux/kprobes.h 2005-01-19 19:46:23.000000000 +0530 @@ -95,6 +95,7 @@ static inline int kprobe_running(void) } extern int arch_prepare_kprobe(struct kprobe *p); +extern void arch_copy_kprobe(struct kprobe *p); extern void arch_remove_kprobe(struct kprobe *p); extern void show_registers(struct pt_regs *regs); diff -puN kernel/kprobes.c~kprobes-x86_64-changes kernel/kprobes.c --- linux-2.6.11-rc1/kernel/kprobes.c~kprobes-x86_64-changes 2005-01-19 19:46:23.000000000 +0530 +++ linux-2.6.11-rc1-prasanna/kernel/kprobes.c 2005-01-19 19:46:23.000000000 +0530 @@ -76,18 +76,19 @@ struct kprobe *get_kprobe(void *addr) int register_kprobe(struct kprobe *p) { int ret = 0; - unsigned long flags; + unsigned long flags = 0; + if ((ret = arch_prepare_kprobe(p)) != 0) { + goto out; + } spin_lock_irqsave(&kprobe_lock, flags); INIT_HLIST_NODE(&p->hlist); if (get_kprobe(p->addr)) { ret = -EEXIST; goto out; } + arch_copy_kprobe(p); - if ((ret = arch_prepare_kprobe(p)) != 0) { - goto out; - } hlist_add_head(&p->hlist, &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]); @@ -97,14 +98,16 @@ int register_kprobe(struct kprobe *p) (unsigned long) p->addr + sizeof(kprobe_opcode_t)); out: spin_unlock_irqrestore(&kprobe_lock, flags); + if (ret == -EEXIST) + arch_remove_kprobe(p); return ret; } void unregister_kprobe(struct kprobe *p) { unsigned long flags; - spin_lock_irqsave(&kprobe_lock, flags); arch_remove_kprobe(p); + spin_lock_irqsave(&kprobe_lock, flags); *p->addr = p->opcode; hlist_del(&p->hlist); flush_icache_range((unsigned long) p->addr, diff -puN arch/ppc64/kernel/kprobes.c~kprobes-x86_64-changes arch/ppc64/kernel/kprobes.c --- linux-2.6.11-rc1/arch/ppc64/kernel/kprobes.c~kprobes-x86_64-changes 2005-01-19 19:52:36.000000000 +0530 +++ linux-2.6.11-rc1-prasanna/arch/ppc64/kernel/kprobes.c 2005-01-19 19:52:49.000000000 +0530 @@ -45,13 +45,19 @@ static struct pt_regs jprobe_saved_regs; int arch_prepare_kprobe(struct kprobe *p) { - memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); - if (IS_MTMSRD(p->ainsn.insn[0]) || IS_RFID(p->ainsn.insn[0])) + kprobe_opcode_t insn = *p->addr; + + if (IS_MTMSRD(insn) || IS_RFID(insn)) /* cannot put bp on RFID/MTMSRD */ return 1; return 0; } +void arch_copy_kprobe(struct kprobe *p) +{ + memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); +} + void arch_remove_kprobe(struct kprobe *p) { } _ -- Prasanna S Panchamukhi Linux Technology Center India Software Labs, IBM Bangalore Ph: 91-80-25044636 <[EMAIL PROTECTED]> - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/