diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c index 6a8ec9fb0869..b7b528cd481b 100644 --- a/drivers/hv/hv_fcopy.c +++ b/drivers/hv/hv_fcopy.c @@ -62,6 +62,10 @@ static DECLARE_WORK(fcopy_send_work, fcopy_send_data); static const char fcopy_devname[] = "vmbus/hv_fcopy"; static u8 *recv_buffer; static struct hvutil_transport *hvt; +/* + * This state maintains the version number registered by the daemon. + */ +static int dm_reg_value; static void fcopy_timeout_func(struct work_struct *dummy) { @@ -81,8 +85,18 @@ static void fcopy_timeout_func(struct work_struct *dummy) static int fcopy_handle_handshake(u32 version) { + u32 our_ver = FCOPY_CURRENT_VERSION; + switch (version) { - case FCOPY_CURRENT_VERSION: + case FCOPY_VERSION_0: + /* Daemon doesn't expect us to reply */ + dm_reg_value = version; + break; + case FCOPY_VERSION_1: + /* Daemon expects us to reply with our own version */ + if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver))) + return -EFAULT; + dm_reg_value = version; break; default: /* diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h index 66c76df2c32d..e4c0a35d6417 100644 --- a/include/uapi/linux/hyperv.h +++ b/include/uapi/linux/hyperv.h @@ -105,7 +105,8 @@ struct hv_vss_msg { */ #define FCOPY_VERSION_0 0 -#define FCOPY_CURRENT_VERSION FCOPY_VERSION_0 +#define FCOPY_VERSION_1 1 +#define FCOPY_CURRENT_VERSION FCOPY_VERSION_1 #define W_MAX_PATH 260 enum hv_fcopy_op { diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c index 9445d8f264a4..5480e4e424eb 100644 --- a/tools/hv/hv_fcopy_daemon.c +++ b/tools/hv/hv_fcopy_daemon.c @@ -137,6 +137,8 @@ int main(int argc, char *argv[]) int version = FCOPY_CURRENT_VERSION; char *buffer[4096 * 2]; struct hv_fcopy_hdr *in_msg; + int in_handshake = 1; + __u32 kernel_modver; static struct option long_options[] = { {"help", no_argument, 0, 'h' }, @@ -191,6 +193,19 @@ int main(int argc, char *argv[]) syslog(LOG_ERR, "pread failed: %s", strerror(errno)); exit(EXIT_FAILURE); } + + if (in_handshake) { + if (len != sizeof(kernel_modver)) { + syslog(LOG_ERR, "invalid version negotiation"); + exit(EXIT_FAILURE); + } + kernel_modver = *(__u32 *)buffer; + in_handshake = 0; + syslog(LOG_INFO, "HV_FCOPY: kernel module version: %d", + kernel_modver); + continue; + } + in_msg = (struct hv_fcopy_hdr *)buffer; switch (in_msg->operation) {