diff options
| -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(); |
