diff options
| -rw-r--r-- | drivers/hv/hv_snapshot.c | 49 | ||||
| -rw-r--r-- | include/uapi/linux/hyperv.h | 5 | ||||
| -rw-r--r-- | tools/hv/hv_vss_daemon.c | 14 |
3 files changed, 56 insertions, 12 deletions
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index 2c8c246d09eb..ee1762b39bf2 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c | |||
| @@ -59,6 +59,11 @@ static struct { | |||
| 59 | 59 | ||
| 60 | static void vss_respond_to_host(int error); | 60 | static void vss_respond_to_host(int error); |
| 61 | 61 | ||
| 62 | /* | ||
| 63 | * This state maintains the version number registered by the daemon. | ||
| 64 | */ | ||
| 65 | static int dm_reg_value; | ||
| 66 | |||
| 62 | static const char vss_devname[] = "vmbus/hv_vss"; | 67 | static const char vss_devname[] = "vmbus/hv_vss"; |
| 63 | static __u8 *recv_buffer; | 68 | static __u8 *recv_buffer; |
| 64 | static struct hvutil_transport *hvt; | 69 | static struct hvutil_transport *hvt; |
| @@ -89,6 +94,29 @@ static void vss_timeout_func(struct work_struct *dummy) | |||
| 89 | hv_vss_onchannelcallback); | 94 | hv_vss_onchannelcallback); |
| 90 | } | 95 | } |
| 91 | 96 | ||
| 97 | static int vss_handle_handshake(struct hv_vss_msg *vss_msg) | ||
| 98 | { | ||
| 99 | u32 our_ver = VSS_OP_REGISTER1; | ||
| 100 | |||
| 101 | switch (vss_msg->vss_hdr.operation) { | ||
| 102 | case VSS_OP_REGISTER: | ||
| 103 | /* Daemon doesn't expect us to reply */ | ||
| 104 | dm_reg_value = VSS_OP_REGISTER; | ||
| 105 | break; | ||
| 106 | case VSS_OP_REGISTER1: | ||
| 107 | /* Daemon expects us to reply with our own version*/ | ||
| 108 | if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver))) | ||
| 109 | return -EFAULT; | ||
| 110 | dm_reg_value = VSS_OP_REGISTER1; | ||
| 111 | break; | ||
| 112 | default: | ||
| 113 | return -EINVAL; | ||
| 114 | } | ||
| 115 | vss_transaction.state = HVUTIL_READY; | ||
| 116 | pr_info("VSS daemon registered\n"); | ||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 92 | static int vss_on_msg(void *msg, int len) | 120 | static int vss_on_msg(void *msg, int len) |
| 93 | { | 121 | { |
| 94 | struct hv_vss_msg *vss_msg = (struct hv_vss_msg *)msg; | 122 | struct hv_vss_msg *vss_msg = (struct hv_vss_msg *)msg; |
| @@ -96,18 +124,15 @@ static int vss_on_msg(void *msg, int len) | |||
| 96 | if (len != sizeof(*vss_msg)) | 124 | if (len != sizeof(*vss_msg)) |
| 97 | return -EINVAL; | 125 | return -EINVAL; |
| 98 | 126 | ||
| 99 | /* | 127 | if (vss_msg->vss_hdr.operation == VSS_OP_REGISTER || |
| 100 | * Don't process registration messages if we're in the middle of | 128 | vss_msg->vss_hdr.operation == VSS_OP_REGISTER1) { |
| 101 | * a transaction processing. | 129 | /* |
| 102 | */ | 130 | * Don't process registration messages if we're in the middle |
| 103 | if (vss_transaction.state > HVUTIL_READY && | 131 | * of a transaction processing. |
| 104 | vss_msg->vss_hdr.operation == VSS_OP_REGISTER) | 132 | */ |
| 105 | return -EINVAL; | 133 | if (vss_transaction.state > HVUTIL_READY) |
| 106 | 134 | return -EINVAL; | |
| 107 | if (vss_transaction.state == HVUTIL_DEVICE_INIT && | 135 | return vss_handle_handshake(vss_msg); |
| 108 | vss_msg->vss_hdr.operation == VSS_OP_REGISTER) { | ||
| 109 | pr_info("VSS daemon registered\n"); | ||
| 110 | vss_transaction.state = HVUTIL_READY; | ||
| 111 | } else if (vss_transaction.state == HVUTIL_USERSPACE_REQ) { | 136 | } else if (vss_transaction.state == HVUTIL_USERSPACE_REQ) { |
| 112 | vss_transaction.state = HVUTIL_USERSPACE_RECV; | 137 | vss_transaction.state = HVUTIL_USERSPACE_RECV; |
| 113 | if (cancel_delayed_work_sync(&vss_timeout_work)) { | 138 | if (cancel_delayed_work_sync(&vss_timeout_work)) { |
diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h index bb1cb73c927a..66c76df2c32d 100644 --- a/include/uapi/linux/hyperv.h +++ b/include/uapi/linux/hyperv.h | |||
| @@ -45,6 +45,11 @@ | |||
| 45 | 45 | ||
| 46 | #define VSS_OP_REGISTER 128 | 46 | #define VSS_OP_REGISTER 128 |
| 47 | 47 | ||
| 48 | /* | ||
| 49 | Daemon code with full handshake support. | ||
| 50 | */ | ||
| 51 | #define VSS_OP_REGISTER1 129 | ||
| 52 | |||
| 48 | enum hv_vss_op { | 53 | enum hv_vss_op { |
| 49 | VSS_OP_CREATE = 0, | 54 | VSS_OP_CREATE = 0, |
| 50 | VSS_OP_DELETE, | 55 | VSS_OP_DELETE, |
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c index 36f18211afa7..96234b638249 100644 --- a/tools/hv/hv_vss_daemon.c +++ b/tools/hv/hv_vss_daemon.c | |||
| @@ -148,6 +148,8 @@ int main(int argc, char *argv[]) | |||
| 148 | int op; | 148 | int op; |
| 149 | struct hv_vss_msg vss_msg[1]; | 149 | struct hv_vss_msg vss_msg[1]; |
| 150 | int daemonize = 1, long_index = 0, opt; | 150 | int daemonize = 1, long_index = 0, opt; |
| 151 | int in_handshake = 1; | ||
| 152 | __u32 kernel_modver; | ||
| 151 | 153 | ||
| 152 | static struct option long_options[] = { | 154 | static struct option long_options[] = { |
| 153 | {"help", no_argument, 0, 'h' }, | 155 | {"help", no_argument, 0, 'h' }, |
| @@ -211,6 +213,18 @@ int main(int argc, char *argv[]) | |||
| 211 | 213 | ||
| 212 | len = read(vss_fd, vss_msg, sizeof(struct hv_vss_msg)); | 214 | len = read(vss_fd, vss_msg, sizeof(struct hv_vss_msg)); |
| 213 | 215 | ||
| 216 | if (in_handshake) { | ||
| 217 | if (len != sizeof(kernel_modver)) { | ||
| 218 | syslog(LOG_ERR, "invalid version negotiation"); | ||
| 219 | exit(EXIT_FAILURE); | ||
| 220 | } | ||
| 221 | kernel_modver = *(__u32 *)vss_msg; | ||
| 222 | in_handshake = 0; | ||
| 223 | syslog(LOG_INFO, "VSS: kernel module version: %d", | ||
| 224 | kernel_modver); | ||
| 225 | continue; | ||
| 226 | } | ||
| 227 | |||
| 214 | if (len != sizeof(struct hv_vss_msg)) { | 228 | if (len != sizeof(struct hv_vss_msg)) { |
| 215 | syslog(LOG_ERR, "read failed; error:%d %s", | 229 | syslog(LOG_ERR, "read failed; error:%d %s", |
| 216 | errno, strerror(errno)); | 230 | errno, strerror(errno)); |
