From a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Wed, 22 Nov 2006 08:25:00 -0600 Subject: [IA64] fix possible XPC deadlock when disconnecting This patch eliminates a potential deadlock that is possible when XPC disconnects a channel to a partition that has gone down. This deadlock will occur if at least one of the kthreads created by XPC for the purpose of making callouts to the channel's registerer is detained in the registerer and will not be returning back to XPC until some registerer request occurs on the now downed partition. The potential for a deadlock is removed by ensuring that there always is a kthread available to make the channel disconnecting callout to the registerer. Signed-off-by: Dean Nelson Signed-off-by: Tony Luck --- include/asm-ia64/sn/xpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-ia64/sn/xpc.h b/include/asm-ia64/sn/xpc.h index 1d45e1518fb3..e52b8508083b 100644 --- a/include/asm-ia64/sn/xpc.h +++ b/include/asm-ia64/sn/xpc.h @@ -673,7 +673,7 @@ extern irqreturn_t xpc_notify_IRQ_handler(int, void *); extern void xpc_dropped_IPI_check(struct xpc_partition *); extern void xpc_activate_partition(struct xpc_partition *); extern void xpc_activate_kthreads(struct xpc_channel *, int); -extern void xpc_create_kthreads(struct xpc_channel *, int); +extern void xpc_create_kthreads(struct xpc_channel *, int, int); extern void xpc_disconnect_wait(int); -- cgit v1.2.3-59-g8ed1b From 08ed38b68099f2a492196414b08a7f5dd8dc3537 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Tue, 14 Nov 2006 09:33:38 -0800 Subject: [IA64] enable trap code on slot 1 Because slot 1 of one instr bundle crosses border of two consecutive 8-bytes, kprobe on slot 1 is disabled. This patch enables kprobe on slot1, it only replaces higher 8-bytes of the instruction bundle and changes the exception code to ignore the low 12 bits of the break number (which is across the border in the lower 8-bytes of the bundle). For those instructions which must execute regardless qp bits, kprobe on slot 1 is still disabled. Signed-off-by: bibo,mao Signed-off-by: Tony Luck --- arch/ia64/kernel/jprobes.S | 3 ++- arch/ia64/kernel/kprobes.c | 51 +++++++++++++++++++++++++++++++++------------- include/asm-ia64/break.h | 4 ++-- include/asm-ia64/kprobes.h | 1 + 4 files changed, 42 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/arch/ia64/kernel/jprobes.S b/arch/ia64/kernel/jprobes.S index 5cd6226f44f2..621630256c4a 100644 --- a/arch/ia64/kernel/jprobes.S +++ b/arch/ia64/kernel/jprobes.S @@ -45,13 +45,14 @@ * to the correct location. */ #include +#include /* * void jprobe_break(void) */ .section .kprobes.text, "ax" ENTRY(jprobe_break) - break.m 0x80300 + break.m __IA64_BREAK_JPROBE END(jprobe_break) /* diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 76e778951e20..8406d24d516b 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c @@ -88,6 +88,7 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot, { p->ainsn.inst_flag = 0; p->ainsn.target_br_reg = 0; + p->ainsn.slot = slot; /* Check for Break instruction * Bits 37:40 Major opcode to be zero @@ -296,12 +297,6 @@ static int __kprobes valid_kprobe_addr(int template, int slot, return -EINVAL; } - if (slot == 1 && bundle_encoding[template][1] != L) { - printk(KERN_WARNING "Inserting kprobes on slot #1 " - "is not supported\n"); - return -EINVAL; - } - return 0; } @@ -458,23 +453,49 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) void __kprobes arch_arm_kprobe(struct kprobe *p) { - unsigned long addr = (unsigned long)p->addr; - unsigned long arm_addr = addr & ~0xFULL; + unsigned long arm_addr; + bundle_t *src, *dest; + + arm_addr = ((unsigned long)p->addr) & ~0xFUL; + dest = &((kprobe_opcode_t *)arm_addr)->bundle; + src = &p->opcode.bundle; flush_icache_range((unsigned long)p->ainsn.insn, (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t)); - memcpy((char *)arm_addr, &p->opcode, sizeof(kprobe_opcode_t)); + switch (p->ainsn.slot) { + case 0: + dest->quad0.slot0 = src->quad0.slot0; + break; + case 1: + dest->quad1.slot1_p1 = src->quad1.slot1_p1; + break; + case 2: + dest->quad1.slot2 = src->quad1.slot2; + break; + } flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); } void __kprobes arch_disarm_kprobe(struct kprobe *p) { - unsigned long addr = (unsigned long)p->addr; - unsigned long arm_addr = addr & ~0xFULL; + unsigned long arm_addr; + bundle_t *src, *dest; + arm_addr = ((unsigned long)p->addr) & ~0xFUL; + dest = &((kprobe_opcode_t *)arm_addr)->bundle; /* p->ainsn.insn contains the original unaltered kprobe_opcode_t */ - memcpy((char *) arm_addr, (char *) p->ainsn.insn, - sizeof(kprobe_opcode_t)); + src = &p->ainsn.insn->bundle; + switch (p->ainsn.slot) { + case 0: + dest->quad0.slot0 = src->quad0.slot0; + break; + case 1: + dest->quad1.slot1_p1 = src->quad1.slot1_p1; + break; + case 2: + dest->quad1.slot2 = src->quad1.slot2; + break; + } flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); } @@ -807,7 +828,9 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, switch(val) { case DIE_BREAK: /* err is break number from ia64_bad_break() */ - if (args->err == 0x80200 || args->err == 0x80300 || args->err == 0) + if ((args->err >> 12) == (__IA64_BREAK_KPROBE >> 12) + || args->err == __IA64_BREAK_JPROBE + || args->err == 0) if (pre_kprobes_handler(args)) ret = NOTIFY_STOP; break; diff --git a/include/asm-ia64/break.h b/include/asm-ia64/break.h index 8167828edc4b..f03402039896 100644 --- a/include/asm-ia64/break.h +++ b/include/asm-ia64/break.h @@ -12,8 +12,8 @@ * OS-specific debug break numbers: */ #define __IA64_BREAK_KDB 0x80100 -#define __IA64_BREAK_KPROBE 0x80200 -#define __IA64_BREAK_JPROBE 0x80300 +#define __IA64_BREAK_KPROBE 0x81000 /* .. 0x81fff */ +#define __IA64_BREAK_JPROBE 0x82000 /* * OS-specific break numbers: diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h index 1b45b71c79b9..828ae00e47c1 100644 --- a/include/asm-ia64/kprobes.h +++ b/include/asm-ia64/kprobes.h @@ -115,6 +115,7 @@ struct arch_specific_insn { #define INST_FLAG_BREAK_INST 4 unsigned long inst_flag; unsigned short target_br_reg; + unsigned short slot; }; extern int kprobe_exceptions_notify(struct notifier_block *self, -- cgit v1.2.3-59-g8ed1b