diff options
Diffstat (limited to 'drivers/hv')
-rw-r--r-- | drivers/hv/channel_mgmt.c | 87 | ||||
-rw-r--r-- | drivers/hv/hv.c | 4 | ||||
-rw-r--r-- | drivers/hv/hv_kvp.c | 253 | ||||
-rw-r--r-- | drivers/hv/hv_kvp.h | 184 | ||||
-rw-r--r-- | drivers/hv/hv_util.c | 3 | ||||
-rw-r--r-- | drivers/hv/hyperv_vmbus.h | 5 |
6 files changed, 193 insertions, 343 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 36484db36baf..9ffbfc575a0c 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c | |||
@@ -37,81 +37,6 @@ struct vmbus_channel_message_table_entry { | |||
37 | void (*message_handler)(struct vmbus_channel_message_header *msg); | 37 | void (*message_handler)(struct vmbus_channel_message_header *msg); |
38 | }; | 38 | }; |
39 | 39 | ||
40 | #define MAX_MSG_TYPES 4 | ||
41 | #define MAX_NUM_DEVICE_CLASSES_SUPPORTED 8 | ||
42 | |||
43 | static const uuid_le | ||
44 | supported_device_classes[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = { | ||
45 | /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */ | ||
46 | /* Storage - SCSI */ | ||
47 | { | ||
48 | .b = { | ||
49 | 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, | ||
50 | 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f | ||
51 | } | ||
52 | }, | ||
53 | |||
54 | /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ | ||
55 | /* Network */ | ||
56 | { | ||
57 | .b = { | ||
58 | 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, | ||
59 | 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E | ||
60 | } | ||
61 | }, | ||
62 | |||
63 | /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */ | ||
64 | /* Input */ | ||
65 | { | ||
66 | .b = { | ||
67 | 0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c, | ||
68 | 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A | ||
69 | } | ||
70 | }, | ||
71 | |||
72 | /* {32412632-86cb-44a2-9b5c-50d1417354f5} */ | ||
73 | /* IDE */ | ||
74 | { | ||
75 | .b = { | ||
76 | 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, | ||
77 | 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5 | ||
78 | } | ||
79 | }, | ||
80 | /* 0E0B6031-5213-4934-818B-38D90CED39DB */ | ||
81 | /* Shutdown */ | ||
82 | { | ||
83 | .b = { | ||
84 | 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49, | ||
85 | 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB | ||
86 | } | ||
87 | }, | ||
88 | /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */ | ||
89 | /* TimeSync */ | ||
90 | { | ||
91 | .b = { | ||
92 | 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49, | ||
93 | 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf | ||
94 | } | ||
95 | }, | ||
96 | /* {57164f39-9115-4e78-ab55-382f3bd5422d} */ | ||
97 | /* Heartbeat */ | ||
98 | { | ||
99 | .b = { | ||
100 | 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e, | ||
101 | 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d | ||
102 | } | ||
103 | }, | ||
104 | /* {A9A0F4E7-5A45-4d96-B827-8A841E8C03E6} */ | ||
105 | /* KVP */ | ||
106 | { | ||
107 | .b = { | ||
108 | 0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d, | ||
109 | 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6 | ||
110 | } | ||
111 | }, | ||
112 | |||
113 | }; | ||
114 | |||
115 | 40 | ||
116 | /** | 41 | /** |
117 | * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message | 42 | * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message |
@@ -321,20 +246,8 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) | |||
321 | struct vmbus_channel *newchannel; | 246 | struct vmbus_channel *newchannel; |
322 | uuid_le *guidtype; | 247 | uuid_le *guidtype; |
323 | uuid_le *guidinstance; | 248 | uuid_le *guidinstance; |
324 | int i; | ||
325 | int fsupported = 0; | ||
326 | 249 | ||
327 | offer = (struct vmbus_channel_offer_channel *)hdr; | 250 | offer = (struct vmbus_channel_offer_channel *)hdr; |
328 | for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) { | ||
329 | if (!uuid_le_cmp(offer->offer.if_type, | ||
330 | supported_device_classes[i])) { | ||
331 | fsupported = 1; | ||
332 | break; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | if (!fsupported) | ||
337 | return; | ||
338 | 251 | ||
339 | guidtype = &offer->offer.if_type; | 252 | guidtype = &offer->offer.if_type; |
340 | guidinstance = &offer->offer.if_instance; | 253 | guidinstance = &offer->offer.if_instance; |
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 12aa97f31f93..15956bd48b48 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c | |||
@@ -155,9 +155,9 @@ int hv_init(void) | |||
155 | union hv_x64_msr_hypercall_contents hypercall_msr; | 155 | union hv_x64_msr_hypercall_contents hypercall_msr; |
156 | void *virtaddr = NULL; | 156 | void *virtaddr = NULL; |
157 | 157 | ||
158 | memset(hv_context.synic_event_page, 0, sizeof(void *) * MAX_NUM_CPUS); | 158 | memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS); |
159 | memset(hv_context.synic_message_page, 0, | 159 | memset(hv_context.synic_message_page, 0, |
160 | sizeof(void *) * MAX_NUM_CPUS); | 160 | sizeof(void *) * NR_CPUS); |
161 | 161 | ||
162 | if (!query_hypervisor_presence()) | 162 | if (!query_hypervisor_presence()) |
163 | goto cleanup; | 163 | goto cleanup; |
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index 0e8343f585bb..6186025209ce 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c | |||
@@ -28,8 +28,6 @@ | |||
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/hyperv.h> | 29 | #include <linux/hyperv.h> |
30 | 30 | ||
31 | #include "hv_kvp.h" | ||
32 | |||
33 | 31 | ||
34 | 32 | ||
35 | /* | 33 | /* |
@@ -44,9 +42,10 @@ | |||
44 | static struct { | 42 | static struct { |
45 | bool active; /* transaction status - active or not */ | 43 | bool active; /* transaction status - active or not */ |
46 | int recv_len; /* number of bytes received. */ | 44 | int recv_len; /* number of bytes received. */ |
47 | int index; /* current index */ | 45 | struct hv_kvp_msg *kvp_msg; /* current message */ |
48 | struct vmbus_channel *recv_channel; /* chn we got the request */ | 46 | struct vmbus_channel *recv_channel; /* chn we got the request */ |
49 | u64 recv_req_id; /* request ID. */ | 47 | u64 recv_req_id; /* request ID. */ |
48 | void *kvp_context; /* for the channel callback */ | ||
50 | } kvp_transaction; | 49 | } kvp_transaction; |
51 | 50 | ||
52 | static void kvp_send_key(struct work_struct *dummy); | 51 | static void kvp_send_key(struct work_struct *dummy); |
@@ -73,15 +72,20 @@ kvp_register(void) | |||
73 | { | 72 | { |
74 | 73 | ||
75 | struct cn_msg *msg; | 74 | struct cn_msg *msg; |
75 | struct hv_kvp_msg *kvp_msg; | ||
76 | char *version; | ||
76 | 77 | ||
77 | msg = kzalloc(sizeof(*msg) + strlen(HV_DRV_VERSION) + 1 , GFP_ATOMIC); | 78 | msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg), GFP_ATOMIC); |
78 | 79 | ||
79 | if (msg) { | 80 | if (msg) { |
81 | kvp_msg = (struct hv_kvp_msg *)msg->data; | ||
82 | version = kvp_msg->body.kvp_register.version; | ||
80 | msg->id.idx = CN_KVP_IDX; | 83 | msg->id.idx = CN_KVP_IDX; |
81 | msg->id.val = CN_KVP_VAL; | 84 | msg->id.val = CN_KVP_VAL; |
82 | msg->seq = KVP_REGISTER; | 85 | |
83 | strcpy(msg->data, HV_DRV_VERSION); | 86 | kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER; |
84 | msg->len = strlen(HV_DRV_VERSION) + 1; | 87 | strcpy(version, HV_DRV_VERSION); |
88 | msg->len = sizeof(struct hv_kvp_msg); | ||
85 | cn_netlink_send(msg, 0, GFP_ATOMIC); | 89 | cn_netlink_send(msg, 0, GFP_ATOMIC); |
86 | kfree(msg); | 90 | kfree(msg); |
87 | } | 91 | } |
@@ -103,23 +107,28 @@ kvp_work_func(struct work_struct *dummy) | |||
103 | static void | 107 | static void |
104 | kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | 108 | kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) |
105 | { | 109 | { |
106 | struct hv_ku_msg *message; | 110 | struct hv_kvp_msg *message; |
111 | struct hv_kvp_msg_enumerate *data; | ||
107 | 112 | ||
108 | message = (struct hv_ku_msg *)msg->data; | 113 | message = (struct hv_kvp_msg *)msg->data; |
109 | if (msg->seq == KVP_REGISTER) { | 114 | switch (message->kvp_hdr.operation) { |
115 | case KVP_OP_REGISTER: | ||
110 | pr_info("KVP: user-mode registering done.\n"); | 116 | pr_info("KVP: user-mode registering done.\n"); |
111 | kvp_register(); | 117 | kvp_register(); |
112 | } | 118 | kvp_transaction.active = false; |
119 | hv_kvp_onchannelcallback(kvp_transaction.kvp_context); | ||
120 | break; | ||
113 | 121 | ||
114 | if (msg->seq == KVP_USER_SET) { | 122 | default: |
123 | data = &message->body.kvp_enum_data; | ||
115 | /* | 124 | /* |
116 | * Complete the transaction by forwarding the key value | 125 | * Complete the transaction by forwarding the key value |
117 | * to the host. But first, cancel the timeout. | 126 | * to the host. But first, cancel the timeout. |
118 | */ | 127 | */ |
119 | if (cancel_delayed_work_sync(&kvp_work)) | 128 | if (cancel_delayed_work_sync(&kvp_work)) |
120 | kvp_respond_to_host(message->kvp_key, | 129 | kvp_respond_to_host(data->data.key, |
121 | message->kvp_value, | 130 | data->data.value, |
122 | !strlen(message->kvp_key)); | 131 | !strlen(data->data.key)); |
123 | } | 132 | } |
124 | } | 133 | } |
125 | 134 | ||
@@ -127,19 +136,105 @@ static void | |||
127 | kvp_send_key(struct work_struct *dummy) | 136 | kvp_send_key(struct work_struct *dummy) |
128 | { | 137 | { |
129 | struct cn_msg *msg; | 138 | struct cn_msg *msg; |
130 | int index = kvp_transaction.index; | 139 | struct hv_kvp_msg *message; |
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; | ||
131 | 145 | ||
132 | 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; | ||
133 | 149 | ||
134 | if (msg) { | 150 | msg->id.idx = CN_KVP_IDX; |
135 | msg->id.idx = CN_KVP_IDX; | 151 | msg->id.val = CN_KVP_VAL; |
136 | msg->id.val = CN_KVP_VAL; | 152 | |
137 | msg->seq = KVP_KERNEL_GET; | 153 | message = (struct hv_kvp_msg *)msg->data; |
138 | ((struct hv_ku_msg *)msg->data)->kvp_index = index; | 154 | message->kvp_hdr.operation = operation; |
139 | msg->len = sizeof(struct hv_ku_msg); | 155 | message->kvp_hdr.pool = pool; |
140 | cn_netlink_send(msg, 0, GFP_ATOMIC); | 156 | in_msg = kvp_transaction.kvp_msg; |
141 | kfree(msg); | 157 | |
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; | ||
142 | } | 232 | } |
233 | |||
234 | msg->len = sizeof(struct hv_kvp_msg); | ||
235 | cn_netlink_send(msg, 0, GFP_ATOMIC); | ||
236 | kfree(msg); | ||
237 | |||
143 | return; | 238 | return; |
144 | } | 239 | } |
145 | 240 | ||
@@ -151,10 +246,11 @@ static void | |||
151 | kvp_respond_to_host(char *key, char *value, int error) | 246 | kvp_respond_to_host(char *key, char *value, int error) |
152 | { | 247 | { |
153 | struct hv_kvp_msg *kvp_msg; | 248 | struct hv_kvp_msg *kvp_msg; |
154 | struct hv_kvp_msg_enumerate *kvp_data; | 249 | struct hv_kvp_exchg_msg_value *kvp_data; |
155 | char *key_name; | 250 | char *key_name; |
156 | struct icmsg_hdr *icmsghdrp; | 251 | struct icmsg_hdr *icmsghdrp; |
157 | int keylen, valuelen; | 252 | int keylen = 0; |
253 | int valuelen = 0; | ||
158 | u32 buf_len; | 254 | u32 buf_len; |
159 | struct vmbus_channel *channel; | 255 | struct vmbus_channel *channel; |
160 | u64 req_id; | 256 | u64 req_id; |
@@ -181,6 +277,9 @@ kvp_respond_to_host(char *key, char *value, int error) | |||
181 | 277 | ||
182 | kvp_transaction.active = false; | 278 | kvp_transaction.active = false; |
183 | 279 | ||
280 | icmsghdrp = (struct icmsg_hdr *) | ||
281 | &recv_buffer[sizeof(struct vmbuspipe_hdr)]; | ||
282 | |||
184 | if (channel->onchannel_callback == NULL) | 283 | if (channel->onchannel_callback == NULL) |
185 | /* | 284 | /* |
186 | * We have raced with util driver being unloaded; | 285 | * We have raced with util driver being unloaded; |
@@ -188,41 +287,67 @@ kvp_respond_to_host(char *key, char *value, int error) | |||
188 | */ | 287 | */ |
189 | return; | 288 | return; |
190 | 289 | ||
191 | icmsghdrp = (struct icmsg_hdr *) | ||
192 | &recv_buffer[sizeof(struct vmbuspipe_hdr)]; | ||
193 | kvp_msg = (struct hv_kvp_msg *) | ||
194 | &recv_buffer[sizeof(struct vmbuspipe_hdr) + | ||
195 | sizeof(struct icmsg_hdr)]; | ||
196 | kvp_data = &kvp_msg->kvp_data; | ||
197 | key_name = key; | ||
198 | 290 | ||
199 | /* | 291 | /* |
200 | * If the error parameter is set, terminate the host's enumeration. | 292 | * If the error parameter is set, terminate the host's enumeration |
293 | * on this pool. | ||
201 | */ | 294 | */ |
202 | if (error) { | 295 | if (error) { |
203 | /* | 296 | /* |
204 | * We don't support this index or the we have timedout; | 297 | * Something failed or the we have timedout; |
205 | * terminate the host-side iteration by returning an error. | 298 | * terminate the current host-side iteration. |
206 | */ | 299 | */ |
207 | icmsghdrp->status = HV_E_FAIL; | 300 | icmsghdrp->status = HV_S_CONT; |
208 | goto response_done; | 301 | goto response_done; |
209 | } | 302 | } |
210 | 303 | ||
304 | icmsghdrp->status = HV_S_OK; | ||
305 | |||
306 | kvp_msg = (struct hv_kvp_msg *) | ||
307 | &recv_buffer[sizeof(struct vmbuspipe_hdr) + | ||
308 | sizeof(struct icmsg_hdr)]; | ||
309 | |||
310 | switch (kvp_transaction.kvp_msg->kvp_hdr.operation) { | ||
311 | case KVP_OP_GET: | ||
312 | kvp_data = &kvp_msg->body.kvp_get.data; | ||
313 | goto copy_value; | ||
314 | |||
315 | case KVP_OP_SET: | ||
316 | case KVP_OP_DELETE: | ||
317 | goto response_done; | ||
318 | |||
319 | default: | ||
320 | break; | ||
321 | } | ||
322 | |||
323 | kvp_data = &kvp_msg->body.kvp_enum_data.data; | ||
324 | key_name = key; | ||
325 | |||
211 | /* | 326 | /* |
212 | * The windows host expects the key/value pair to be encoded | 327 | * The windows host expects the key/value pair to be encoded |
213 | * in utf16. | 328 | * in utf16. Ensure that the key/value size reported to the host |
329 | * will be less than or equal to the MAX size (including the | ||
330 | * terminating character). | ||
214 | */ | 331 | */ |
215 | keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN, | 332 | keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN, |
216 | (wchar_t *) kvp_data->data.key, | 333 | (wchar_t *) kvp_data->key, |
217 | HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2); | 334 | (HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2) - 2); |
218 | kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */ | 335 | kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */ |
336 | |||
337 | copy_value: | ||
219 | valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN, | 338 | valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN, |
220 | (wchar_t *) kvp_data->data.value, | 339 | (wchar_t *) kvp_data->value, |
221 | HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2); | 340 | (HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2); |
222 | kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */ | 341 | kvp_data->value_size = 2*(valuelen + 1); /* utf16 encoding */ |
223 | 342 | ||
224 | kvp_data->data.value_type = REG_SZ; /* all our values are strings */ | 343 | /* |
225 | icmsghdrp->status = HV_S_OK; | 344 | * If the utf8s to utf16s conversion failed; notify host |
345 | * of the error. | ||
346 | */ | ||
347 | if ((keylen < 0) || (valuelen < 0)) | ||
348 | icmsghdrp->status = HV_E_FAIL; | ||
349 | |||
350 | kvp_data->value_type = REG_SZ; /* all our values are strings */ | ||
226 | 351 | ||
227 | response_done: | 352 | response_done: |
228 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; | 353 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; |
@@ -249,11 +374,18 @@ void hv_kvp_onchannelcallback(void *context) | |||
249 | u64 requestid; | 374 | u64 requestid; |
250 | 375 | ||
251 | struct hv_kvp_msg *kvp_msg; | 376 | struct hv_kvp_msg *kvp_msg; |
252 | struct hv_kvp_msg_enumerate *kvp_data; | ||
253 | 377 | ||
254 | struct icmsg_hdr *icmsghdrp; | 378 | struct icmsg_hdr *icmsghdrp; |
255 | struct icmsg_negotiate *negop = NULL; | 379 | struct icmsg_negotiate *negop = NULL; |
256 | 380 | ||
381 | if (kvp_transaction.active) { | ||
382 | /* | ||
383 | * We will defer processing this callback once | ||
384 | * the current transaction is complete. | ||
385 | */ | ||
386 | kvp_transaction.kvp_context = context; | ||
387 | return; | ||
388 | } | ||
257 | 389 | ||
258 | vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid); | 390 | vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid); |
259 | 391 | ||
@@ -268,29 +400,16 @@ void hv_kvp_onchannelcallback(void *context) | |||
268 | sizeof(struct vmbuspipe_hdr) + | 400 | sizeof(struct vmbuspipe_hdr) + |
269 | sizeof(struct icmsg_hdr)]; | 401 | sizeof(struct icmsg_hdr)]; |
270 | 402 | ||
271 | kvp_data = &kvp_msg->kvp_data; | ||
272 | |||
273 | /* | ||
274 | * We only support the "get" operation on | ||
275 | * "KVP_POOL_AUTO" pool. | ||
276 | */ | ||
277 | |||
278 | if ((kvp_msg->kvp_hdr.pool != KVP_POOL_AUTO) || | ||
279 | (kvp_msg->kvp_hdr.operation != | ||
280 | KVP_OP_ENUMERATE)) { | ||
281 | icmsghdrp->status = HV_E_FAIL; | ||
282 | goto callback_done; | ||
283 | } | ||
284 | |||
285 | /* | 403 | /* |
286 | * Stash away this global state for completing the | 404 | * Stash away this global state for completing the |
287 | * transaction; note transactions are serialized. | 405 | * transaction; note transactions are serialized. |
288 | */ | 406 | */ |
407 | |||
289 | kvp_transaction.recv_len = recvlen; | 408 | kvp_transaction.recv_len = recvlen; |
290 | kvp_transaction.recv_channel = channel; | 409 | kvp_transaction.recv_channel = channel; |
291 | kvp_transaction.recv_req_id = requestid; | 410 | kvp_transaction.recv_req_id = requestid; |
292 | kvp_transaction.active = true; | 411 | kvp_transaction.active = true; |
293 | kvp_transaction.index = kvp_data->index; | 412 | kvp_transaction.kvp_msg = kvp_msg; |
294 | 413 | ||
295 | /* | 414 | /* |
296 | * Get the information from the | 415 | * Get the information from the |
@@ -308,8 +427,6 @@ void hv_kvp_onchannelcallback(void *context) | |||
308 | 427 | ||
309 | } | 428 | } |
310 | 429 | ||
311 | callback_done: | ||
312 | |||
313 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | 430 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION |
314 | | ICMSGHDRFLAG_RESPONSE; | 431 | | ICMSGHDRFLAG_RESPONSE; |
315 | 432 | ||
@@ -330,6 +447,14 @@ hv_kvp_init(struct hv_util_service *srv) | |||
330 | return err; | 447 | return err; |
331 | recv_buffer = srv->recv_buffer; | 448 | recv_buffer = srv->recv_buffer; |
332 | 449 | ||
450 | /* | ||
451 | * When this driver loads, the user level daemon that | ||
452 | * processes the host requests may not yet be running. | ||
453 | * Defer processing channel callbacks until the daemon | ||
454 | * has registered. | ||
455 | */ | ||
456 | kvp_transaction.active = true; | ||
457 | |||
333 | return 0; | 458 | return 0; |
334 | } | 459 | } |
335 | 460 | ||
diff --git a/drivers/hv/hv_kvp.h b/drivers/hv/hv_kvp.h deleted file mode 100644 index 9b765d7df838..000000000000 --- a/drivers/hv/hv_kvp.h +++ /dev/null | |||
@@ -1,184 +0,0 @@ | |||
1 | /* | ||
2 | * An implementation of HyperV key value pair (KVP) functionality for Linux. | ||
3 | * | ||
4 | * | ||
5 | * Copyright (C) 2010, Novell, Inc. | ||
6 | * Author : K. Y. Srinivasan <ksrinivasan@novell.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published | ||
10 | * by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
15 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
16 | * details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | * | ||
22 | */ | ||
23 | #ifndef _KVP_H | ||
24 | #define _KVP_H_ | ||
25 | |||
26 | /* | ||
27 | * Maximum value size - used for both key names and value data, and includes | ||
28 | * any applicable NULL terminators. | ||
29 | * | ||
30 | * Note: This limit is somewhat arbitrary, but falls easily within what is | ||
31 | * supported for all native guests (back to Win 2000) and what is reasonable | ||
32 | * for the IC KVP exchange functionality. Note that Windows Me/98/95 are | ||
33 | * limited to 255 character key names. | ||
34 | * | ||
35 | * MSDN recommends not storing data values larger than 2048 bytes in the | ||
36 | * registry. | ||
37 | * | ||
38 | * Note: This value is used in defining the KVP exchange message - this value | ||
39 | * cannot be modified without affecting the message size and compatibility. | ||
40 | */ | ||
41 | |||
42 | /* | ||
43 | * bytes, including any null terminators | ||
44 | */ | ||
45 | #define HV_KVP_EXCHANGE_MAX_VALUE_SIZE (2048) | ||
46 | |||
47 | |||
48 | /* | ||
49 | * Maximum key size - the registry limit for the length of an entry name | ||
50 | * is 256 characters, including the null terminator | ||
51 | */ | ||
52 | |||
53 | #define HV_KVP_EXCHANGE_MAX_KEY_SIZE (512) | ||
54 | |||
55 | /* | ||
56 | * In Linux, we implement the KVP functionality in two components: | ||
57 | * 1) The kernel component which is packaged as part of the hv_utils driver | ||
58 | * is responsible for communicating with the host and responsible for | ||
59 | * implementing the host/guest protocol. 2) A user level daemon that is | ||
60 | * responsible for data gathering. | ||
61 | * | ||
62 | * Host/Guest Protocol: The host iterates over an index and expects the guest | ||
63 | * to assign a key name to the index and also return the value corresponding to | ||
64 | * the key. The host will have atmost one KVP transaction outstanding at any | ||
65 | * given point in time. The host side iteration stops when the guest returns | ||
66 | * an error. Microsoft has specified the following mapping of key names to | ||
67 | * host specified index: | ||
68 | * | ||
69 | * Index Key Name | ||
70 | * 0 FullyQualifiedDomainName | ||
71 | * 1 IntegrationServicesVersion | ||
72 | * 2 NetworkAddressIPv4 | ||
73 | * 3 NetworkAddressIPv6 | ||
74 | * 4 OSBuildNumber | ||
75 | * 5 OSName | ||
76 | * 6 OSMajorVersion | ||
77 | * 7 OSMinorVersion | ||
78 | * 8 OSVersion | ||
79 | * 9 ProcessorArchitecture | ||
80 | * | ||
81 | * The Windows host expects the Key Name and Key Value to be encoded in utf16. | ||
82 | * | ||
83 | * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the | ||
84 | * data gathering functionality in a user mode daemon. The user level daemon | ||
85 | * is also responsible for binding the key name to the index as well. The | ||
86 | * kernel and user-level daemon communicate using a connector channel. | ||
87 | * | ||
88 | * The user mode component first registers with the | ||
89 | * the kernel component. Subsequently, the kernel component requests, data | ||
90 | * for the specified keys. In response to this message the user mode component | ||
91 | * fills in the value corresponding to the specified key. We overload the | ||
92 | * sequence field in the cn_msg header to define our KVP message types. | ||
93 | * | ||
94 | * | ||
95 | * The kernel component simply acts as a conduit for communication between the | ||
96 | * Windows host and the user-level daemon. The kernel component passes up the | ||
97 | * index received from the Host to the user-level daemon. If the index is | ||
98 | * valid (supported), the corresponding key as well as its | ||
99 | * value (both are strings) is returned. If the index is invalid | ||
100 | * (not supported), a NULL key string is returned. | ||
101 | */ | ||
102 | |||
103 | /* | ||
104 | * | ||
105 | * The following definitions are shared with the user-mode component; do not | ||
106 | * change any of this without making the corresponding changes in | ||
107 | * the KVP user-mode component. | ||
108 | */ | ||
109 | |||
110 | #define CN_KVP_VAL 0x1 /* This supports queries from the kernel */ | ||
111 | #define CN_KVP_USER_VAL 0x2 /* This supports queries from the user */ | ||
112 | |||
113 | enum hv_ku_op { | ||
114 | KVP_REGISTER = 0, /* Register the user mode component */ | ||
115 | KVP_KERNEL_GET, /* Kernel is requesting the value */ | ||
116 | KVP_KERNEL_SET, /* Kernel is providing the value */ | ||
117 | KVP_USER_GET, /* User is requesting the value */ | ||
118 | KVP_USER_SET /* User is providing the value */ | ||
119 | }; | ||
120 | |||
121 | struct hv_ku_msg { | ||
122 | __u32 kvp_index; /* Key index */ | ||
123 | __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */ | ||
124 | __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */ | ||
125 | }; | ||
126 | |||
127 | |||
128 | |||
129 | |||
130 | #ifdef __KERNEL__ | ||
131 | |||
132 | /* | ||
133 | * Registry value types. | ||
134 | */ | ||
135 | |||
136 | #define REG_SZ 1 | ||
137 | |||
138 | enum hv_kvp_exchg_op { | ||
139 | KVP_OP_GET = 0, | ||
140 | KVP_OP_SET, | ||
141 | KVP_OP_DELETE, | ||
142 | KVP_OP_ENUMERATE, | ||
143 | KVP_OP_COUNT /* Number of operations, must be last. */ | ||
144 | }; | ||
145 | |||
146 | enum hv_kvp_exchg_pool { | ||
147 | KVP_POOL_EXTERNAL = 0, | ||
148 | KVP_POOL_GUEST, | ||
149 | KVP_POOL_AUTO, | ||
150 | KVP_POOL_AUTO_EXTERNAL, | ||
151 | KVP_POOL_AUTO_INTERNAL, | ||
152 | KVP_POOL_COUNT /* Number of pools, must be last. */ | ||
153 | }; | ||
154 | |||
155 | struct hv_kvp_hdr { | ||
156 | u8 operation; | ||
157 | u8 pool; | ||
158 | }; | ||
159 | |||
160 | struct hv_kvp_exchg_msg_value { | ||
161 | u32 value_type; | ||
162 | u32 key_size; | ||
163 | u32 value_size; | ||
164 | u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; | ||
165 | u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; | ||
166 | }; | ||
167 | |||
168 | struct hv_kvp_msg_enumerate { | ||
169 | u32 index; | ||
170 | struct hv_kvp_exchg_msg_value data; | ||
171 | }; | ||
172 | |||
173 | struct hv_kvp_msg { | ||
174 | struct hv_kvp_hdr kvp_hdr; | ||
175 | struct hv_kvp_msg_enumerate kvp_data; | ||
176 | }; | ||
177 | |||
178 | int hv_kvp_init(struct hv_util_service *); | ||
179 | void hv_kvp_deinit(void); | ||
180 | void hv_kvp_onchannelcallback(void *); | ||
181 | |||
182 | #endif /* __KERNEL__ */ | ||
183 | #endif /* _KVP_H */ | ||
184 | |||
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 55d58f21e6d4..dbb8b8eec210 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c | |||
@@ -28,9 +28,6 @@ | |||
28 | #include <linux/reboot.h> | 28 | #include <linux/reboot.h> |
29 | #include <linux/hyperv.h> | 29 | #include <linux/hyperv.h> |
30 | 30 | ||
31 | #include "hv_kvp.h" | ||
32 | |||
33 | |||
34 | static void shutdown_onchannelcallback(void *context); | 31 | static void shutdown_onchannelcallback(void *context); |
35 | static struct hv_util_service util_shutdown = { | 32 | static struct hv_util_service util_shutdown = { |
36 | .util_cb = shutdown_onchannelcallback, | 33 | .util_cb = shutdown_onchannelcallback, |
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 6d7d286d5440..699f0d8e59ed 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h | |||
@@ -457,7 +457,6 @@ static const uuid_le VMBUS_SERVICE_ID = { | |||
457 | }, | 457 | }, |
458 | }; | 458 | }; |
459 | 459 | ||
460 | #define MAX_NUM_CPUS 32 | ||
461 | 460 | ||
462 | 461 | ||
463 | struct hv_input_signal_event_buffer { | 462 | struct hv_input_signal_event_buffer { |
@@ -483,8 +482,8 @@ struct hv_context { | |||
483 | /* 8-bytes aligned of the buffer above */ | 482 | /* 8-bytes aligned of the buffer above */ |
484 | struct hv_input_signal_event *signal_event_param; | 483 | struct hv_input_signal_event *signal_event_param; |
485 | 484 | ||
486 | void *synic_message_page[MAX_NUM_CPUS]; | 485 | void *synic_message_page[NR_CPUS]; |
487 | void *synic_event_page[MAX_NUM_CPUS]; | 486 | void *synic_event_page[NR_CPUS]; |
488 | }; | 487 | }; |
489 | 488 | ||
490 | extern struct hv_context hv_context; | 489 | extern struct hv_context hv_context; |