143aa3132SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 201325476SK. Y. Srinivasan /* 301325476SK. Y. Srinivasan * An implementation of file copy service. 401325476SK. Y. Srinivasan * 501325476SK. Y. Srinivasan * Copyright (C) 2014, Microsoft, Inc. 601325476SK. Y. Srinivasan * 701325476SK. Y. Srinivasan * Author : K. Y. Srinivasan <ksrinivasan@novell.com> 801325476SK. Y. Srinivasan */ 901325476SK. Y. Srinivasan 1001325476SK. Y. Srinivasan #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1101325476SK. Y. Srinivasan 1201325476SK. Y. Srinivasan #include <linux/nls.h> 1301325476SK. Y. Srinivasan #include <linux/workqueue.h> 1401325476SK. Y. Srinivasan #include <linux/hyperv.h> 1501325476SK. Y. Srinivasan #include <linux/sched.h> 16b14d749aSHimadri Pandya #include <asm/hyperv-tlfs.h> 1701325476SK. Y. Srinivasan 1801325476SK. Y. Srinivasan #include "hyperv_vmbus.h" 19c7e490fcSVitaly Kuznetsov #include "hv_utils_transport.h" 2001325476SK. Y. Srinivasan 2101325476SK. Y. Srinivasan #define WIN8_SRV_MAJOR 1 2201325476SK. Y. Srinivasan #define WIN8_SRV_MINOR 1 2301325476SK. Y. Srinivasan #define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR) 2401325476SK. Y. Srinivasan 25a1656454SAlex Ng #define FCOPY_VER_COUNT 1 26a1656454SAlex Ng static const int fcopy_versions[] = { 27a1656454SAlex Ng WIN8_SRV_VERSION 28a1656454SAlex Ng }; 29a1656454SAlex Ng 30a1656454SAlex Ng #define FW_VER_COUNT 1 31a1656454SAlex Ng static const int fw_versions[] = { 32a1656454SAlex Ng UTIL_FW_VERSION 33a1656454SAlex Ng }; 34a1656454SAlex Ng 3501325476SK. Y. Srinivasan /* 3601325476SK. Y. Srinivasan * Global state maintained for transaction that is being processed. 3701325476SK. Y. Srinivasan * For a class of integration services, including the "file copy service", 3801325476SK. Y. Srinivasan * the specified protocol is a "request/response" protocol which means that 3901325476SK. Y. Srinivasan * there can only be single outstanding transaction from the host at any 4001325476SK. Y. Srinivasan * given point in time. We use this to simplify memory management in this 4101325476SK. Y. Srinivasan * driver - we cache and process only one message at a time. 4201325476SK. Y. Srinivasan * 4301325476SK. Y. Srinivasan * While the request/response protocol is guaranteed by the host, we further 4401325476SK. Y. Srinivasan * ensure this by serializing packet processing in this driver - we do not 4501325476SK. Y. Srinivasan * read additional packets from the VMBUs until the current packet is fully 4601325476SK. Y. Srinivasan * handled. 4701325476SK. Y. Srinivasan */ 4801325476SK. Y. Srinivasan 4901325476SK. Y. Srinivasan static struct { 504c93ccccSVitaly Kuznetsov int state; /* hvutil_device_state */ 5101325476SK. Y. Srinivasan int recv_len; /* number of bytes received. */ 5201325476SK. Y. Srinivasan struct hv_fcopy_hdr *fcopy_msg; /* current message */ 5301325476SK. Y. Srinivasan struct vmbus_channel *recv_channel; /* chn we got the request */ 5401325476SK. Y. Srinivasan u64 recv_req_id; /* request ID. */ 5501325476SK. Y. Srinivasan } fcopy_transaction; 5601325476SK. Y. Srinivasan 5701325476SK. Y. Srinivasan static void fcopy_respond_to_host(int error); 58c7e490fcSVitaly Kuznetsov static void fcopy_send_data(struct work_struct *dummy); 591d072339SVitaly Kuznetsov static void fcopy_timeout_func(struct work_struct *dummy); 601d072339SVitaly Kuznetsov static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func); 61c7e490fcSVitaly Kuznetsov static DECLARE_WORK(fcopy_send_work, fcopy_send_data); 62c7e490fcSVitaly Kuznetsov static const char fcopy_devname[] = "vmbus/hv_fcopy"; 6301325476SK. Y. Srinivasan static u8 *recv_buffer; 64c7e490fcSVitaly Kuznetsov static struct hvutil_transport *hvt; 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 164549e658aSOlaf Hering case WRITE_TO_FILE: 165549e658aSOlaf Hering out_src = fcopy_transaction.fcopy_msg; 166549e658aSOlaf Hering out_len = sizeof(struct hv_do_fcopy); 167549e658aSOlaf Hering break; 16801325476SK. Y. Srinivasan default: 169c7e490fcSVitaly Kuznetsov out_src = fcopy_transaction.fcopy_msg; 170c7e490fcSVitaly Kuznetsov out_len = fcopy_transaction.recv_len; 17101325476SK. Y. Srinivasan break; 17201325476SK. Y. Srinivasan } 173c7e490fcSVitaly Kuznetsov 174c7e490fcSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_USERSPACE_REQ; 175e0fa3e5eSVitaly Kuznetsov rc = hvutil_transport_send(hvt, out_src, out_len, NULL); 176c7e490fcSVitaly Kuznetsov if (rc) { 177c7e490fcSVitaly Kuznetsov pr_debug("FCP: failed to communicate to the daemon: %d\n", rc); 178c7e490fcSVitaly Kuznetsov if (cancel_delayed_work_sync(&fcopy_timeout_work)) { 179c7e490fcSVitaly Kuznetsov fcopy_respond_to_host(HV_E_FAIL); 180c7e490fcSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_READY; 181c7e490fcSVitaly Kuznetsov } 182c7e490fcSVitaly Kuznetsov } 18325ef06feSVitaly Kuznetsov kfree(smsg_out); 18401325476SK. Y. Srinivasan } 18501325476SK. Y. Srinivasan 18601325476SK. Y. Srinivasan /* 18701325476SK. Y. Srinivasan * Send a response back to the host. 18801325476SK. Y. Srinivasan */ 18901325476SK. Y. Srinivasan 19001325476SK. Y. Srinivasan static void 19101325476SK. Y. Srinivasan fcopy_respond_to_host(int error) 19201325476SK. Y. Srinivasan { 19301325476SK. Y. Srinivasan struct icmsg_hdr *icmsghdr; 19401325476SK. Y. Srinivasan u32 buf_len; 19501325476SK. Y. Srinivasan struct vmbus_channel *channel; 19601325476SK. Y. Srinivasan u64 req_id; 19701325476SK. Y. Srinivasan 19801325476SK. Y. Srinivasan /* 19901325476SK. Y. Srinivasan * Copy the global state for completing the transaction. Note that 20001325476SK. Y. Srinivasan * only one transaction can be active at a time. This is guaranteed 20101325476SK. Y. Srinivasan * by the file copy protocol implemented by the host. Furthermore, 20201325476SK. Y. Srinivasan * the "transaction active" state we maintain ensures that there can 20301325476SK. Y. Srinivasan * only be one active transaction at a time. 20401325476SK. Y. Srinivasan */ 20501325476SK. Y. Srinivasan 20601325476SK. Y. Srinivasan buf_len = fcopy_transaction.recv_len; 20701325476SK. Y. Srinivasan channel = fcopy_transaction.recv_channel; 20801325476SK. Y. Srinivasan req_id = fcopy_transaction.recv_req_id; 20901325476SK. Y. Srinivasan 21001325476SK. Y. Srinivasan icmsghdr = (struct icmsg_hdr *) 21101325476SK. Y. Srinivasan &recv_buffer[sizeof(struct vmbuspipe_hdr)]; 21201325476SK. Y. Srinivasan 21301325476SK. Y. Srinivasan if (channel->onchannel_callback == NULL) 21401325476SK. Y. Srinivasan /* 21501325476SK. Y. Srinivasan * We have raced with util driver being unloaded; 21601325476SK. Y. Srinivasan * silently return. 21701325476SK. Y. Srinivasan */ 21801325476SK. Y. Srinivasan return; 21901325476SK. Y. Srinivasan 22001325476SK. Y. Srinivasan icmsghdr->status = error; 22101325476SK. Y. Srinivasan icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; 22201325476SK. Y. Srinivasan vmbus_sendpacket(channel, recv_buffer, buf_len, req_id, 22301325476SK. Y. Srinivasan VM_PKT_DATA_INBAND, 0); 22401325476SK. Y. Srinivasan } 22501325476SK. Y. Srinivasan 22601325476SK. Y. Srinivasan void hv_fcopy_onchannelcallback(void *context) 22701325476SK. Y. Srinivasan { 22801325476SK. Y. Srinivasan struct vmbus_channel *channel = context; 22901325476SK. Y. Srinivasan u32 recvlen; 23001325476SK. Y. Srinivasan u64 requestid; 23101325476SK. Y. Srinivasan struct hv_fcopy_hdr *fcopy_msg; 23201325476SK. Y. Srinivasan struct icmsg_hdr *icmsghdr; 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 238b14d749aSHimadri Pandya vmbus_recvpacket(channel, recv_buffer, HV_HYP_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) { 2461274a690SAlex Ng if (vmbus_prep_negotiate_resp(icmsghdr, recv_buffer, 247a1656454SAlex Ng fw_versions, FW_VER_COUNT, 248a1656454SAlex Ng fcopy_versions, FCOPY_VER_COUNT, 2491274a690SAlex Ng NULL, &fcopy_srv_version)) { 2501274a690SAlex Ng 2511274a690SAlex Ng pr_info("FCopy IC version %d.%d\n", 2521274a690SAlex Ng fcopy_srv_version >> 16, 2531274a690SAlex Ng fcopy_srv_version & 0xFFFF); 2541274a690SAlex Ng } 25501325476SK. Y. Srinivasan } else { 25601325476SK. Y. Srinivasan fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[ 25701325476SK. Y. Srinivasan sizeof(struct vmbuspipe_hdr) + 25801325476SK. Y. Srinivasan sizeof(struct icmsg_hdr)]; 25901325476SK. Y. Srinivasan 26001325476SK. Y. Srinivasan /* 26101325476SK. Y. Srinivasan * Stash away this global state for completing the 26201325476SK. Y. Srinivasan * transaction; note transactions are serialized. 26301325476SK. Y. Srinivasan */ 26401325476SK. Y. Srinivasan 26501325476SK. Y. Srinivasan fcopy_transaction.recv_len = recvlen; 26601325476SK. Y. Srinivasan fcopy_transaction.recv_req_id = requestid; 26701325476SK. Y. Srinivasan fcopy_transaction.fcopy_msg = fcopy_msg; 26801325476SK. Y. Srinivasan 2694c93ccccSVitaly Kuznetsov if (fcopy_transaction.state < HVUTIL_READY) { 2704c93ccccSVitaly Kuznetsov /* Userspace is not registered yet */ 2714c93ccccSVitaly Kuznetsov fcopy_respond_to_host(HV_E_FAIL); 2724c93ccccSVitaly Kuznetsov return; 2734c93ccccSVitaly Kuznetsov } 2744c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED; 2754c93ccccSVitaly Kuznetsov 27601325476SK. Y. Srinivasan /* 27701325476SK. Y. Srinivasan * Send the information to the user-level daemon. 27801325476SK. Y. Srinivasan */ 279c7e490fcSVitaly Kuznetsov schedule_work(&fcopy_send_work); 280c0b200cfSK. Y. Srinivasan schedule_delayed_work(&fcopy_timeout_work, 281c0b200cfSK. Y. Srinivasan HV_UTIL_TIMEOUT * HZ); 28201325476SK. Y. Srinivasan return; 28301325476SK. Y. Srinivasan } 28401325476SK. Y. Srinivasan icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; 28501325476SK. Y. Srinivasan vmbus_sendpacket(channel, recv_buffer, recvlen, requestid, 28601325476SK. Y. Srinivasan VM_PKT_DATA_INBAND, 0); 28701325476SK. Y. Srinivasan } 28801325476SK. Y. Srinivasan 289c7e490fcSVitaly Kuznetsov /* Callback when data is received from userspace */ 290c7e490fcSVitaly Kuznetsov static int fcopy_on_msg(void *msg, int len) 29101325476SK. Y. Srinivasan { 292c7e490fcSVitaly Kuznetsov int *val = (int *)msg; 29301325476SK. Y. Srinivasan 294c7e490fcSVitaly Kuznetsov if (len != sizeof(int)) 29501325476SK. Y. Srinivasan return -EINVAL; 29601325476SK. Y. Srinivasan 297c7e490fcSVitaly Kuznetsov if (fcopy_transaction.state == HVUTIL_DEVICE_INIT) 298c7e490fcSVitaly Kuznetsov return fcopy_handle_handshake(*val); 29901325476SK. Y. Srinivasan 3004c93ccccSVitaly Kuznetsov if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ) 3014c93ccccSVitaly Kuznetsov return -EINVAL; 3024c93ccccSVitaly Kuznetsov 30301325476SK. Y. Srinivasan /* 30401325476SK. Y. Srinivasan * Complete the transaction by forwarding the result 30501325476SK. Y. Srinivasan * to the host. But first, cancel the timeout. 30601325476SK. Y. Srinivasan */ 3074c93ccccSVitaly Kuznetsov if (cancel_delayed_work_sync(&fcopy_timeout_work)) { 3084c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_USERSPACE_RECV; 309c7e490fcSVitaly Kuznetsov fcopy_respond_to_host(*val); 3103cace4a6SOlaf Hering hv_poll_channel(fcopy_transaction.recv_channel, 3113cace4a6SOlaf Hering fcopy_poll_wrapper); 312242f3122SVitaly Kuznetsov } 31301325476SK. Y. Srinivasan 31401325476SK. Y. Srinivasan return 0; 31501325476SK. Y. Srinivasan } 31601325476SK. Y. Srinivasan 317c7e490fcSVitaly Kuznetsov static void fcopy_on_reset(void) 31801325476SK. Y. Srinivasan { 31901325476SK. Y. Srinivasan /* 32001325476SK. Y. Srinivasan * The daemon has exited; reset the state. 32101325476SK. Y. Srinivasan */ 3224c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_INIT; 323d9b16529SDexuan Cui 324c7e490fcSVitaly Kuznetsov if (cancel_delayed_work_sync(&fcopy_timeout_work)) 325d9b16529SDexuan Cui fcopy_respond_to_host(HV_E_FAIL); 326d9b16529SDexuan Cui } 32701325476SK. Y. Srinivasan 32801325476SK. Y. Srinivasan int hv_fcopy_init(struct hv_util_service *srv) 32901325476SK. Y. Srinivasan { 33001325476SK. Y. Srinivasan recv_buffer = srv->recv_buffer; 331b9830d12SK. Y. Srinivasan fcopy_transaction.recv_channel = srv->channel; 33201325476SK. Y. Srinivasan 33301325476SK. Y. Srinivasan /* 33401325476SK. Y. Srinivasan * When this driver loads, the user level daemon that 33501325476SK. Y. Srinivasan * processes the host requests may not yet be running. 33601325476SK. Y. Srinivasan * Defer processing channel callbacks until the daemon 33701325476SK. Y. Srinivasan * has registered. 33801325476SK. Y. Srinivasan */ 3394c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_INIT; 34001325476SK. Y. Srinivasan 341c7e490fcSVitaly Kuznetsov hvt = hvutil_transport_init(fcopy_devname, 0, 0, 342c7e490fcSVitaly Kuznetsov fcopy_on_msg, fcopy_on_reset); 343c7e490fcSVitaly Kuznetsov if (!hvt) 344c7e490fcSVitaly Kuznetsov return -EFAULT; 345c7e490fcSVitaly Kuznetsov 346c7e490fcSVitaly Kuznetsov return 0; 34701325476SK. Y. Srinivasan } 34801325476SK. Y. Srinivasan 34954e19d34SDexuan Cui static void hv_fcopy_cancel_work(void) 35054e19d34SDexuan Cui { 35154e19d34SDexuan Cui cancel_delayed_work_sync(&fcopy_timeout_work); 35254e19d34SDexuan Cui cancel_work_sync(&fcopy_send_work); 35354e19d34SDexuan Cui } 35454e19d34SDexuan Cui 35554e19d34SDexuan Cui int hv_fcopy_pre_suspend(void) 35654e19d34SDexuan Cui { 35754e19d34SDexuan Cui struct vmbus_channel *channel = fcopy_transaction.recv_channel; 35854e19d34SDexuan Cui struct hv_fcopy_hdr *fcopy_msg; 35954e19d34SDexuan Cui 36054e19d34SDexuan Cui /* 36154e19d34SDexuan Cui * Fake a CANCEL_FCOPY message for the user space daemon in case the 36254e19d34SDexuan Cui * daemon is in the middle of copying some file. It doesn't matter if 36354e19d34SDexuan Cui * there is already a message pending to be delivered to the user 36454e19d34SDexuan Cui * space since we force fcopy_transaction.state to be HVUTIL_READY, so 36554e19d34SDexuan Cui * the user space daemon's write() will fail with EINVAL (see 36654e19d34SDexuan Cui * fcopy_on_msg()), and the daemon will reset the device by closing 36754e19d34SDexuan Cui * and re-opening it. 36854e19d34SDexuan Cui */ 36954e19d34SDexuan Cui fcopy_msg = kzalloc(sizeof(*fcopy_msg), GFP_KERNEL); 37054e19d34SDexuan Cui if (!fcopy_msg) 37154e19d34SDexuan Cui return -ENOMEM; 37254e19d34SDexuan Cui 37354e19d34SDexuan Cui tasklet_disable(&channel->callback_event); 37454e19d34SDexuan Cui 37554e19d34SDexuan Cui fcopy_msg->operation = CANCEL_FCOPY; 37654e19d34SDexuan Cui 37754e19d34SDexuan Cui hv_fcopy_cancel_work(); 37854e19d34SDexuan Cui 37954e19d34SDexuan Cui /* We don't care about the return value. */ 38054e19d34SDexuan Cui hvutil_transport_send(hvt, fcopy_msg, sizeof(*fcopy_msg), NULL); 38154e19d34SDexuan Cui 38254e19d34SDexuan Cui kfree(fcopy_msg); 38354e19d34SDexuan Cui 38454e19d34SDexuan Cui fcopy_transaction.state = HVUTIL_READY; 38554e19d34SDexuan Cui 38654e19d34SDexuan Cui /* tasklet_enable() will be called in hv_fcopy_pre_resume(). */ 38754e19d34SDexuan Cui return 0; 38854e19d34SDexuan Cui } 38954e19d34SDexuan Cui 39054e19d34SDexuan Cui int hv_fcopy_pre_resume(void) 39154e19d34SDexuan Cui { 39254e19d34SDexuan Cui struct vmbus_channel *channel = fcopy_transaction.recv_channel; 39354e19d34SDexuan Cui 39454e19d34SDexuan Cui tasklet_enable(&channel->callback_event); 39554e19d34SDexuan Cui 39654e19d34SDexuan Cui return 0; 39754e19d34SDexuan Cui } 39854e19d34SDexuan Cui 39901325476SK. Y. Srinivasan void hv_fcopy_deinit(void) 40001325476SK. Y. Srinivasan { 4014c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_DYING; 40254e19d34SDexuan Cui 40354e19d34SDexuan Cui hv_fcopy_cancel_work(); 40454e19d34SDexuan Cui 405c7e490fcSVitaly Kuznetsov hvutil_transport_destroy(hvt); 40601325476SK. Y. Srinivasan } 407