This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[PATCH] uprobes: fix SMP multithreading race
- From: Jim Keniston <jkenisto at us dot ibm dot com>
- To: systemtap <systemtap at sources dot redhat dot com>
- Date: Sat, 09 Jun 2007 14:04:12 -0700
- Subject: [PATCH] uprobes: fix SMP multithreading race
The enclosed patch fixes a problem seen on SMP systems when multiple
threads of a multithreaded app are pounding the probed instruction
when the uprobe is registered. This patch applies atop the most recent
uprobes patch set, which I posted May 25 (May 26 UTC):
http://sources.redhat.com/ml/systemtap/2007-q2/msg00399.html
The problem was intermittent, but I was able to tickle it pretty
reliably using the enclosed script. In the test suite, run
$ probe7-thread 1000000000 # 1 billion
and after that's started, run the script
# ./poundt
The bug causes probe7-thread to die with a SIGSEGV. The fix allows
probe7-thread to run to completion.
Jim Keniston
----- poundt -----
#!/bin/bash
vaddr=`objdump -d probe7-thread | awk '$2=="<add>:" {print $1}'`
pid=`ps -e -o fname,pid | awk '$1=="probe7-t" {print $2}'`
kill -cont $pid
# While probed process runs...
while (ps -p $pid > /dev/null)
do
sleep 0.2
insmod probe5.ko verbose=0 vaddr=0x$vaddr pid=$pid
if [ $? -ne 0 ]
then
exit 1
fi
sleep 0.2
rmmod probe5
done
exit 0
-----
Fixes a problem seen on SMP systems when multiple threads of a multithreaded
app are pounding the probed instruction when the uprobe is registered.
uprobe_verify_ssol() was releasing the second thread through before SSOL
setup was complete.
---
include/linux/uprobes.h | 3 +++
kernel/uprobes.c | 8 +++++---
2 files changed, 8 insertions(+), 3 deletions(-)
diff -puN include/linux/uprobes.h~uprobes-smp-pounder-fix include/linux/uprobes.h
--- linux-2.6.21-rc6/include/linux/uprobes.h~uprobes-smp-pounder-fix 2007-06-09 11:21:05.000000000 -0700
+++ linux-2.6.21-rc6-jimk/include/linux/uprobes.h 2007-06-09 11:23:33.000000000 -0700
@@ -169,6 +169,9 @@ struct uprobe_ssol_area {
/* Ensures 2 threads don't try to set up the vma simultaneously. */
struct mutex setup_mutex;
+
+ /* 1 = we've at least tried. IS_ERR(insn_area) if we failed. */
+ int initialized;
};
/*
diff -puN kernel/uprobes.c~uprobes-smp-pounder-fix kernel/uprobes.c
--- linux-2.6.21-rc6/kernel/uprobes.c~uprobes-smp-pounder-fix 2007-06-09 11:21:05.000000000 -0700
+++ linux-2.6.21-rc6-jimk/kernel/uprobes.c 2007-06-09 11:23:51.000000000 -0700
@@ -285,9 +285,9 @@ static void rouse_all_threads(struct upr
if (utask->quiescing) {
utask->quiescing = 0;
if (utask->state == UPTASK_QUIESCENT) {
- clear_utrace_quiesce(utask);
utask->state = UPTASK_RUNNING;
uproc->n_quiescent_threads--;
+ clear_utrace_quiesce(utask);
}
}
}
@@ -533,6 +533,7 @@ static struct uprobe_process *uprobe_mk_
uproc->uretprobe_trampoline_addr = NULL;
uproc->ssol_area.insn_area = NULL;
+ uproc->ssol_area.initialized = 0;
mutex_init(&uproc->ssol_area.setup_mutex);
#ifdef CONFIG_UPROBES_SSOL
uproc->sstep_out_of_line = 1;
@@ -1020,13 +1021,14 @@ static __user uprobe_opcode_t
{
struct uprobe_ssol_area *area = &uproc->ssol_area;
- if (unlikely(!area->insn_area)) {
+ if (unlikely(!area->initialized)) {
/* First time through for this probed process */
static DEFINE_MUTEX(ssol_setup_mutex);
mutex_lock(&ssol_setup_mutex);
- if (likely(!area->insn_area))
+ if (likely(!area->initialized))
/* Nobody snuck in and set things up ahead of us. */
uprobe_init_ssol(uproc);
+ area->initialized = 1;
mutex_unlock(&ssol_setup_mutex);
}
return area->insn_area;
_