Commit 7cc88fdcff3cc7f0d5d2384ffd7f6d4ce9a745f1
Exists in
master
and in
7 other branches
Merge branch 'xen/xenbus' into upstream/xen
* xen/xenbus: implement O_NONBLOCK for /proc/xen/xenbus xenbus: do not hold transaction_mutex when returning to userspace
Showing 2 changed files Side-by-side Diff
drivers/xen/xenbus/xenbus_xs.c
... | ... | @@ -76,6 +76,14 @@ |
76 | 76 | /* |
77 | 77 | * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex. |
78 | 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 | 89 | /* One request at a time. */ |
... | ... | @@ -85,7 +93,9 @@ |
85 | 93 | struct mutex response_mutex; |
86 | 94 | |
87 | 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 | 100 | /* Protect watch (de)register against save/restore. */ |
91 | 101 | struct rw_semaphore watch_mutex; |
... | ... | @@ -157,6 +167,31 @@ |
157 | 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 | 195 | void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) |
161 | 196 | { |
162 | 197 | void *ret; |
... | ... | @@ -164,7 +199,7 @@ |
164 | 199 | int err; |
165 | 200 | |
166 | 201 | if (req_msg.type == XS_TRANSACTION_START) |
167 | - down_read(&xs_state.transaction_mutex); | |
202 | + transaction_start(); | |
168 | 203 | |
169 | 204 | mutex_lock(&xs_state.request_mutex); |
170 | 205 | |
... | ... | @@ -180,7 +215,7 @@ |
180 | 215 | if ((msg->type == XS_TRANSACTION_END) || |
181 | 216 | ((req_msg.type == XS_TRANSACTION_START) && |
182 | 217 | (msg->type == XS_ERROR))) |
183 | - up_read(&xs_state.transaction_mutex); | |
218 | + transaction_end(); | |
184 | 219 | |
185 | 220 | return ret; |
186 | 221 | } |
187 | 222 | |
... | ... | @@ -432,11 +467,11 @@ |
432 | 467 | { |
433 | 468 | char *id_str; |
434 | 469 | |
435 | - down_read(&xs_state.transaction_mutex); | |
470 | + transaction_start(); | |
436 | 471 | |
437 | 472 | id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL); |
438 | 473 | if (IS_ERR(id_str)) { |
439 | - up_read(&xs_state.transaction_mutex); | |
474 | + transaction_end(); | |
440 | 475 | return PTR_ERR(id_str); |
441 | 476 | } |
442 | 477 | |
... | ... | @@ -461,7 +496,7 @@ |
461 | 496 | |
462 | 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 | 501 | return err; |
467 | 502 | } |
... | ... | @@ -662,7 +697,7 @@ |
662 | 697 | |
663 | 698 | void xs_suspend(void) |
664 | 699 | { |
665 | - down_write(&xs_state.transaction_mutex); | |
700 | + transaction_suspend(); | |
666 | 701 | down_write(&xs_state.watch_mutex); |
667 | 702 | mutex_lock(&xs_state.request_mutex); |
668 | 703 | mutex_lock(&xs_state.response_mutex); |
... | ... | @@ -677,7 +712,7 @@ |
677 | 712 | |
678 | 713 | mutex_unlock(&xs_state.response_mutex); |
679 | 714 | mutex_unlock(&xs_state.request_mutex); |
680 | - up_write(&xs_state.transaction_mutex); | |
715 | + transaction_resume(); | |
681 | 716 | |
682 | 717 | /* No need for watches_lock: the watch_mutex is sufficient. */ |
683 | 718 | list_for_each_entry(watch, &watches, list) { |
... | ... | @@ -693,7 +728,7 @@ |
693 | 728 | mutex_unlock(&xs_state.response_mutex); |
694 | 729 | mutex_unlock(&xs_state.request_mutex); |
695 | 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 | 734 | static int xenwatch_thread(void *unused) |
700 | 735 | |
... | ... | @@ -843,8 +878,10 @@ |
843 | 878 | |
844 | 879 | mutex_init(&xs_state.request_mutex); |
845 | 880 | mutex_init(&xs_state.response_mutex); |
846 | - init_rwsem(&xs_state.transaction_mutex); | |
881 | + mutex_init(&xs_state.transaction_mutex); | |
847 | 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 | 886 | /* Initialize the shared memory rings to talk to xenstored */ |
850 | 887 | err = xb_init_comms(); |
drivers/xen/xenfs/xenbus.c
... | ... | @@ -124,6 +124,9 @@ |
124 | 124 | mutex_lock(&u->reply_mutex); |
125 | 125 | while (list_empty(&u->read_buffers)) { |
126 | 126 | mutex_unlock(&u->reply_mutex); |
127 | + if (filp->f_flags & O_NONBLOCK) | |
128 | + return -EAGAIN; | |
129 | + | |
127 | 130 | ret = wait_event_interruptible(u->read_waitq, |
128 | 131 | !list_empty(&u->read_buffers)); |
129 | 132 | if (ret) |