diff options
author | Josh Stone <jistone@redhat.com> | 2009-03-12 17:12:38 -0700 |
---|---|---|
committer | Josh Stone <jistone@redhat.com> | 2009-03-13 14:32:31 -0700 |
commit | 52aeb26b8d83c26e00adaf70bbf5a3a828689fb2 (patch) | |
tree | fcc966c5906c8edf79ba0e2500d9a475d2396cf1 /runtime/transport/transport.c | |
parent | 2497c78e8aa704366683dad56fc8d749a5e92f52 (diff) | |
download | systemtap-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.c | 20 |
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); } |