ia64/linux-2.6.18-xen.hg

changeset 500:0637d22ed554

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@citrix.com>
author Ian Campbell <ian.campbell@citrix.com>
date Fri Mar 28 09:49:22 2008 +0000 (2008-03-28)
parents fdb998e79aba
children 080b0c482ad6
files drivers/xen/xenbus/xenbus_xs.c
line diff
     1.1 --- a/drivers/xen/xenbus/xenbus_xs.c	Fri Mar 28 09:44:51 2008 +0000
     1.2 +++ b/drivers/xen/xenbus/xenbus_xs.c	Fri Mar 28 09:49:22 2008 +0000
     1.3 @@ -629,6 +629,8 @@ void unregister_xenbus_watch(struct xenb
     1.4  	char token[sizeof(watch) * 2 + 1];
     1.5  	int err;
     1.6  
     1.7 +	BUG_ON(watch->flags & XBWF_new_thread);
     1.8 +
     1.9  	sprintf(token, "%lX", (long)watch);
    1.10  
    1.11  	down_read(&xs_state.watch_mutex);
    1.12 @@ -738,16 +740,29 @@ static int xenwatch_thread(void *unused)
    1.13  			list_del(ent);
    1.14  		spin_unlock(&watch_events_lock);
    1.15  
    1.16 -		if (ent != &watch_events) {
    1.17 -			msg = list_entry(ent, struct xs_stored_msg, list);
    1.18 -			if (msg->u.watch.handle->flags & XBWF_new_thread)
    1.19 -				kthread_run(xenwatch_handle_callback,
    1.20 -					    msg, "xenwatch_cb");
    1.21 -			else
    1.22 -				xenwatch_handle_callback(msg);
    1.23 +		if (ent == &watch_events) {
    1.24 +			mutex_unlock(&xenwatch_mutex);
    1.25 +			continue;
    1.26  		}
    1.27  
    1.28 -		mutex_unlock(&xenwatch_mutex);
    1.29 +		msg = list_entry(ent, struct xs_stored_msg, list);
    1.30 +
    1.31 +		/*
    1.32 +		 * Unlock the mutex before running an XBWF_new_thread
    1.33 +		 * handler. kthread_run can block which can deadlock
    1.34 +		 * against unregister_xenbus_watch() if we need to
    1.35 +		 * unregister other watches in order to make
    1.36 +		 * progress. This can occur on resume before the swap
    1.37 +		 * device is attached.
    1.38 +		 */
    1.39 +		if (msg->u.watch.handle->flags & XBWF_new_thread) {
    1.40 +			mutex_unlock(&xenwatch_mutex);
    1.41 +			kthread_run(xenwatch_handle_callback,
    1.42 +				    msg, "xenwatch_cb");
    1.43 +		} else {
    1.44 +			xenwatch_handle_callback(msg);
    1.45 +			mutex_unlock(&xenwatch_mutex);
    1.46 +		}
    1.47  	}
    1.48  
    1.49  	return 0;