aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen
diff options
context:
space:
mode:
authorIan Campbell <ian.campbell@citrix.com>2009-11-03 10:58:40 -0500
committerJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2009-11-03 17:35:59 -0500
commit4c31a781144c1f556dfcda3277dafecd4e107d95 (patch)
treecc2712f289e047b4cb782362bf3cef1415b04cb3 /drivers/xen
parent74fca6a42863ffacaf7ba6f1936a9f228950f657 (diff)
xenbus: do not hold transaction_mutex when returning to userspace
================================================ [ BUG: lock held when returning to user space! ] ------------------------------------------------ xenstore-list/3522 is leaving the kernel with locks still held! 1 lock held by xenstore-list/3522: #0: (&xs_state.transaction_mutex){......}, at: [<c026dc6f>] xenbus_dev_request_and_reply+0x8f/0xa0 The canonical fix for this type of issue appears to be to maintain a count manually rather than using an rwsem so do that here. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Diffstat (limited to 'drivers/xen')
-rw-r--r--drivers/xen/xenbus/xenbus_xs.c57
1 files changed, 47 insertions, 10 deletions
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
index eab33f1dbdf7..6f91e8c8b932 100644
--- a/drivers/xen/xenbus/xenbus_xs.c
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -76,6 +76,14 @@ struct xs_handle {
76 /* 76 /*
77 * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex. 77 * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex.
78 * response_mutex is never taken simultaneously with the other three. 78 * response_mutex is never taken simultaneously with the other three.
79 *
80 * transaction_mutex must be held before incrementing
81 * transaction_count. The mutex is held when a suspend is in
82 * progress to prevent new transactions starting.
83 *
84 * When decrementing transaction_count to zero the wait queue
85 * should be woken up, the suspend code waits for count to
86 * reach zero.
79 */ 87 */
80 88
81 /* One request at a time. */ 89 /* One request at a time. */
@@ -85,7 +93,9 @@ struct xs_handle {
85 struct mutex response_mutex; 93 struct mutex response_mutex;
86 94
87 /* Protect transactions against save/restore. */ 95 /* Protect transactions against save/restore. */
88 struct rw_semaphore transaction_mutex; 96 struct mutex transaction_mutex;
97 atomic_t transaction_count;
98 wait_queue_head_t transaction_wq;
89 99
90 /* Protect watch (de)register against save/restore. */ 100 /* Protect watch (de)register against save/restore. */
91 struct rw_semaphore watch_mutex; 101 struct rw_semaphore watch_mutex;
@@ -157,6 +167,31 @@ static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
157 return body; 167 return body;
158} 168}
159 169
170static void transaction_start(void)
171{
172 mutex_lock(&xs_state.transaction_mutex);
173 atomic_inc(&xs_state.transaction_count);
174 mutex_unlock(&xs_state.transaction_mutex);
175}
176
177static void transaction_end(void)
178{
179 if (atomic_dec_and_test(&xs_state.transaction_count))
180 wake_up(&xs_state.transaction_wq);
181}
182
183static void transaction_suspend(void)
184{
185 mutex_lock(&xs_state.transaction_mutex);
186 wait_event(xs_state.transaction_wq,
187 atomic_read(&xs_state.transaction_count) == 0);
188}
189
190static void transaction_resume(void)
191{
192 mutex_unlock(&xs_state.transaction_mutex);
193}
194
160void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) 195void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
161{ 196{
162 void *ret; 197 void *ret;
@@ -164,7 +199,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
164 int err; 199 int err;
165 200
166 if (req_msg.type == XS_TRANSACTION_START) 201 if (req_msg.type == XS_TRANSACTION_START)
167 down_read(&xs_state.transaction_mutex); 202 transaction_start();
168 203
169 mutex_lock(&xs_state.request_mutex); 204 mutex_lock(&xs_state.request_mutex);
170 205
@@ -180,7 +215,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
180 if ((msg->type == XS_TRANSACTION_END) || 215 if ((msg->type == XS_TRANSACTION_END) ||
181 ((req_msg.type == XS_TRANSACTION_START) && 216 ((req_msg.type == XS_TRANSACTION_START) &&
182 (msg->type == XS_ERROR))) 217 (msg->type == XS_ERROR)))
183 up_read(&xs_state.transaction_mutex); 218 transaction_end();
184 219
185 return ret; 220 return ret;
186} 221}
@@ -432,11 +467,11 @@ int xenbus_transaction_start(struct xenbus_transaction *t)
432{ 467{
433 char *id_str; 468 char *id_str;
434 469
435 down_read(&xs_state.transaction_mutex); 470 transaction_start();
436 471
437 id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL); 472 id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL);
438 if (IS_ERR(id_str)) { 473 if (IS_ERR(id_str)) {
439 up_read(&xs_state.transaction_mutex); 474 transaction_end();
440 return PTR_ERR(id_str); 475 return PTR_ERR(id_str);
441 } 476 }
442 477
@@ -461,7 +496,7 @@ int xenbus_transaction_end(struct xenbus_transaction t, int abort)
461 496
462 err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL)); 497 err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
463 498
464 up_read(&xs_state.transaction_mutex); 499 transaction_end();
465 500
466 return err; 501 return err;
467} 502}
@@ -662,7 +697,7 @@ EXPORT_SYMBOL_GPL(unregister_xenbus_watch);
662 697
663void xs_suspend(void) 698void xs_suspend(void)
664{ 699{
665 down_write(&xs_state.transaction_mutex); 700 transaction_suspend();
666 down_write(&xs_state.watch_mutex); 701 down_write(&xs_state.watch_mutex);
667 mutex_lock(&xs_state.request_mutex); 702 mutex_lock(&xs_state.request_mutex);
668 mutex_lock(&xs_state.response_mutex); 703 mutex_lock(&xs_state.response_mutex);
@@ -677,7 +712,7 @@ void xs_resume(void)
677 712
678 mutex_unlock(&xs_state.response_mutex); 713 mutex_unlock(&xs_state.response_mutex);
679 mutex_unlock(&xs_state.request_mutex); 714 mutex_unlock(&xs_state.request_mutex);
680 up_write(&xs_state.transaction_mutex); 715 transaction_resume();
681 716
682 /* No need for watches_lock: the watch_mutex is sufficient. */ 717 /* No need for watches_lock: the watch_mutex is sufficient. */
683 list_for_each_entry(watch, &watches, list) { 718 list_for_each_entry(watch, &watches, list) {
@@ -693,7 +728,7 @@ void xs_suspend_cancel(void)
693 mutex_unlock(&xs_state.response_mutex); 728 mutex_unlock(&xs_state.response_mutex);
694 mutex_unlock(&xs_state.request_mutex); 729 mutex_unlock(&xs_state.request_mutex);
695 up_write(&xs_state.watch_mutex); 730 up_write(&xs_state.watch_mutex);
696 up_write(&xs_state.transaction_mutex); 731 mutex_unlock(&xs_state.transaction_mutex);
697} 732}
698 733
699static int xenwatch_thread(void *unused) 734static int xenwatch_thread(void *unused)
@@ -843,8 +878,10 @@ int xs_init(void)
843 878
844 mutex_init(&xs_state.request_mutex); 879 mutex_init(&xs_state.request_mutex);
845 mutex_init(&xs_state.response_mutex); 880 mutex_init(&xs_state.response_mutex);
846 init_rwsem(&xs_state.transaction_mutex); 881 mutex_init(&xs_state.transaction_mutex);
847 init_rwsem(&xs_state.watch_mutex); 882 init_rwsem(&xs_state.watch_mutex);
883 atomic_set(&xs_state.transaction_count, 0);
884 init_waitqueue_head(&xs_state.transaction_wq);
848 885
849 /* Initialize the shared memory rings to talk to xenstored */ 886 /* Initialize the shared memory rings to talk to xenstored */
850 err = xb_init_comms(); 887 err = xb_init_comms();