aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hv
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2012-03-16 11:02:25 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-03-16 16:36:04 -0400
commitfa3d5b85c681518b6e4ec515814dcb2d5b702b89 (patch)
treea4da543c22e4fb90bb75b977728501ca42f92870 /drivers/hv
parente485ceac9ebd43901ef0ce13622385d509e072e7 (diff)
Drivers: hv: Support the newly introduced KVP messages in the driver
Support the newly defined KVP message types. It turns out that the host pushes a set of standard key value pairs as soon as the guest opens the KVP channel. Since we cannot handle these tuples until the user level daemon loads up, defer reading the KVP channel until the user level daemon is launched. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hv')
-rw-r--r--drivers/hv/hv_kvp.c218
1 files changed, 167 insertions, 51 deletions
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 779109b6f4f0..cfe60b02e3e8 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -42,9 +42,10 @@
42static struct { 42static struct {
43 bool active; /* transaction status - active or not */ 43 bool active; /* transaction status - active or not */
44 int recv_len; /* number of bytes received. */ 44 int recv_len; /* number of bytes received. */
45 int index; /* current index */ 45 struct hv_kvp_msg *kvp_msg; /* current message */
46 struct vmbus_channel *recv_channel; /* chn we got the request */ 46 struct vmbus_channel *recv_channel; /* chn we got the request */
47 u64 recv_req_id; /* request ID. */ 47 u64 recv_req_id; /* request ID. */
48 void *kvp_context; /* for the channel callback */
48} kvp_transaction; 49} kvp_transaction;
49 50
50static void kvp_send_key(struct work_struct *dummy); 51static void kvp_send_key(struct work_struct *dummy);
@@ -110,12 +111,15 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
110 struct hv_kvp_msg_enumerate *data; 111 struct hv_kvp_msg_enumerate *data;
111 112
112 message = (struct hv_kvp_msg *)msg->data; 113 message = (struct hv_kvp_msg *)msg->data;
113 if (message->kvp_hdr.operation == KVP_OP_REGISTER) { 114 switch (message->kvp_hdr.operation) {
115 case KVP_OP_REGISTER:
114 pr_info("KVP: user-mode registering done.\n"); 116 pr_info("KVP: user-mode registering done.\n");
115 kvp_register(); 117 kvp_register();
116 } 118 kvp_transaction.active = false;
119 hv_kvp_onchannelcallback(kvp_transaction.kvp_context);
120 break;
117 121
118 if (message->kvp_hdr.operation == KVP_OP_ENUMERATE) { 122 default:
119 data = &message->body.kvp_enum_data; 123 data = &message->body.kvp_enum_data;
120 /* 124 /*
121 * Complete the transaction by forwarding the key value 125 * Complete the transaction by forwarding the key value
@@ -133,21 +137,104 @@ kvp_send_key(struct work_struct *dummy)
133{ 137{
134 struct cn_msg *msg; 138 struct cn_msg *msg;
135 struct hv_kvp_msg *message; 139 struct hv_kvp_msg *message;
136 int index = kvp_transaction.index; 140 struct hv_kvp_msg *in_msg;
141 __u8 operation = kvp_transaction.kvp_msg->kvp_hdr.operation;
142 __u8 pool = kvp_transaction.kvp_msg->kvp_hdr.pool;
143 __u32 val32;
144 __u64 val64;
137 145
138 msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC); 146 msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC);
147 if (!msg)
148 return;
139 149
140 if (msg) { 150 msg->id.idx = CN_KVP_IDX;
141 msg->id.idx = CN_KVP_IDX; 151 msg->id.val = CN_KVP_VAL;
142 msg->id.val = CN_KVP_VAL;
143 152
144 message = (struct hv_kvp_msg *)msg->data; 153 message = (struct hv_kvp_msg *)msg->data;
145 message->kvp_hdr.operation = KVP_OP_ENUMERATE; 154 message->kvp_hdr.operation = operation;
146 message->body.kvp_enum_data.index = index; 155 message->kvp_hdr.pool = pool;
147 msg->len = sizeof(struct hv_kvp_msg); 156 in_msg = kvp_transaction.kvp_msg;
148 cn_netlink_send(msg, 0, GFP_ATOMIC); 157
149 kfree(msg); 158 /*
159 * The key/value strings sent from the host are encoded in
160 * in utf16; convert it to utf8 strings.
161 * The host assures us that the utf16 strings will not exceed
162 * the max lengths specified. We will however, reserve room
163 * for the string terminating character - in the utf16s_utf8s()
164 * function we limit the size of the buffer where the converted
165 * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to gaurantee
166 * that the strings can be properly terminated!
167 */
168
169 switch (message->kvp_hdr.operation) {
170 case KVP_OP_SET:
171 switch (in_msg->body.kvp_set.data.value_type) {
172 case REG_SZ:
173 /*
174 * The value is a string - utf16 encoding.
175 */
176 message->body.kvp_set.data.value_size =
177 utf16s_to_utf8s(
178 (wchar_t *)in_msg->body.kvp_set.data.value,
179 in_msg->body.kvp_set.data.value_size,
180 UTF16_LITTLE_ENDIAN,
181 message->body.kvp_set.data.value,
182 HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1;
183 break;
184
185 case REG_U32:
186 /*
187 * The value is a 32 bit scalar.
188 * We save this as a utf8 string.
189 */
190 val32 = in_msg->body.kvp_set.data.value_u32;
191 message->body.kvp_set.data.value_size =
192 sprintf(message->body.kvp_set.data.value,
193 "%d", val32) + 1;
194 break;
195
196 case REG_U64:
197 /*
198 * The value is a 64 bit scalar.
199 * We save this as a utf8 string.
200 */
201 val64 = in_msg->body.kvp_set.data.value_u64;
202 message->body.kvp_set.data.value_size =
203 sprintf(message->body.kvp_set.data.value,
204 "%llu", val64) + 1;
205 break;
206
207 }
208 case KVP_OP_GET:
209 message->body.kvp_set.data.key_size =
210 utf16s_to_utf8s(
211 (wchar_t *)in_msg->body.kvp_set.data.key,
212 in_msg->body.kvp_set.data.key_size,
213 UTF16_LITTLE_ENDIAN,
214 message->body.kvp_set.data.key,
215 HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
216 break;
217
218 case KVP_OP_DELETE:
219 message->body.kvp_delete.key_size =
220 utf16s_to_utf8s(
221 (wchar_t *)in_msg->body.kvp_delete.key,
222 in_msg->body.kvp_delete.key_size,
223 UTF16_LITTLE_ENDIAN,
224 message->body.kvp_delete.key,
225 HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
226 break;
227
228 case KVP_OP_ENUMERATE:
229 message->body.kvp_enum_data.index =
230 in_msg->body.kvp_enum_data.index;
231 break;
150 } 232 }
233
234 msg->len = sizeof(struct hv_kvp_msg);
235 cn_netlink_send(msg, 0, GFP_ATOMIC);
236 kfree(msg);
237
151 return; 238 return;
152} 239}
153 240
@@ -159,10 +246,11 @@ static void
159kvp_respond_to_host(char *key, char *value, int error) 246kvp_respond_to_host(char *key, char *value, int error)
160{ 247{
161 struct hv_kvp_msg *kvp_msg; 248 struct hv_kvp_msg *kvp_msg;
162 struct hv_kvp_msg_enumerate *kvp_data; 249 struct hv_kvp_exchg_msg_value *kvp_data;
163 char *key_name; 250 char *key_name;
164 struct icmsg_hdr *icmsghdrp; 251 struct icmsg_hdr *icmsghdrp;
165 int keylen, valuelen; 252 int keylen = 0;
253 int valuelen = 0;
166 u32 buf_len; 254 u32 buf_len;
167 struct vmbus_channel *channel; 255 struct vmbus_channel *channel;
168 u64 req_id; 256 u64 req_id;
@@ -189,6 +277,9 @@ kvp_respond_to_host(char *key, char *value, int error)
189 277
190 kvp_transaction.active = false; 278 kvp_transaction.active = false;
191 279
280 icmsghdrp = (struct icmsg_hdr *)
281 &recv_buffer[sizeof(struct vmbuspipe_hdr)];
282
192 if (channel->onchannel_callback == NULL) 283 if (channel->onchannel_callback == NULL)
193 /* 284 /*
194 * We have raced with util driver being unloaded; 285 * We have raced with util driver being unloaded;
@@ -196,41 +287,66 @@ kvp_respond_to_host(char *key, char *value, int error)
196 */ 287 */
197 return; 288 return;
198 289
199 icmsghdrp = (struct icmsg_hdr *)
200 &recv_buffer[sizeof(struct vmbuspipe_hdr)];
201 kvp_msg = (struct hv_kvp_msg *)
202 &recv_buffer[sizeof(struct vmbuspipe_hdr) +
203 sizeof(struct icmsg_hdr)];
204 kvp_data = &kvp_msg->body.kvp_enum_data;
205 key_name = key;
206 290
207 /* 291 /*
208 * If the error parameter is set, terminate the host's enumeration. 292 * If the error parameter is set, terminate the host's enumeration.
209 */ 293 */
210 if (error) { 294 if (error) {
211 /* 295 /*
212 * We don't support this index or the we have timedout; 296 * Something failed or the we have timedout;
213 * terminate the host-side iteration by returning an error. 297 * terminate the host-side iteration by returning an error.
214 */ 298 */
215 icmsghdrp->status = HV_E_FAIL; 299 icmsghdrp->status = HV_E_FAIL;
216 goto response_done; 300 goto response_done;
217 } 301 }
218 302
303 icmsghdrp->status = HV_S_OK;
304
305 kvp_msg = (struct hv_kvp_msg *)
306 &recv_buffer[sizeof(struct vmbuspipe_hdr) +
307 sizeof(struct icmsg_hdr)];
308
309 switch (kvp_transaction.kvp_msg->kvp_hdr.operation) {
310 case KVP_OP_GET:
311 kvp_data = &kvp_msg->body.kvp_get.data;
312 goto copy_value;
313
314 case KVP_OP_SET:
315 case KVP_OP_DELETE:
316 goto response_done;
317
318 default:
319 break;
320 }
321
322 kvp_data = &kvp_msg->body.kvp_enum_data.data;
323 key_name = key;
324
219 /* 325 /*
220 * The windows host expects the key/value pair to be encoded 326 * The windows host expects the key/value pair to be encoded
221 * in utf16. 327 * in utf16. Ensure that the key/value size reported to the host
328 * will be less than or equal to the MAX size (including the
329 * terminating character).
222 */ 330 */
223 keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN, 331 keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN,
224 (wchar_t *) kvp_data->data.key, 332 (wchar_t *) kvp_data->key,
225 HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2); 333 (HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2) - 2);
226 kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */ 334 kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */
335
336copy_value:
227 valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN, 337 valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
228 (wchar_t *) kvp_data->data.value, 338 (wchar_t *) kvp_data->value,
229 HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2); 339 (HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2);
230 kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */ 340 kvp_data->value_size = 2*(valuelen + 1); /* utf16 encoding */
231 341
232 kvp_data->data.value_type = REG_SZ; /* all our values are strings */ 342 /*
233 icmsghdrp->status = HV_S_OK; 343 * If the utf8s to utf16s conversion failed; notify host
344 * of the error.
345 */
346 if ((keylen < 0) || (valuelen < 0))
347 icmsghdrp->status = HV_E_FAIL;
348
349 kvp_data->value_type = REG_SZ; /* all our values are strings */
234 350
235response_done: 351response_done:
236 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; 352 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
@@ -257,11 +373,18 @@ void hv_kvp_onchannelcallback(void *context)
257 u64 requestid; 373 u64 requestid;
258 374
259 struct hv_kvp_msg *kvp_msg; 375 struct hv_kvp_msg *kvp_msg;
260 struct hv_kvp_msg_enumerate *kvp_data;
261 376
262 struct icmsg_hdr *icmsghdrp; 377 struct icmsg_hdr *icmsghdrp;
263 struct icmsg_negotiate *negop = NULL; 378 struct icmsg_negotiate *negop = NULL;
264 379
380 if (kvp_transaction.active) {
381 /*
382 * We will defer processing this callback once
383 * the current transaction is complete.
384 */
385 kvp_transaction.kvp_context = context;
386 return;
387 }
265 388
266 vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid); 389 vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid);
267 390
@@ -276,29 +399,16 @@ void hv_kvp_onchannelcallback(void *context)
276 sizeof(struct vmbuspipe_hdr) + 399 sizeof(struct vmbuspipe_hdr) +
277 sizeof(struct icmsg_hdr)]; 400 sizeof(struct icmsg_hdr)];
278 401
279 kvp_data = &kvp_msg->body.kvp_enum_data;
280
281 /*
282 * We only support the "get" operation on
283 * "KVP_POOL_AUTO" pool.
284 */
285
286 if ((kvp_msg->kvp_hdr.pool != KVP_POOL_AUTO) ||
287 (kvp_msg->kvp_hdr.operation !=
288 KVP_OP_ENUMERATE)) {
289 icmsghdrp->status = HV_E_FAIL;
290 goto callback_done;
291 }
292
293 /* 402 /*
294 * Stash away this global state for completing the 403 * Stash away this global state for completing the
295 * transaction; note transactions are serialized. 404 * transaction; note transactions are serialized.
296 */ 405 */
406
297 kvp_transaction.recv_len = recvlen; 407 kvp_transaction.recv_len = recvlen;
298 kvp_transaction.recv_channel = channel; 408 kvp_transaction.recv_channel = channel;
299 kvp_transaction.recv_req_id = requestid; 409 kvp_transaction.recv_req_id = requestid;
300 kvp_transaction.active = true; 410 kvp_transaction.active = true;
301 kvp_transaction.index = kvp_data->index; 411 kvp_transaction.kvp_msg = kvp_msg;
302 412
303 /* 413 /*
304 * Get the information from the 414 * Get the information from the
@@ -316,8 +426,6 @@ void hv_kvp_onchannelcallback(void *context)
316 426
317 } 427 }
318 428
319callback_done:
320
321 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION 429 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
322 | ICMSGHDRFLAG_RESPONSE; 430 | ICMSGHDRFLAG_RESPONSE;
323 431
@@ -338,6 +446,14 @@ hv_kvp_init(struct hv_util_service *srv)
338 return err; 446 return err;
339 recv_buffer = srv->recv_buffer; 447 recv_buffer = srv->recv_buffer;
340 448
449 /*
450 * When this driver loads, the user level daemon that
451 * processes the host requests may not yet be running.
452 * Defer processing channel callbacks until the daemon
453 * has registered.
454 */
455 kvp_transaction.active = true;
456
341 return 0; 457 return 0;
342} 458}
343 459