xen: prevent adding duplicate xenwatches
When a xenstore watch triggers, the event is processed on process_msg and if a valid handle it's found the handler is queued for execution on the pending xen watches queue (watch_events). This may present a problem if we trigger a xenwatch several times and then disconnect the device. If several xenwatch events are added to the watch_events queue and the device is disconnected afterwards, the first processed xenwatch event will disconnect the device, remove the watch and free all resources. This triggers a panic if there are pending xenwatch events for that device already queued in the local queue of the function xenwatch_thread, since when the next watch that has the same handler tries to execute we get a panic due to the fact that the device is already disconnected and all resources had been freed: xenbus_watch: 0xffffa0000b7cd1d0 xbw_callback: 0xffffffff80755dd4 otherend_changed: backend/vif/1/0 backend/vif/1/0/state 6 backend/vif/1/0 -> Closed backend/vif/1/0 -> backend_device, b_detach: 0xffffffff8075a2bf xenbus_watch: 0xffffa0000b7cd1d0 xbw_callback: 0xfc5ec02183e547a8 fatal protection fault in supervisor mode trap type 4 code 0 rip ffffffff80756596 cs e030 rflags 10246 cr2 7f7ff7b4c020 ilevel 0 rsp ffffa000e6d82c50 curlwp 0xffffa0000a72d580 pid 0 lid 36 lowest kstack 0xffffa000e6d7f000 kernel: protection fault trap, code=0 Stopped in pid 0.36 (system) at netbsd:xenwatch_thread+0xc7: call *10(%rax ) xenwatch_thread() at netbsd:xenwatch_thread+0xc7 ds f es 5987 fs 2c40 gs 1460 rdi ffffa0000b7cd1d0 rsi ffffa0000a5477f0 rbp ffffa000e6d82c70 rbx ffffa0000b7c14c0 rdx 2 rcx f rax ffffa0000b7cd1d0 r8 78 r9 ffffffef r10 deadbeef r11 1 r12 ffffa000e6d82c50 r13 ffffa0000a72d580 r14 ffffa0000a72d580 r15 0 rip ffffffff80756596 xenwatch_thread+0xc7 cs e030 rflags 10246 rsp ffffa000e6d82c50 ss e02b netbsd:xenwatch_thread+0xc7: call *10(%rax)
This commit is contained in:
parent
9dae46742e
commit
f301a1b2e9
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: xenbus_xs.c,v 1.22 2011/07/27 23:11:23 matt Exp $ */
|
||||
/* $NetBSD: xenbus_xs.c,v 1.23 2012/11/28 16:26:59 royger Exp $ */
|
||||
/******************************************************************************
|
||||
* xenbus_xs.c
|
||||
*
|
||||
|
@ -30,7 +30,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: xenbus_xs.c,v 1.22 2011/07/27 23:11:23 matt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: xenbus_xs.c,v 1.23 2012/11/28 16:26:59 royger Exp $");
|
||||
|
||||
#if 0
|
||||
#define DPRINTK(fmt, args...) \
|
||||
|
@ -751,7 +751,7 @@ xenwatch_thread(void *unused)
|
|||
static int
|
||||
process_msg(void)
|
||||
{
|
||||
struct xs_stored_msg *msg;
|
||||
struct xs_stored_msg *msg, *s_msg;
|
||||
char *body;
|
||||
int err;
|
||||
|
||||
|
@ -782,7 +782,7 @@ process_msg(void)
|
|||
body[msg->hdr.len] = '\0';
|
||||
|
||||
if (msg->hdr.type == XS_WATCH_EVENT) {
|
||||
bool found;
|
||||
bool found, repeated;
|
||||
|
||||
DPRINTK("process_msg: XS_WATCH_EVENT");
|
||||
msg->u.watch.vec = split(body, msg->hdr.len,
|
||||
|
@ -796,14 +796,24 @@ process_msg(void)
|
|||
msg->u.watch.handle = find_watch(
|
||||
msg->u.watch.vec[XS_WATCH_TOKEN]);
|
||||
found = (msg->u.watch.handle != NULL);
|
||||
repeated = false;
|
||||
if (found) {
|
||||
mutex_enter(&watch_events_lock);
|
||||
SIMPLEQ_INSERT_TAIL(&watch_events, msg, msg_next);
|
||||
cv_broadcast(&watch_cv);
|
||||
/* Don't add duplicate events to the queue of pending watches */
|
||||
SIMPLEQ_FOREACH(s_msg, &watch_events, msg_next) {
|
||||
if (s_msg->u.watch.handle == msg->u.watch.handle) {
|
||||
repeated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!repeated) {
|
||||
SIMPLEQ_INSERT_TAIL(&watch_events, msg, msg_next);
|
||||
cv_broadcast(&watch_cv);
|
||||
}
|
||||
mutex_exit(&watch_events_lock);
|
||||
}
|
||||
mutex_exit(&watches_lock);
|
||||
if (!found) {
|
||||
if (!found || repeated) {
|
||||
free(msg->u.watch.vec, M_DEVBUF);
|
||||
free(msg, M_DEVBUF);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue