aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hv/hv_kvp.c
diff options
context:
space:
mode:
authorOlaf Hering <olaf@aepfle.de>2015-12-14 19:01:33 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-12-14 22:12:21 -0500
commit3cace4a616108539e2730f8dc21a636474395e0f (patch)
tree431580a2995465901957035bfd024e038ba8ebf3 /drivers/hv/hv_kvp.c
parentc0b200cfb0403740171c7527b3ac71d03f82947a (diff)
Drivers: hv: utils: run polling callback always in interrupt context
All channel interrupts are bound to specific VCPUs in the guest at the point channel is created. While currently, we invoke the polling function on the correct CPU (the CPU to which the channel is bound to) in some cases we may run the polling function in a non-interrupt context. This potentially can cause an issue as the polling function can be interrupted by the channel callback function. Fix the issue by running the polling function on the appropriate CPU at interrupt level. Additional details of the issue being addressed by this patch are given below: Currently hv_fcopy_onchannelcallback is called from interrupts and also via the ->write function of hv_utils. Since the used global variables to maintain state are not thread safe the state can get out of sync. This affects the variable state as well as the channel inbound buffer. As suggested by KY adjust hv_poll_channel to always run the given callback on the cpu which the channel is bound to. This avoids the need for locking because all the util services are single threaded and only one transaction is active at any given point in time. Additionally, remove the context variable, they will always be the same as recv_channel. Signed-off-by: Olaf Hering <olaf@aepfle.de> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hv/hv_kvp.c')
-rw-r--r--drivers/hv/hv_kvp.c28
1 files changed, 10 insertions, 18 deletions
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index e6aa33a89b0e..2a3420c4ca59 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -66,7 +66,6 @@ static struct {
66 struct hv_kvp_msg *kvp_msg; /* current message */ 66 struct hv_kvp_msg *kvp_msg; /* current message */
67 struct vmbus_channel *recv_channel; /* chn we got the request */ 67 struct vmbus_channel *recv_channel; /* chn we got the request */
68 u64 recv_req_id; /* request ID. */ 68 u64 recv_req_id; /* request ID. */
69 void *kvp_context; /* for the channel callback */
70} kvp_transaction; 69} kvp_transaction;
71 70
72/* 71/*
@@ -94,6 +93,13 @@ static struct hvutil_transport *hvt;
94 */ 93 */
95#define HV_DRV_VERSION "3.1" 94#define HV_DRV_VERSION "3.1"
96 95
96static void kvp_poll_wrapper(void *channel)
97{
98 /* Transaction is finished, reset the state here to avoid races. */
99 kvp_transaction.state = HVUTIL_READY;
100 hv_kvp_onchannelcallback(channel);
101}
102
97static void 103static void
98kvp_register(int reg_value) 104kvp_register(int reg_value)
99{ 105{
@@ -121,12 +127,7 @@ static void kvp_timeout_func(struct work_struct *dummy)
121 */ 127 */
122 kvp_respond_to_host(NULL, HV_E_FAIL); 128 kvp_respond_to_host(NULL, HV_E_FAIL);
123 129
124 /* Transaction is finished, reset the state. */ 130 hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
125 if (kvp_transaction.state > HVUTIL_READY)
126 kvp_transaction.state = HVUTIL_READY;
127
128 hv_poll_channel(kvp_transaction.kvp_context,
129 hv_kvp_onchannelcallback);
130} 131}
131 132
132static int kvp_handle_handshake(struct hv_kvp_msg *msg) 133static int kvp_handle_handshake(struct hv_kvp_msg *msg)
@@ -218,9 +219,7 @@ static int kvp_on_msg(void *msg, int len)
218 */ 219 */
219 if (cancel_delayed_work_sync(&kvp_timeout_work)) { 220 if (cancel_delayed_work_sync(&kvp_timeout_work)) {
220 kvp_respond_to_host(message, error); 221 kvp_respond_to_host(message, error);
221 kvp_transaction.state = HVUTIL_READY; 222 hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
222 hv_poll_channel(kvp_transaction.kvp_context,
223 hv_kvp_onchannelcallback);
224 } 223 }
225 224
226 return 0; 225 return 0;
@@ -596,15 +595,8 @@ void hv_kvp_onchannelcallback(void *context)
596 int util_fw_version; 595 int util_fw_version;
597 int kvp_srv_version; 596 int kvp_srv_version;
598 597
599 if (kvp_transaction.state > HVUTIL_READY) { 598 if (kvp_transaction.state > HVUTIL_READY)
600 /*
601 * We will defer processing this callback once
602 * the current transaction is complete.
603 */
604 kvp_transaction.kvp_context = context;
605 return; 599 return;
606 }
607 kvp_transaction.kvp_context = NULL;
608 600
609 vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen, 601 vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen,
610 &requestid); 602 &requestid);