aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hv
diff options
context:
space:
mode:
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