aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2012-08-13 13:06:52 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-16 16:48:08 -0400
commitb47a81dcc5a806efb6d970608299129771588289 (patch)
tree59325254754b37e1b28393c552a854e4c922e243
parent9b5957803cb444a99275355eb2309b6fecc63c5f (diff)
Drivers: hv: kvp: Cleanup error handling in KVP
In preparation to implementing IP injection, cleanup the way we propagate and handle errors both in the driver as well as in the user level daemon. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> Reviewed-by: Olaf Hering <olaf@aepfle.de> Reviewed-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/hv/hv_kvp.c114
-rw-r--r--include/linux/hyperv.h17
-rw-r--r--tools/hv/hv_kvp_daemon.c66
3 files changed, 135 insertions, 62 deletions
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 0012eed6d872..eb4d0730f44d 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -48,13 +48,24 @@ static struct {
48 void *kvp_context; /* for the channel callback */ 48 void *kvp_context; /* for the channel callback */
49} kvp_transaction; 49} kvp_transaction;
50 50
51/*
52 * Before we can accept KVP messages from the host, we need
53 * to handshake with the user level daemon. This state tracks
54 * if we are in the handshake phase.
55 */
56static bool in_hand_shake = true;
57
58/*
59 * This state maintains the version number registered by the daemon.
60 */
61static int dm_reg_value;
62
51static void kvp_send_key(struct work_struct *dummy); 63static void kvp_send_key(struct work_struct *dummy);
52 64
53#define TIMEOUT_FIRED 1
54 65
55static void kvp_respond_to_host(char *key, char *value, int error); 66static void kvp_respond_to_host(char *key, char *value, int error);
56static void kvp_work_func(struct work_struct *dummy); 67static void kvp_work_func(struct work_struct *dummy);
57static void kvp_register(void); 68static void kvp_register(int);
58 69
59static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func); 70static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func);
60static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); 71static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
@@ -68,7 +79,7 @@ static u8 *recv_buffer;
68 */ 79 */
69 80
70static void 81static void
71kvp_register(void) 82kvp_register(int reg_value)
72{ 83{
73 84
74 struct cn_msg *msg; 85 struct cn_msg *msg;
@@ -83,7 +94,7 @@ kvp_register(void)
83 msg->id.idx = CN_KVP_IDX; 94 msg->id.idx = CN_KVP_IDX;
84 msg->id.val = CN_KVP_VAL; 95 msg->id.val = CN_KVP_VAL;
85 96
86 kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER; 97 kvp_msg->kvp_hdr.operation = reg_value;
87 strcpy(version, HV_DRV_VERSION); 98 strcpy(version, HV_DRV_VERSION);
88 msg->len = sizeof(struct hv_kvp_msg); 99 msg->len = sizeof(struct hv_kvp_msg);
89 cn_netlink_send(msg, 0, GFP_ATOMIC); 100 cn_netlink_send(msg, 0, GFP_ATOMIC);
@@ -97,9 +108,43 @@ kvp_work_func(struct work_struct *dummy)
97 * If the timer fires, the user-mode component has not responded; 108 * If the timer fires, the user-mode component has not responded;
98 * process the pending transaction. 109 * process the pending transaction.
99 */ 110 */
100 kvp_respond_to_host("Unknown key", "Guest timed out", TIMEOUT_FIRED); 111 kvp_respond_to_host("Unknown key", "Guest timed out", HV_E_FAIL);
112}
113
114static int kvp_handle_handshake(struct hv_kvp_msg *msg)
115{
116 int ret = 1;
117
118 switch (msg->kvp_hdr.operation) {
119 case KVP_OP_REGISTER:
120 dm_reg_value = KVP_OP_REGISTER;
121 pr_info("KVP: IP injection functionality not available\n");
122 pr_info("KVP: Upgrade the KVP daemon\n");
123 break;
124 case KVP_OP_REGISTER1:
125 dm_reg_value = KVP_OP_REGISTER1;
126 break;
127 default:
128 pr_info("KVP: incompatible daemon\n");
129 pr_info("KVP: KVP version: %d, Daemon version: %d\n",
130 KVP_OP_REGISTER1, msg->kvp_hdr.operation);
131 ret = 0;
132 }
133
134 if (ret) {
135 /*
136 * We have a compatible daemon; complete the handshake.
137 */
138 pr_info("KVP: user-mode registering done.\n");
139 kvp_register(dm_reg_value);
140 kvp_transaction.active = false;
141 if (kvp_transaction.kvp_context)
142 hv_kvp_onchannelcallback(kvp_transaction.kvp_context);
143 }
144 return ret;
101} 145}
102 146
147
103/* 148/*
104 * Callback when data is received from user mode. 149 * Callback when data is received from user mode.
105 */ 150 */
@@ -109,27 +154,52 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
109{ 154{
110 struct hv_kvp_msg *message; 155 struct hv_kvp_msg *message;
111 struct hv_kvp_msg_enumerate *data; 156 struct hv_kvp_msg_enumerate *data;
157 int error = 0;
112 158
113 message = (struct hv_kvp_msg *)msg->data; 159 message = (struct hv_kvp_msg *)msg->data;
114 switch (message->kvp_hdr.operation) { 160
161 /*
162 * If we are negotiating the version information
163 * with the daemon; handle that first.
164 */
165
166 if (in_hand_shake) {
167 if (kvp_handle_handshake(message))
168 in_hand_shake = false;
169 return;
170 }
171
172 /*
173 * Based on the version of the daemon, we propagate errors from the
174 * daemon differently.
175 */
176
177 data = &message->body.kvp_enum_data;
178
179 switch (dm_reg_value) {
115 case KVP_OP_REGISTER: 180 case KVP_OP_REGISTER:
116 pr_info("KVP: user-mode registering done.\n"); 181 /*
117 kvp_register(); 182 * Null string is used to pass back error condition.
118 kvp_transaction.active = false; 183 */
119 hv_kvp_onchannelcallback(kvp_transaction.kvp_context); 184 if (data->data.key[0] == 0)
185 error = HV_S_CONT;
120 break; 186 break;
121 187
122 default: 188 case KVP_OP_REGISTER1:
123 data = &message->body.kvp_enum_data;
124 /* 189 /*
125 * Complete the transaction by forwarding the key value 190 * We use the message header information from
126 * to the host. But first, cancel the timeout. 191 * the user level daemon to transmit errors.
127 */ 192 */
128 if (cancel_delayed_work_sync(&kvp_work)) 193 error = message->error;
129 kvp_respond_to_host(data->data.key, 194 break;
130 data->data.value,
131 !strlen(data->data.key));
132 } 195 }
196
197 /*
198 * Complete the transaction by forwarding the key value
199 * to the host. But first, cancel the timeout.
200 */
201 if (cancel_delayed_work_sync(&kvp_work))
202 kvp_respond_to_host(data->data.key, data->data.value, error);
133} 203}
134 204
135static void 205static void
@@ -287,6 +357,7 @@ kvp_respond_to_host(char *key, char *value, int error)
287 */ 357 */
288 return; 358 return;
289 359
360 icmsghdrp->status = error;
290 361
291 /* 362 /*
292 * If the error parameter is set, terminate the host's enumeration 363 * If the error parameter is set, terminate the host's enumeration
@@ -294,15 +365,12 @@ kvp_respond_to_host(char *key, char *value, int error)
294 */ 365 */
295 if (error) { 366 if (error) {
296 /* 367 /*
297 * Something failed or the we have timedout; 368 * Something failed or we have timedout;
298 * terminate the current host-side iteration. 369 * terminate the current host-side iteration.
299 */ 370 */
300 icmsghdrp->status = HV_S_CONT;
301 goto response_done; 371 goto response_done;
302 } 372 }
303 373
304 icmsghdrp->status = HV_S_OK;
305
306 kvp_msg = (struct hv_kvp_msg *) 374 kvp_msg = (struct hv_kvp_msg *)
307 &recv_buffer[sizeof(struct vmbuspipe_hdr) + 375 &recv_buffer[sizeof(struct vmbuspipe_hdr) +
308 sizeof(struct icmsg_hdr)]; 376 sizeof(struct icmsg_hdr)];
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 11afc4e0849a..b587c448e8ab 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -181,6 +181,17 @@ enum hv_kvp_exchg_pool {
181 KVP_POOL_COUNT /* Number of pools, must be last. */ 181 KVP_POOL_COUNT /* Number of pools, must be last. */
182}; 182};
183 183
184/*
185 * Some Hyper-V status codes.
186 */
187
188#define HV_S_OK 0x00000000
189#define HV_E_FAIL 0x80004005
190#define HV_S_CONT 0x80070103
191#define HV_ERROR_NOT_SUPPORTED 0x80070032
192#define HV_ERROR_MACHINE_LOCKED 0x800704F7
193#define HV_ERROR_DEVICE_NOT_CONNECTED 0x8007048F
194
184#define ADDR_FAMILY_NONE 0x00 195#define ADDR_FAMILY_NONE 0x00
185#define ADDR_FAMILY_IPV4 0x01 196#define ADDR_FAMILY_IPV4 0x01
186#define ADDR_FAMILY_IPV6 0x02 197#define ADDR_FAMILY_IPV6 0x02
@@ -1048,12 +1059,6 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver);
1048#define ICMSGHDRFLAG_REQUEST 2 1059#define ICMSGHDRFLAG_REQUEST 2
1049#define ICMSGHDRFLAG_RESPONSE 4 1060#define ICMSGHDRFLAG_RESPONSE 4
1050 1061
1051#define HV_S_OK 0x00000000
1052#define HV_E_FAIL 0x80004005
1053#define HV_S_CONT 0x80070103
1054#define HV_ERROR_NOT_SUPPORTED 0x80070032
1055#define HV_ERROR_MACHINE_LOCKED 0x800704F7
1056#define HV_ERROR_DEVICE_NOT_CONNECTED 0x8007048F
1057 1062
1058/* 1063/*
1059 * While we want to handle util services as regular devices, 1064 * While we want to handle util services as regular devices,
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 8fbcf7b3c69d..069e2b38decb 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -71,13 +71,14 @@ enum key_index {
71static char kvp_send_buffer[4096]; 71static char kvp_send_buffer[4096];
72static char kvp_recv_buffer[4096 * 2]; 72static char kvp_recv_buffer[4096 * 2];
73static struct sockaddr_nl addr; 73static struct sockaddr_nl addr;
74static int in_hand_shake = 1;
74 75
75static char *os_name = ""; 76static char *os_name = "";
76static char *os_major = ""; 77static char *os_major = "";
77static char *os_minor = ""; 78static char *os_minor = "";
78static char *processor_arch; 79static char *processor_arch;
79static char *os_build; 80static char *os_build;
80static char *lic_version; 81static char *lic_version = "Unknown version";
81static struct utsname uts_buf; 82static struct utsname uts_buf;
82 83
83 84
@@ -394,7 +395,7 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
394 return 1; 395 return 1;
395} 396}
396 397
397static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, 398static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
398 __u8 *value, int value_size) 399 __u8 *value, int value_size)
399{ 400{
400 struct kvp_record *record; 401 struct kvp_record *record;
@@ -406,16 +407,12 @@ static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
406 record = kvp_file_info[pool].records; 407 record = kvp_file_info[pool].records;
407 408
408 if (index >= kvp_file_info[pool].num_records) { 409 if (index >= kvp_file_info[pool].num_records) {
409 /* 410 return 1;
410 * This is an invalid index; terminate enumeration;
411 * - a NULL value will do the trick.
412 */
413 strcpy(value, "");
414 return;
415 } 411 }
416 412
417 memcpy(key, record[index].key, key_size); 413 memcpy(key, record[index].key, key_size);
418 memcpy(value, record[index].value, value_size); 414 memcpy(value, record[index].value, value_size);
415 return 0;
419} 416}
420 417
421 418
@@ -646,6 +643,8 @@ int main(void)
646 char *p; 643 char *p;
647 char *key_value; 644 char *key_value;
648 char *key_name; 645 char *key_name;
646 int op;
647 int pool;
649 648
650 daemon(1, 0); 649 daemon(1, 0);
651 openlog("KVP", 0, LOG_USER); 650 openlog("KVP", 0, LOG_USER);
@@ -687,7 +686,7 @@ int main(void)
687 message->id.val = CN_KVP_VAL; 686 message->id.val = CN_KVP_VAL;
688 687
689 hv_msg = (struct hv_kvp_msg *)message->data; 688 hv_msg = (struct hv_kvp_msg *)message->data;
690 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER; 689 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
691 message->ack = 0; 690 message->ack = 0;
692 message->len = sizeof(struct hv_kvp_msg); 691 message->len = sizeof(struct hv_kvp_msg);
693 692
@@ -721,12 +720,21 @@ int main(void)
721 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); 720 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
722 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; 721 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
723 722
724 switch (hv_msg->kvp_hdr.operation) { 723 /*
725 case KVP_OP_REGISTER: 724 * We will use the KVP header information to pass back
725 * the error from this daemon. So, first copy the state
726 * and set the error code to success.
727 */
728 op = hv_msg->kvp_hdr.operation;
729 pool = hv_msg->kvp_hdr.pool;
730 hv_msg->error = HV_S_OK;
731
732 if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
726 /* 733 /*
727 * Driver is registering with us; stash away the version 734 * Driver is registering with us; stash away the version
728 * information. 735 * information.
729 */ 736 */
737 in_hand_shake = 0;
730 p = (char *)hv_msg->body.kvp_register.version; 738 p = (char *)hv_msg->body.kvp_register.version;
731 lic_version = malloc(strlen(p) + 1); 739 lic_version = malloc(strlen(p) + 1);
732 if (lic_version) { 740 if (lic_version) {
@@ -737,44 +745,39 @@ int main(void)
737 syslog(LOG_ERR, "malloc failed"); 745 syslog(LOG_ERR, "malloc failed");
738 } 746 }
739 continue; 747 continue;
748 }
740 749
741 /* 750 switch (op) {
742 * The current protocol with the kernel component uses a
743 * NULL key name to pass an error condition.
744 * For the SET, GET and DELETE operations,
745 * use the existing protocol to pass back error.
746 */
747
748 case KVP_OP_SET: 751 case KVP_OP_SET:
749 if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool, 752 if (kvp_key_add_or_modify(pool,
750 hv_msg->body.kvp_set.data.key, 753 hv_msg->body.kvp_set.data.key,
751 hv_msg->body.kvp_set.data.key_size, 754 hv_msg->body.kvp_set.data.key_size,
752 hv_msg->body.kvp_set.data.value, 755 hv_msg->body.kvp_set.data.value,
753 hv_msg->body.kvp_set.data.value_size)) 756 hv_msg->body.kvp_set.data.value_size))
754 strcpy(hv_msg->body.kvp_set.data.key, ""); 757 hv_msg->error = HV_S_CONT;
755 break; 758 break;
756 759
757 case KVP_OP_GET: 760 case KVP_OP_GET:
758 if (kvp_get_value(hv_msg->kvp_hdr.pool, 761 if (kvp_get_value(pool,
759 hv_msg->body.kvp_set.data.key, 762 hv_msg->body.kvp_set.data.key,
760 hv_msg->body.kvp_set.data.key_size, 763 hv_msg->body.kvp_set.data.key_size,
761 hv_msg->body.kvp_set.data.value, 764 hv_msg->body.kvp_set.data.value,
762 hv_msg->body.kvp_set.data.value_size)) 765 hv_msg->body.kvp_set.data.value_size))
763 strcpy(hv_msg->body.kvp_set.data.key, ""); 766 hv_msg->error = HV_S_CONT;
764 break; 767 break;
765 768
766 case KVP_OP_DELETE: 769 case KVP_OP_DELETE:
767 if (kvp_key_delete(hv_msg->kvp_hdr.pool, 770 if (kvp_key_delete(pool,
768 hv_msg->body.kvp_delete.key, 771 hv_msg->body.kvp_delete.key,
769 hv_msg->body.kvp_delete.key_size)) 772 hv_msg->body.kvp_delete.key_size))
770 strcpy(hv_msg->body.kvp_delete.key, ""); 773 hv_msg->error = HV_S_CONT;
771 break; 774 break;
772 775
773 default: 776 default:
774 break; 777 break;
775 } 778 }
776 779
777 if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE) 780 if (op != KVP_OP_ENUMERATE)
778 goto kvp_done; 781 goto kvp_done;
779 782
780 /* 783 /*
@@ -782,13 +785,14 @@ int main(void)
782 * both the key and the value; if not read from the 785 * both the key and the value; if not read from the
783 * appropriate pool. 786 * appropriate pool.
784 */ 787 */
785 if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) { 788 if (pool != KVP_POOL_AUTO) {
786 kvp_pool_enumerate(hv_msg->kvp_hdr.pool, 789 if (kvp_pool_enumerate(pool,
787 hv_msg->body.kvp_enum_data.index, 790 hv_msg->body.kvp_enum_data.index,
788 hv_msg->body.kvp_enum_data.data.key, 791 hv_msg->body.kvp_enum_data.data.key,
789 HV_KVP_EXCHANGE_MAX_KEY_SIZE, 792 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
790 hv_msg->body.kvp_enum_data.data.value, 793 hv_msg->body.kvp_enum_data.data.value,
791 HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 794 HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
795 hv_msg->error = HV_S_CONT;
792 goto kvp_done; 796 goto kvp_done;
793 } 797 }
794 798
@@ -841,11 +845,7 @@ int main(void)
841 strcpy(key_name, "ProcessorArchitecture"); 845 strcpy(key_name, "ProcessorArchitecture");
842 break; 846 break;
843 default: 847 default:
844 strcpy(key_value, "Unknown Key"); 848 hv_msg->error = HV_S_CONT;
845 /*
846 * We use a null key name to terminate enumeration.
847 */
848 strcpy(key_name, "");
849 break; 849 break;
850 } 850 }
851 /* 851 /*