aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2011-10-04 17:00:02 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-10-10 20:05:27 -0400
commit76e5f8135d63eb784ef44438e46e82cf0329e179 (patch)
tree1159513b1b822081bcd5333745e6b2e96061007c
parent93decf3661bf1c7c05bbc217d4e69222b557512a (diff)
Staging: hv: util: Fix a bug in kvp implementation
The host gurantees that there can be only one kvp transaction active against the guest. So, the transaction active state is needed only to protect against spurious user level calls. The current code had a race condition where the guest could prematurely return because the previous transaction state was not cleared - this state was being cleared after sending the response to the host and there was a window where the host could notify the guest of a new transaction before the transaction active state was properly set. Also deal with the case when the user mode component does not respond in a timely fashion correctly. I would like to thank Long Li <longli@microsoft.com> for identifying the problem. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> Diagnosed-by: Long Li <longli@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/staging/hv/hv_kvp.c13
1 files changed, 5 insertions, 8 deletions
diff --git a/drivers/staging/hv/hv_kvp.c b/drivers/staging/hv/hv_kvp.c
index 9aa9ede0ee8..307aedc08a3 100644
--- a/drivers/staging/hv/hv_kvp.c
+++ b/drivers/staging/hv/hv_kvp.c
@@ -50,6 +50,8 @@ static struct {
50 50
51static int kvp_send_key(int index); 51static int kvp_send_key(int index);
52 52
53#define TIMEOUT_FIRED 1
54
53static void kvp_respond_to_host(char *key, char *value, int error); 55static void kvp_respond_to_host(char *key, char *value, int error);
54static void kvp_work_func(struct work_struct *dummy); 56static void kvp_work_func(struct work_struct *dummy);
55static void kvp_register(void); 57static void kvp_register(void);
@@ -58,7 +60,6 @@ static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func);
58 60
59static struct cb_id kvp_id = { CN_KVP_IDX, CN_KVP_VAL }; 61static struct cb_id kvp_id = { CN_KVP_IDX, CN_KVP_VAL };
60static const char kvp_name[] = "kvp_kernel_module"; 62static const char kvp_name[] = "kvp_kernel_module";
61static int timeout_fired;
62static u8 *recv_buffer; 63static u8 *recv_buffer;
63/* 64/*
64 * Register the kernel component with the user-level daemon. 65 * Register the kernel component with the user-level daemon.
@@ -90,8 +91,7 @@ kvp_work_func(struct work_struct *dummy)
90 * If the timer fires, the user-mode component has not responded; 91 * If the timer fires, the user-mode component has not responded;
91 * process the pending transaction. 92 * process the pending transaction.
92 */ 93 */
93 kvp_respond_to_host("Unknown key", "Guest timed out", timeout_fired); 94 kvp_respond_to_host("Unknown key", "Guest timed out", TIMEOUT_FIRED);
94 timeout_fired = 1;
95} 95}
96 96
97/* 97/*
@@ -177,6 +177,8 @@ kvp_respond_to_host(char *key, char *value, int error)
177 channel = kvp_transaction.recv_channel; 177 channel = kvp_transaction.recv_channel;
178 req_id = kvp_transaction.recv_req_id; 178 req_id = kvp_transaction.recv_req_id;
179 179
180 kvp_transaction.active = false;
181
180 if (channel->onchannel_callback == NULL) 182 if (channel->onchannel_callback == NULL)
181 /* 183 /*
182 * We have raced with util driver being unloaded; 184 * We have raced with util driver being unloaded;
@@ -224,7 +226,6 @@ response_done:
224 vmbus_sendpacket(channel, recv_buffer, buf_len, req_id, 226 vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
225 VM_PKT_DATA_INBAND, 0); 227 VM_PKT_DATA_INBAND, 0);
226 228
227 kvp_transaction.active = false;
228} 229}
229 230
230/* 231/*
@@ -250,10 +251,6 @@ void hv_kvp_onchannelcallback(void *context)
250 struct icmsg_negotiate *negop = NULL; 251 struct icmsg_negotiate *negop = NULL;
251 252
252 253
253 if (kvp_transaction.active)
254 return;
255
256
257 vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid); 254 vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid);
258 255
259 if (recvlen > 0) { 256 if (recvlen > 0) {