summaryrefslogtreecommitdiffstats
path: root/runtime/transport/transport.c
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2009-03-12 17:12:38 -0700
committerJosh Stone <jistone@redhat.com>2009-03-13 14:32:31 -0700
commit52aeb26b8d83c26e00adaf70bbf5a3a828689fb2 (patch)
treefcc966c5906c8edf79ba0e2500d9a475d2396cf1 /runtime/transport/transport.c
parent2497c78e8aa704366683dad56fc8d749a5e92f52 (diff)
downloadsystemtap-steved-52aeb26b8d83c26e00adaf70bbf5a3a828689fb2.tar.gz
systemtap-steved-52aeb26b8d83c26e00adaf70bbf5a3a828689fb2.tar.xz
systemtap-steved-52aeb26b8d83c26e00adaf70bbf5a3a828689fb2.zip
PR9947: move runtime cleanup out of the work queue
The kernel lockdep checking found a possible deadlock if a forced rmmod tried to destroy _stp_work_queue at the same time that the work queue was unregistering tracepoints. An unlikely scenario, but still possible. Now the work queue will just issue a STP_REQUEST_EXIT down to usermode, and usermode will echo back an STP_EXIT that triggers the actual probe cleanup. This way the unregistrations are happening in exactly the same context as the registrations were.
Diffstat (limited to 'runtime/transport/transport.c')
-rw-r--r--runtime/transport/transport.c20
1 files changed, 16 insertions, 4 deletions
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index 7fcebd42..762c0a92 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -25,7 +25,6 @@ static struct utt_trace *_stp_utt = NULL;
static unsigned int utt_seq = 1;
static int _stp_probes_started = 0;
static pid_t _stp_target = 0;
-static int _stp_exit_called = 0;
static int _stp_exit_flag = 0;
#include "control.h"
#ifdef STP_OLD_TRANSPORT
@@ -89,13 +88,14 @@ static void _stp_handle_start(struct _stp_msg_start *st)
/* when someone does /sbin/rmmod on a loaded systemtap module. */
static void _stp_cleanup_and_exit(int send_exit)
{
- if (!_stp_exit_called) {
+ static int called = 0;
+ if (!called) {
int failures;
dbug_trans(1, "cleanup_and_exit (%d)\n", send_exit);
_stp_exit_flag = 1;
/* we only want to do this stuff once */
- _stp_exit_called = 1;
+ called = 1;
if (_stp_probes_started) {
dbug_trans(1, "calling probe_exit\n");
@@ -119,6 +119,18 @@ static void _stp_cleanup_and_exit(int send_exit)
}
}
+static void _stp_request_exit(void)
+{
+ static int called = 0;
+ if (!called) {
+ /* we only want to do this once */
+ called = 1;
+ dbug_trans(1, "ctl_send STP_REQUEST_EXIT\n");
+ _stp_ctl_send(STP_REQUEST_EXIT, NULL, 0);
+ dbug_trans(1, "done with ctl_send STP_REQUEST_EXIT\n");
+ }
+}
+
/*
* Called when stapio closes the control channel.
*/
@@ -169,7 +181,7 @@ static void _stp_work_queue(void *data)
/* if exit flag is set AND we have finished with probe_start() */
if (unlikely(_stp_exit_flag && _stp_probes_started))
- _stp_cleanup_and_exit(1);
+ _stp_request_exit();
if (likely(_stp_attached))
queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER);
}