diff options
| author | Prasanna S. Panchamukhi <prasanna@in.ibm.com> | 2005-01-20 16:00:15 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-01-20 16:00:15 -0800 |
| commit | eab5cc1e76bbb0320488cffe65185c20918a3d4a (patch) | |
| tree | 15ec6f96423c3f16e517f9e7bea25a1aa1a19f66 | |
| parent | 95e5e682f1a4cf716c89c9f9e6c01da898fb1f9c (diff) | |
[PATCH] kprobes: x86_64 memory allocation changes
Minor changes to the kprobes code to provide memory allocation for x86_64
architecture outside kprobes spin lock.
Signed-off-by: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | arch/i386/kernel/kprobes.c | 6 | ||||
| -rw-r--r-- | arch/ppc64/kernel/kprobes.c | 10 | ||||
| -rw-r--r-- | arch/sparc64/kernel/kprobes.c | 6 | ||||
| -rw-r--r-- | arch/x86_64/kernel/kprobes.c | 16 | ||||
| -rw-r--r-- | include/linux/kprobes.h | 1 | ||||
| -rw-r--r-- | kernel/kprobes.c | 13 |
6 files changed, 40 insertions, 12 deletions
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c index 50e3fedc5372..f74b755704c4 100644 --- a/arch/i386/kernel/kprobes.c +++ b/arch/i386/kernel/kprobes.c @@ -62,10 +62,14 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode) 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 --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c index 677f6272fc29..522e7742ac00 100644 --- a/arch/ppc64/kernel/kprobes.c +++ b/arch/ppc64/kernel/kprobes.c @@ -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) { } diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c index 801ab91a739f..7d97138f5d2e 100644 --- a/arch/sparc64/kernel/kprobes.c +++ b/arch/sparc64/kernel/kprobes.c @@ -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 --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c index dfef3128ff63..131d24ef9a63 100644 --- a/arch/x86_64/kernel/kprobes.c +++ b/arch/x86_64/kernel/kprobes.c @@ -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_opcode_t *insn) 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(void) } /* 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 --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 3177a7ffe573..f20c163de4f5 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -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 --git a/kernel/kprobes.c b/kernel/kprobes.c index cc6f72585f1e..4a331aed0866 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -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, |
