diff options
Diffstat (limited to 'drivers/hv')
-rw-r--r-- | drivers/hv/hv_kvp.c | 218 |
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 @@ | |||
42 | static struct { | 42 | static 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 | ||
50 | static void kvp_send_key(struct work_struct *dummy); | 51 | static 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 | |||
159 | kvp_respond_to_host(char *key, char *value, int error) | 246 | kvp_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 | |||
336 | copy_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 | ||
235 | response_done: | 351 | response_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 | ||
319 | callback_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 | ||