diff options
author | Ian Campbell <ian.campbell@citrix.com> | 2009-11-03 10:58:40 -0500 |
---|---|---|
committer | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2009-11-03 17:35:59 -0500 |
commit | 4c31a781144c1f556dfcda3277dafecd4e107d95 (patch) | |
tree | cc2712f289e047b4cb782362bf3cef1415b04cb3 /drivers | |
parent | 74fca6a42863ffacaf7ba6f1936a9f228950f657 (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')
-rw-r--r-- | drivers/xen/xenbus/xenbus_xs.c | 57 |
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 | ||
170 | static 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 | |||
177 | static void transaction_end(void) | ||
178 | { | ||
179 | if (atomic_dec_and_test(&xs_state.transaction_count)) | ||
180 | wake_up(&xs_state.transaction_wq); | ||
181 | } | ||
182 | |||
183 | static 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 | |||
190 | static void transaction_resume(void) | ||
191 | { | ||
192 | mutex_unlock(&xs_state.transaction_mutex); | ||
193 | } | ||
194 | |||
160 | void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) | 195 | void *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 | ||
663 | void xs_suspend(void) | 698 | void 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 | ||
699 | static int xenwatch_thread(void *unused) | 734 | static 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(); |