# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1206978517 -3600
# Node ID a7c923d6cf228ecb32619280488385b71377cf17
# Parent 456421041d9ab8ae56ee28b8e0228fd44f10837e
Avoid deadlock when unregistering a xenbus watch.
Watch handlers which run in a separate thread (XBWF_new_thread) should
run without the xenbus_mutex held since kthread_run can block waiting
for memory which causes a deadlock if further watches need to be
unregistered in order to activate the swap device on resume.
XBWF_new_thread cannot be safely unregistered anyway since the mutex
only protects thread startup.
Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
linux-2.6.18-xen changeset: 498:0637d22ed554eb0b9cecc7a74fa0a77a7c456497
linux-2.6.18-xen date: Fri Mar 28 09:49:22 2008 +0000
---
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c | 31 ++++++++++++++------
1 files changed, 23 insertions(+), 8 deletions(-)
diff -r 456421041d9a -r a7c923d6cf22
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c Mon Mar 31
16:48:17 2008 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c Mon Mar 31
16:48:37 2008 +0100
@@ -629,6 +629,8 @@ void unregister_xenbus_watch(struct xenb
char token[sizeof(watch) * 2 + 1];
int err;
+ BUG_ON(watch->flags & XBWF_new_thread);
+
sprintf(token, "%lX", (long)watch);
down_read(&xs_state.watch_mutex);
@@ -738,16 +740,29 @@ static int xenwatch_thread(void *unused)
list_del(ent);
spin_unlock(&watch_events_lock);
- if (ent != &watch_events) {
- msg = list_entry(ent, struct xs_stored_msg, list);
- if (msg->u.watch.handle->flags & XBWF_new_thread)
- kthread_run(xenwatch_handle_callback,
- msg, "xenwatch_cb");
- else
- xenwatch_handle_callback(msg);
+ if (ent == &watch_events) {
+ mutex_unlock(&xenwatch_mutex);
+ continue;
}
- mutex_unlock(&xenwatch_mutex);
+ msg = list_entry(ent, struct xs_stored_msg, list);
+
+ /*
+ * Unlock the mutex before running an XBWF_new_thread
+ * handler. kthread_run can block which can deadlock
+ * against unregister_xenbus_watch() if we need to
+ * unregister other watches in order to make
+ * progress. This can occur on resume before the swap
+ * device is attached.
+ */
+ if (msg->u.watch.handle->flags & XBWF_new_thread) {
+ mutex_unlock(&xenwatch_mutex);
+ kthread_run(xenwatch_handle_callback,
+ msg, "xenwatch_cb");
+ } else {
+ xenwatch_handle_callback(msg);
+ mutex_unlock(&xenwatch_mutex);
+ }
}
return 0;
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|