101325476SK. Y. Srinivasan /* 201325476SK. Y. Srinivasan * An implementation of file copy service. 301325476SK. Y. Srinivasan * 401325476SK. Y. Srinivasan * Copyright (C) 2014, Microsoft, Inc. 501325476SK. Y. Srinivasan * 601325476SK. Y. Srinivasan * Author : K. Y. Srinivasan <ksrinivasan@novell.com> 701325476SK. Y. Srinivasan * 801325476SK. Y. Srinivasan * This program is free software; you can redistribute it and/or modify it 901325476SK. Y. Srinivasan * under the terms of the GNU General Public License version 2 as published 1001325476SK. Y. Srinivasan * by the Free Software Foundation. 1101325476SK. Y. Srinivasan * 1201325476SK. Y. Srinivasan * This program is distributed in the hope that it will be useful, but 1301325476SK. Y. Srinivasan * WITHOUT ANY WARRANTY; without even the implied warranty of 1401325476SK. Y. Srinivasan * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 1501325476SK. Y. Srinivasan * NON INFRINGEMENT. See the GNU General Public License for more 1601325476SK. Y. Srinivasan * details. 1701325476SK. Y. Srinivasan * 1801325476SK. Y. Srinivasan */ 1901325476SK. Y. Srinivasan 2001325476SK. Y. Srinivasan #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 2101325476SK. Y. Srinivasan 2201325476SK. Y. Srinivasan #include <linux/nls.h> 2301325476SK. Y. Srinivasan #include <linux/workqueue.h> 2401325476SK. Y. Srinivasan #include <linux/hyperv.h> 2501325476SK. Y. Srinivasan #include <linux/sched.h> 2601325476SK. Y. Srinivasan 2701325476SK. Y. Srinivasan #include "hyperv_vmbus.h" 28c7e490fcSVitaly Kuznetsov #include "hv_utils_transport.h" 2901325476SK. Y. Srinivasan 3001325476SK. Y. Srinivasan #define WIN8_SRV_MAJOR 1 3101325476SK. Y. Srinivasan #define WIN8_SRV_MINOR 1 3201325476SK. Y. Srinivasan #define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR) 3301325476SK. Y. Srinivasan 3401325476SK. Y. Srinivasan /* 3501325476SK. Y. Srinivasan * Global state maintained for transaction that is being processed. 3601325476SK. Y. Srinivasan * For a class of integration services, including the "file copy service", 3701325476SK. Y. Srinivasan * the specified protocol is a "request/response" protocol which means that 3801325476SK. Y. Srinivasan * there can only be single outstanding transaction from the host at any 3901325476SK. Y. Srinivasan * given point in time. We use this to simplify memory management in this 4001325476SK. Y. Srinivasan * driver - we cache and process only one message at a time. 4101325476SK. Y. Srinivasan * 4201325476SK. Y. Srinivasan * While the request/response protocol is guaranteed by the host, we further 4301325476SK. Y. Srinivasan * ensure this by serializing packet processing in this driver - we do not 4401325476SK. Y. Srinivasan * read additional packets from the VMBUs until the current packet is fully 4501325476SK. Y. Srinivasan * handled. 4601325476SK. Y. Srinivasan */ 4701325476SK. Y. Srinivasan 4801325476SK. Y. Srinivasan static struct { 494c93ccccSVitaly Kuznetsov int state; /* hvutil_device_state */ 5001325476SK. Y. Srinivasan int recv_len; /* number of bytes received. */ 5101325476SK. Y. Srinivasan struct hv_fcopy_hdr *fcopy_msg; /* current message */ 5201325476SK. Y. Srinivasan struct vmbus_channel *recv_channel; /* chn we got the request */ 5301325476SK. Y. Srinivasan u64 recv_req_id; /* request ID. */ 5401325476SK. Y. Srinivasan } fcopy_transaction; 5501325476SK. Y. Srinivasan 5601325476SK. Y. Srinivasan static void fcopy_respond_to_host(int error); 57c7e490fcSVitaly Kuznetsov static void fcopy_send_data(struct work_struct *dummy); 581d072339SVitaly Kuznetsov static void fcopy_timeout_func(struct work_struct *dummy); 591d072339SVitaly Kuznetsov static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func); 60c7e490fcSVitaly Kuznetsov static DECLARE_WORK(fcopy_send_work, fcopy_send_data); 61c7e490fcSVitaly Kuznetsov static const char fcopy_devname[] = "vmbus/hv_fcopy"; 6201325476SK. Y. Srinivasan static u8 *recv_buffer; 63c7e490fcSVitaly Kuznetsov static struct hvutil_transport *hvt; 6420951c75SK. Y. Srinivasan static struct completion release_event; 65a4d1ee5bSVitaly Kuznetsov /* 66a4d1ee5bSVitaly Kuznetsov * This state maintains the version number registered by the daemon. 67a4d1ee5bSVitaly Kuznetsov */ 68a4d1ee5bSVitaly Kuznetsov static int dm_reg_value; 6901325476SK. Y. Srinivasan 703cace4a6SOlaf Hering static void fcopy_poll_wrapper(void *channel) 713cace4a6SOlaf Hering { 723cace4a6SOlaf Hering /* Transaction is finished, reset the state here to avoid races. */ 733cace4a6SOlaf Hering fcopy_transaction.state = HVUTIL_READY; 743cace4a6SOlaf Hering hv_fcopy_onchannelcallback(channel); 753cace4a6SOlaf Hering } 763cace4a6SOlaf Hering 771d072339SVitaly Kuznetsov static void fcopy_timeout_func(struct work_struct *dummy) 7801325476SK. Y. Srinivasan { 7901325476SK. Y. Srinivasan /* 8001325476SK. Y. Srinivasan * If the timer fires, the user-mode component has not responded; 8101325476SK. Y. Srinivasan * process the pending transaction. 8201325476SK. Y. Srinivasan */ 8301325476SK. Y. Srinivasan fcopy_respond_to_host(HV_E_FAIL); 843cace4a6SOlaf Hering hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); 8501325476SK. Y. Srinivasan } 8601325476SK. Y. Srinivasan 87e0fa3e5eSVitaly Kuznetsov static void fcopy_register_done(void) 88e0fa3e5eSVitaly Kuznetsov { 89e0fa3e5eSVitaly Kuznetsov pr_debug("FCP: userspace daemon registered\n"); 90e0fa3e5eSVitaly Kuznetsov hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); 91e0fa3e5eSVitaly Kuznetsov } 92e0fa3e5eSVitaly Kuznetsov 9301325476SK. Y. Srinivasan static int fcopy_handle_handshake(u32 version) 9401325476SK. Y. Srinivasan { 95a4d1ee5bSVitaly Kuznetsov u32 our_ver = FCOPY_CURRENT_VERSION; 96a4d1ee5bSVitaly Kuznetsov 9701325476SK. Y. Srinivasan switch (version) { 98a4d1ee5bSVitaly Kuznetsov case FCOPY_VERSION_0: 99a4d1ee5bSVitaly Kuznetsov /* Daemon doesn't expect us to reply */ 100a4d1ee5bSVitaly Kuznetsov dm_reg_value = version; 101a4d1ee5bSVitaly Kuznetsov break; 102a4d1ee5bSVitaly Kuznetsov case FCOPY_VERSION_1: 103a4d1ee5bSVitaly Kuznetsov /* Daemon expects us to reply with our own version */ 104e0fa3e5eSVitaly Kuznetsov if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver), 105e0fa3e5eSVitaly Kuznetsov fcopy_register_done)) 106a4d1ee5bSVitaly Kuznetsov return -EFAULT; 107a4d1ee5bSVitaly Kuznetsov dm_reg_value = version; 10801325476SK. Y. Srinivasan break; 10901325476SK. Y. Srinivasan default: 11001325476SK. Y. Srinivasan /* 11101325476SK. Y. Srinivasan * For now we will fail the registration. 11201325476SK. Y. Srinivasan * If and when we have multiple versions to 11301325476SK. Y. Srinivasan * deal with, we will be backward compatible. 11401325476SK. Y. Srinivasan * We will add this code when needed. 11501325476SK. Y. Srinivasan */ 11601325476SK. Y. Srinivasan return -EINVAL; 11701325476SK. Y. Srinivasan } 118e0fa3e5eSVitaly Kuznetsov pr_debug("FCP: userspace daemon ver. %d connected\n", version); 11901325476SK. Y. Srinivasan return 0; 12001325476SK. Y. Srinivasan } 12101325476SK. Y. Srinivasan 122c7e490fcSVitaly Kuznetsov static void fcopy_send_data(struct work_struct *dummy) 12301325476SK. Y. Srinivasan { 12425ef06feSVitaly Kuznetsov struct hv_start_fcopy *smsg_out = NULL; 12501325476SK. Y. Srinivasan int operation = fcopy_transaction.fcopy_msg->operation; 12601325476SK. Y. Srinivasan struct hv_start_fcopy *smsg_in; 127c7e490fcSVitaly Kuznetsov void *out_src; 128c7e490fcSVitaly Kuznetsov int rc, out_len; 12901325476SK. Y. Srinivasan 13001325476SK. Y. Srinivasan /* 13101325476SK. Y. Srinivasan * The strings sent from the host are encoded in 13201325476SK. Y. Srinivasan * in utf16; convert it to utf8 strings. 13301325476SK. Y. Srinivasan * The host assures us that the utf16 strings will not exceed 13401325476SK. Y. Srinivasan * the max lengths specified. We will however, reserve room 13501325476SK. Y. Srinivasan * for the string terminating character - in the utf16s_utf8s() 13601325476SK. Y. Srinivasan * function we limit the size of the buffer where the converted 13701325476SK. Y. Srinivasan * string is placed to W_MAX_PATH -1 to guarantee 13801325476SK. Y. Srinivasan * that the strings can be properly terminated! 13901325476SK. Y. Srinivasan */ 14001325476SK. Y. Srinivasan 14101325476SK. Y. Srinivasan switch (operation) { 14201325476SK. Y. Srinivasan case START_FILE_COPY: 143c7e490fcSVitaly Kuznetsov out_len = sizeof(struct hv_start_fcopy); 14425ef06feSVitaly Kuznetsov smsg_out = kzalloc(sizeof(*smsg_out), GFP_KERNEL); 14525ef06feSVitaly Kuznetsov if (!smsg_out) 14625ef06feSVitaly Kuznetsov return; 14725ef06feSVitaly Kuznetsov 14825ef06feSVitaly Kuznetsov smsg_out->hdr.operation = operation; 14901325476SK. Y. Srinivasan smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg; 15001325476SK. Y. Srinivasan 15101325476SK. Y. Srinivasan utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH, 15201325476SK. Y. Srinivasan UTF16_LITTLE_ENDIAN, 15325ef06feSVitaly Kuznetsov (__u8 *)&smsg_out->file_name, W_MAX_PATH - 1); 15401325476SK. Y. Srinivasan 15501325476SK. Y. Srinivasan utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH, 15601325476SK. Y. Srinivasan UTF16_LITTLE_ENDIAN, 15725ef06feSVitaly Kuznetsov (__u8 *)&smsg_out->path_name, W_MAX_PATH - 1); 15801325476SK. Y. Srinivasan 15925ef06feSVitaly Kuznetsov smsg_out->copy_flags = smsg_in->copy_flags; 16025ef06feSVitaly Kuznetsov smsg_out->file_size = smsg_in->file_size; 16125ef06feSVitaly Kuznetsov out_src = smsg_out; 16201325476SK. Y. Srinivasan break; 16301325476SK. Y. Srinivasan 16401325476SK. Y. Srinivasan default: 165c7e490fcSVitaly Kuznetsov out_src = fcopy_transaction.fcopy_msg; 166c7e490fcSVitaly Kuznetsov out_len = fcopy_transaction.recv_len; 16701325476SK. Y. Srinivasan break; 16801325476SK. Y. Srinivasan } 169c7e490fcSVitaly Kuznetsov 170c7e490fcSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_USERSPACE_REQ; 171e0fa3e5eSVitaly Kuznetsov rc = hvutil_transport_send(hvt, out_src, out_len, NULL); 172c7e490fcSVitaly Kuznetsov if (rc) { 173c7e490fcSVitaly Kuznetsov pr_debug("FCP: failed to communicate to the daemon: %d\n", rc); 174c7e490fcSVitaly Kuznetsov if (cancel_delayed_work_sync(&fcopy_timeout_work)) { 175c7e490fcSVitaly Kuznetsov fcopy_respond_to_host(HV_E_FAIL); 176c7e490fcSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_READY; 177c7e490fcSVitaly Kuznetsov } 178c7e490fcSVitaly Kuznetsov } 17925ef06feSVitaly Kuznetsov kfree(smsg_out); 18025ef06feSVitaly Kuznetsov 18101325476SK. Y. Srinivasan return; 18201325476SK. Y. Srinivasan } 18301325476SK. Y. Srinivasan 18401325476SK. Y. Srinivasan /* 18501325476SK. Y. Srinivasan * Send a response back to the host. 18601325476SK. Y. Srinivasan */ 18701325476SK. Y. Srinivasan 18801325476SK. Y. Srinivasan static void 18901325476SK. Y. Srinivasan fcopy_respond_to_host(int error) 19001325476SK. Y. Srinivasan { 19101325476SK. Y. Srinivasan struct icmsg_hdr *icmsghdr; 19201325476SK. Y. Srinivasan u32 buf_len; 19301325476SK. Y. Srinivasan struct vmbus_channel *channel; 19401325476SK. Y. Srinivasan u64 req_id; 19501325476SK. Y. Srinivasan 19601325476SK. Y. Srinivasan /* 19701325476SK. Y. Srinivasan * Copy the global state for completing the transaction. Note that 19801325476SK. Y. Srinivasan * only one transaction can be active at a time. This is guaranteed 19901325476SK. Y. Srinivasan * by the file copy protocol implemented by the host. Furthermore, 20001325476SK. Y. Srinivasan * the "transaction active" state we maintain ensures that there can 20101325476SK. Y. Srinivasan * only be one active transaction at a time. 20201325476SK. Y. Srinivasan */ 20301325476SK. Y. Srinivasan 20401325476SK. Y. Srinivasan buf_len = fcopy_transaction.recv_len; 20501325476SK. Y. Srinivasan channel = fcopy_transaction.recv_channel; 20601325476SK. Y. Srinivasan req_id = fcopy_transaction.recv_req_id; 20701325476SK. Y. Srinivasan 20801325476SK. Y. Srinivasan icmsghdr = (struct icmsg_hdr *) 20901325476SK. Y. Srinivasan &recv_buffer[sizeof(struct vmbuspipe_hdr)]; 21001325476SK. Y. Srinivasan 21101325476SK. Y. Srinivasan if (channel->onchannel_callback == NULL) 21201325476SK. Y. Srinivasan /* 21301325476SK. Y. Srinivasan * We have raced with util driver being unloaded; 21401325476SK. Y. Srinivasan * silently return. 21501325476SK. Y. Srinivasan */ 21601325476SK. Y. Srinivasan return; 21701325476SK. Y. Srinivasan 21801325476SK. Y. Srinivasan icmsghdr->status = error; 21901325476SK. Y. Srinivasan icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; 22001325476SK. Y. Srinivasan vmbus_sendpacket(channel, recv_buffer, buf_len, req_id, 22101325476SK. Y. Srinivasan VM_PKT_DATA_INBAND, 0); 22201325476SK. Y. Srinivasan } 22301325476SK. Y. Srinivasan 22401325476SK. Y. Srinivasan void hv_fcopy_onchannelcallback(void *context) 22501325476SK. Y. Srinivasan { 22601325476SK. Y. Srinivasan struct vmbus_channel *channel = context; 22701325476SK. Y. Srinivasan u32 recvlen; 22801325476SK. Y. Srinivasan u64 requestid; 22901325476SK. Y. Srinivasan struct hv_fcopy_hdr *fcopy_msg; 23001325476SK. Y. Srinivasan struct icmsg_hdr *icmsghdr; 23101325476SK. Y. Srinivasan struct icmsg_negotiate *negop = NULL; 23201325476SK. Y. Srinivasan int util_fw_version; 23301325476SK. Y. Srinivasan int fcopy_srv_version; 23401325476SK. Y. Srinivasan 2353cace4a6SOlaf Hering if (fcopy_transaction.state > HVUTIL_READY) 23601325476SK. Y. Srinivasan return; 23701325476SK. Y. Srinivasan 23801325476SK. Y. Srinivasan vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen, 23901325476SK. Y. Srinivasan &requestid); 24001325476SK. Y. Srinivasan if (recvlen <= 0) 24101325476SK. Y. Srinivasan return; 24201325476SK. Y. Srinivasan 24301325476SK. Y. Srinivasan icmsghdr = (struct icmsg_hdr *)&recv_buffer[ 24401325476SK. Y. Srinivasan sizeof(struct vmbuspipe_hdr)]; 24501325476SK. Y. Srinivasan if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) { 24601325476SK. Y. Srinivasan util_fw_version = UTIL_FW_VERSION; 24701325476SK. Y. Srinivasan fcopy_srv_version = WIN8_SRV_VERSION; 24801325476SK. Y. Srinivasan vmbus_prep_negotiate_resp(icmsghdr, negop, recv_buffer, 24901325476SK. Y. Srinivasan util_fw_version, fcopy_srv_version); 25001325476SK. Y. Srinivasan } else { 25101325476SK. Y. Srinivasan fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[ 25201325476SK. Y. Srinivasan sizeof(struct vmbuspipe_hdr) + 25301325476SK. Y. Srinivasan sizeof(struct icmsg_hdr)]; 25401325476SK. Y. Srinivasan 25501325476SK. Y. Srinivasan /* 25601325476SK. Y. Srinivasan * Stash away this global state for completing the 25701325476SK. Y. Srinivasan * transaction; note transactions are serialized. 25801325476SK. Y. Srinivasan */ 25901325476SK. Y. Srinivasan 26001325476SK. Y. Srinivasan fcopy_transaction.recv_len = recvlen; 26101325476SK. Y. Srinivasan fcopy_transaction.recv_req_id = requestid; 26201325476SK. Y. Srinivasan fcopy_transaction.fcopy_msg = fcopy_msg; 26301325476SK. Y. Srinivasan 2644c93ccccSVitaly Kuznetsov if (fcopy_transaction.state < HVUTIL_READY) { 2654c93ccccSVitaly Kuznetsov /* Userspace is not registered yet */ 2664c93ccccSVitaly Kuznetsov fcopy_respond_to_host(HV_E_FAIL); 2674c93ccccSVitaly Kuznetsov return; 2684c93ccccSVitaly Kuznetsov } 2694c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED; 2704c93ccccSVitaly Kuznetsov 27101325476SK. Y. Srinivasan /* 27201325476SK. Y. Srinivasan * Send the information to the user-level daemon. 27301325476SK. Y. Srinivasan */ 274c7e490fcSVitaly Kuznetsov schedule_work(&fcopy_send_work); 275c0b200cfSK. Y. Srinivasan schedule_delayed_work(&fcopy_timeout_work, 276c0b200cfSK. Y. Srinivasan HV_UTIL_TIMEOUT * HZ); 27701325476SK. Y. Srinivasan return; 27801325476SK. Y. Srinivasan } 27901325476SK. Y. Srinivasan icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; 28001325476SK. Y. Srinivasan vmbus_sendpacket(channel, recv_buffer, recvlen, requestid, 28101325476SK. Y. Srinivasan VM_PKT_DATA_INBAND, 0); 28201325476SK. Y. Srinivasan } 28301325476SK. Y. Srinivasan 284c7e490fcSVitaly Kuznetsov /* Callback when data is received from userspace */ 285c7e490fcSVitaly Kuznetsov static int fcopy_on_msg(void *msg, int len) 28601325476SK. Y. Srinivasan { 287c7e490fcSVitaly Kuznetsov int *val = (int *)msg; 28801325476SK. Y. Srinivasan 289c7e490fcSVitaly Kuznetsov if (len != sizeof(int)) 29001325476SK. Y. Srinivasan return -EINVAL; 29101325476SK. Y. Srinivasan 292c7e490fcSVitaly Kuznetsov if (fcopy_transaction.state == HVUTIL_DEVICE_INIT) 293c7e490fcSVitaly Kuznetsov return fcopy_handle_handshake(*val); 29401325476SK. Y. Srinivasan 2954c93ccccSVitaly Kuznetsov if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ) 2964c93ccccSVitaly Kuznetsov return -EINVAL; 2974c93ccccSVitaly Kuznetsov 29801325476SK. Y. Srinivasan /* 29901325476SK. Y. Srinivasan * Complete the transaction by forwarding the result 30001325476SK. Y. Srinivasan * to the host. But first, cancel the timeout. 30101325476SK. Y. Srinivasan */ 3024c93ccccSVitaly Kuznetsov if (cancel_delayed_work_sync(&fcopy_timeout_work)) { 3034c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_USERSPACE_RECV; 304c7e490fcSVitaly Kuznetsov fcopy_respond_to_host(*val); 3053cace4a6SOlaf Hering hv_poll_channel(fcopy_transaction.recv_channel, 3063cace4a6SOlaf Hering fcopy_poll_wrapper); 307242f3122SVitaly Kuznetsov } 30801325476SK. Y. Srinivasan 30901325476SK. Y. Srinivasan return 0; 31001325476SK. Y. Srinivasan } 31101325476SK. Y. Srinivasan 312c7e490fcSVitaly Kuznetsov static void fcopy_on_reset(void) 31301325476SK. Y. Srinivasan { 31401325476SK. Y. Srinivasan /* 31501325476SK. Y. Srinivasan * The daemon has exited; reset the state. 31601325476SK. Y. Srinivasan */ 3174c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_INIT; 318d9b16529SDexuan Cui 319c7e490fcSVitaly Kuznetsov if (cancel_delayed_work_sync(&fcopy_timeout_work)) 320d9b16529SDexuan Cui fcopy_respond_to_host(HV_E_FAIL); 32120951c75SK. Y. Srinivasan complete(&release_event); 322d9b16529SDexuan Cui } 32301325476SK. Y. Srinivasan 32401325476SK. Y. Srinivasan int hv_fcopy_init(struct hv_util_service *srv) 32501325476SK. Y. Srinivasan { 32601325476SK. Y. Srinivasan recv_buffer = srv->recv_buffer; 327b9830d12SK. Y. Srinivasan fcopy_transaction.recv_channel = srv->channel; 32801325476SK. Y. Srinivasan 32920951c75SK. Y. Srinivasan init_completion(&release_event); 33001325476SK. Y. Srinivasan /* 33101325476SK. Y. Srinivasan * When this driver loads, the user level daemon that 33201325476SK. Y. Srinivasan * processes the host requests may not yet be running. 33301325476SK. Y. Srinivasan * Defer processing channel callbacks until the daemon 33401325476SK. Y. Srinivasan * has registered. 33501325476SK. Y. Srinivasan */ 3364c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_INIT; 33701325476SK. Y. Srinivasan 338c7e490fcSVitaly Kuznetsov hvt = hvutil_transport_init(fcopy_devname, 0, 0, 339c7e490fcSVitaly Kuznetsov fcopy_on_msg, fcopy_on_reset); 340c7e490fcSVitaly Kuznetsov if (!hvt) 341c7e490fcSVitaly Kuznetsov return -EFAULT; 342c7e490fcSVitaly Kuznetsov 343c7e490fcSVitaly Kuznetsov return 0; 34401325476SK. Y. Srinivasan } 34501325476SK. Y. Srinivasan 34601325476SK. Y. Srinivasan void hv_fcopy_deinit(void) 34701325476SK. Y. Srinivasan { 3484c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_DYING; 3491d072339SVitaly Kuznetsov cancel_delayed_work_sync(&fcopy_timeout_work); 350c7e490fcSVitaly Kuznetsov hvutil_transport_destroy(hvt); 35120951c75SK. Y. Srinivasan wait_for_completion(&release_event); 35201325476SK. Y. Srinivasan } 353