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/kernel/kprobes.c =================================================================== --- linux-2.6-lttng.orig/kernel/kprobes.c 2007-08-27 11:48:56.000000000 -0400 +++ linux-2.6-lttng/kernel/kprobes.c 2007-08-27 11:48:58.000000000 -0400 @@ -95,6 +95,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); @@ -131,7 +135,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) { @@ -140,7 +146,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. */ @@ -154,8 +161,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 @@ -165,7 +174,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); @@ -173,7 +183,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. */ @@ -207,7 +220,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; @@ -231,6 +244,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)) { @@ -247,6 +261,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/