From: Brad Peters <bpeters@redhat.com> Date: Thu, 31 Jul 2008 14:52:38 -0400 Subject: [ppc64] missed hw breakpoints across multiple threads Message-id: 20080731185238.10238.3682.sendpatchset@squad5-lp1.lab.bos.redhat.com O-Subject: [PATCH RHEL5.3] Kernel missing triggers of hw watchpoints using DABR registers with multi-threaded apps Bugzilla: 444076 RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com> RHBZ#: ====== https://bugzilla.redhat.com/show_bug.cgi?id=444076 Description: =========== Upon estabilishing a hardware watchpoint to monitor a variable on PPC64 64-bit threaded binary, sometimes GDB does not receive signals back from the kernel even though the monitored variable's been changed. The patch does the following. We keep a per-cpu cache of the current DABR value, and only write to the DABR register if the current process has a different DABR value. In one place we were forgetting to update the cache, and so we would incorrectly skip a write to the register. The patch just moves the cache management into the set_dabr() function so the cache always reflects reality. RHEL Version Found: ================ RHEL 5.2 kABI Status: ============ No symbols were harmed. Brew: ===== Built on all platforms. http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1389146 Upstream Status: ================ Committed here: http://lkml.org/lkml/2008/3/28/127 Test Status: ============ Using test case attached to BZ, repeating 250 times did not witness a single failure. Brad Peters, 7/31/08 =============================================================== Proposed Patch: =============== This patch is based on 2.6.18-95 diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index e96fa97..f4169c3 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -221,8 +221,17 @@ void discard_lazy_cpu_state(void) #endif /* CONFIG_SMP */ #ifdef CONFIG_PPC_MERGE /* XXX for now */ + +#ifdef CONFIG_PPC64 +static DEFINE_PER_CPU(unsigned long, current_dabr); +#endif + int set_dabr(unsigned long dabr) { +#ifdef CONFIG_PPC64 + __get_cpu_var(current_dabr) = dabr; +#endif + if (ppc_md.set_dabr) return ppc_md.set_dabr(dabr); @@ -233,7 +242,6 @@ int set_dabr(unsigned long dabr) #ifdef CONFIG_PPC64 DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); -static DEFINE_PER_CPU(unsigned long, current_dabr); #endif struct task_struct *__switch_to(struct task_struct *prev, @@ -301,10 +309,8 @@ struct task_struct *__switch_to(struct task_struct *prev, #endif /* CONFIG_SMP */ #ifdef CONFIG_PPC64 /* for now */ - if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) { + if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) set_dabr(new->thread.dabr); - __get_cpu_var(current_dabr) = new->thread.dabr; - } flush_tlb_pending(); #endif