Protect the instruction pages list by a specific insn pages mutex, called in get_insn_slot() and free_insn_slot(). It makes sure that architectures that does not need to call arch_remove_kprobe() does not take an unneeded kprobes mutex. Signed-off-by: Mathieu Desnoyers Acked-by: Ananth N Mavinakayanahalli CC: hch@infradead.org CC: anil.s.keshavamurthy@intel.com CC: davem@davemloft.net --- kernel/kprobes.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) Index: linux-2.6-lttng.mm/kernel/kprobes.c =================================================================== --- linux-2.6-lttng.mm.orig/kernel/kprobes.c 2008-04-09 10:28:02.000000000 -0400 +++ linux-2.6-lttng.mm/kernel/kprobes.c 2008-04-09 10:32:34.000000000 -0400 @@ -107,6 +107,10 @@ enum kprobe_slot_state { SLOT_USED = 2, }; +/* + * Protects the kprobe_insn_pages list. Can nest into kprobe_mutex. + */ +static DEFINE_MUTEX(kprobe_insn_mutex); static struct hlist_head kprobe_insn_pages; static int kprobe_garbage_slots; static int collect_garbage_slots(void); @@ -143,7 +147,9 @@ kprobe_opcode_t __kprobes *get_insn_slot { struct kprobe_insn_page *kip; struct hlist_node *pos; + kprobe_opcode_t *ret; + mutex_lock(&kprobe_insn_mutex); retry: hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) { if (kip->nused < INSNS_PER_PAGE) { @@ -152,7 +158,8 @@ kprobe_opcode_t __kprobes *get_insn_slot if (kip->slot_used[i] == SLOT_CLEAN) { kip->slot_used[i] = SLOT_USED; kip->nused++; - return kip->insns + (i * MAX_INSN_SIZE); + ret = kip->insns + (i * MAX_INSN_SIZE); + goto end; } } /* Surprise! No unused slots. Fix kip->nused. */ @@ -166,8 +173,10 @@ kprobe_opcode_t __kprobes *get_insn_slot } /* All out of space. Need to allocate a new page. Use slot 0. */ kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL); - if (!kip) - return NULL; + if (!kip) { + ret = NULL; + goto end; + } /* * Use module_alloc so this page is within +/- 2GB of where the @@ -177,7 +186,8 @@ kprobe_opcode_t __kprobes *get_insn_slot kip->insns = module_alloc(PAGE_SIZE); if (!kip->insns) { kfree(kip); - return NULL; + ret = NULL; + goto end; } INIT_HLIST_NODE(&kip->hlist); hlist_add_head(&kip->hlist, &kprobe_insn_pages); @@ -185,7 +195,10 @@ kprobe_opcode_t __kprobes *get_insn_slot kip->slot_used[0] = SLOT_USED; kip->nused = 1; kip->ngarbage = 0; - return kip->insns; + ret = kip->insns; +end: + mutex_unlock(&kprobe_insn_mutex); + return ret; } /* Return 1 if all garbages are collected, otherwise 0. */ @@ -219,7 +232,7 @@ static int __kprobes collect_garbage_slo struct kprobe_insn_page *kip; struct hlist_node *pos, *next; - /* Ensure no-one is preepmted on the garbages */ + /* Ensure no-one is preempted on the garbages */ if (check_safety() != 0) return -EAGAIN; @@ -243,6 +256,7 @@ void __kprobes free_insn_slot(kprobe_opc struct kprobe_insn_page *kip; struct hlist_node *pos; + mutex_lock(&kprobe_insn_mutex); hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) { if (kip->insns <= slot && slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) { @@ -259,6 +273,7 @@ void __kprobes free_insn_slot(kprobe_opc if (dirty && ++kprobe_garbage_slots > INSNS_PER_PAGE) collect_garbage_slots(); + mutex_unlock(&kprobe_insn_mutex); } #endif -- Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/