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
fcopy_poll_wrapper(void * channel)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;
74238d2ed8SAndrea Parri (Microsoft) tasklet_schedule(&((struct vmbus_channel *)channel)->callback_event);
753cace4a6SOlaf Hering }
763cace4a6SOlaf Hering
fcopy_timeout_func(struct work_struct * dummy)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
fcopy_register_done(void)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
fcopy_handle_handshake(u32 version)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
fcopy_send_data(struct work_struct * dummy)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
132*676576d1SShaomin Deng * 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
fcopy_respond_to_host(int error)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
hv_fcopy_onchannelcallback(void * context)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
23806caa778SAndres Beltran if (vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen, &requestid)) {
23906caa778SAndres Beltran pr_err_ratelimited("Fcopy request received. Could not read into recv buf\n");
24001325476SK. Y. Srinivasan return;
24106caa778SAndres Beltran }
24206caa778SAndres Beltran
24306caa778SAndres Beltran if (!recvlen)
24406caa778SAndres Beltran return;
24506caa778SAndres Beltran
24606caa778SAndres Beltran /* Ensure recvlen is big enough to read header data */
24706caa778SAndres Beltran if (recvlen < ICMSG_HDR) {
24806caa778SAndres Beltran pr_err_ratelimited("Fcopy request received. Packet length too small: %d\n",
24906caa778SAndres Beltran recvlen);
25006caa778SAndres Beltran return;
25106caa778SAndres Beltran }
25201325476SK. Y. Srinivasan
25301325476SK. Y. Srinivasan icmsghdr = (struct icmsg_hdr *)&recv_buffer[
25401325476SK. Y. Srinivasan sizeof(struct vmbuspipe_hdr)];
25506caa778SAndres Beltran
25601325476SK. Y. Srinivasan if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
25706caa778SAndres Beltran if (vmbus_prep_negotiate_resp(icmsghdr,
25806caa778SAndres Beltran recv_buffer, recvlen,
259a1656454SAlex Ng fw_versions, FW_VER_COUNT,
260a1656454SAlex Ng fcopy_versions, FCOPY_VER_COUNT,
2611274a690SAlex Ng NULL, &fcopy_srv_version)) {
2621274a690SAlex Ng
2631274a690SAlex Ng pr_info("FCopy IC version %d.%d\n",
2641274a690SAlex Ng fcopy_srv_version >> 16,
2651274a690SAlex Ng fcopy_srv_version & 0xFFFF);
2661274a690SAlex Ng }
26706caa778SAndres Beltran } else if (icmsghdr->icmsgtype == ICMSGTYPE_FCOPY) {
26806caa778SAndres Beltran /* Ensure recvlen is big enough to contain hv_fcopy_hdr */
26906caa778SAndres Beltran if (recvlen < ICMSG_HDR + sizeof(struct hv_fcopy_hdr)) {
27006caa778SAndres Beltran pr_err_ratelimited("Invalid Fcopy hdr. Packet length too small: %u\n",
27106caa778SAndres Beltran recvlen);
27206caa778SAndres Beltran return;
27306caa778SAndres Beltran }
27406caa778SAndres Beltran fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[ICMSG_HDR];
27501325476SK. Y. Srinivasan
27601325476SK. Y. Srinivasan /*
27701325476SK. Y. Srinivasan * Stash away this global state for completing the
27801325476SK. Y. Srinivasan * transaction; note transactions are serialized.
27901325476SK. Y. Srinivasan */
28001325476SK. Y. Srinivasan
28101325476SK. Y. Srinivasan fcopy_transaction.recv_len = recvlen;
28201325476SK. Y. Srinivasan fcopy_transaction.recv_req_id = requestid;
28301325476SK. Y. Srinivasan fcopy_transaction.fcopy_msg = fcopy_msg;
28401325476SK. Y. Srinivasan
2854c93ccccSVitaly Kuznetsov if (fcopy_transaction.state < HVUTIL_READY) {
2864c93ccccSVitaly Kuznetsov /* Userspace is not registered yet */
2874c93ccccSVitaly Kuznetsov fcopy_respond_to_host(HV_E_FAIL);
2884c93ccccSVitaly Kuznetsov return;
2894c93ccccSVitaly Kuznetsov }
2904c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
2914c93ccccSVitaly Kuznetsov
29201325476SK. Y. Srinivasan /*
29301325476SK. Y. Srinivasan * Send the information to the user-level daemon.
29401325476SK. Y. Srinivasan */
295c7e490fcSVitaly Kuznetsov schedule_work(&fcopy_send_work);
296c0b200cfSK. Y. Srinivasan schedule_delayed_work(&fcopy_timeout_work,
297c0b200cfSK. Y. Srinivasan HV_UTIL_TIMEOUT * HZ);
29801325476SK. Y. Srinivasan return;
29906caa778SAndres Beltran } else {
30006caa778SAndres Beltran pr_err_ratelimited("Fcopy request received. Invalid msg type: %d\n",
30106caa778SAndres Beltran icmsghdr->icmsgtype);
30206caa778SAndres Beltran return;
30301325476SK. Y. Srinivasan }
30401325476SK. Y. Srinivasan icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
30501325476SK. Y. Srinivasan vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
30601325476SK. Y. Srinivasan VM_PKT_DATA_INBAND, 0);
30701325476SK. Y. Srinivasan }
30801325476SK. Y. Srinivasan
309c7e490fcSVitaly Kuznetsov /* Callback when data is received from userspace */
fcopy_on_msg(void * msg,int len)310c7e490fcSVitaly Kuznetsov static int fcopy_on_msg(void *msg, int len)
31101325476SK. Y. Srinivasan {
312c7e490fcSVitaly Kuznetsov int *val = (int *)msg;
31301325476SK. Y. Srinivasan
314c7e490fcSVitaly Kuznetsov if (len != sizeof(int))
31501325476SK. Y. Srinivasan return -EINVAL;
31601325476SK. Y. Srinivasan
317c7e490fcSVitaly Kuznetsov if (fcopy_transaction.state == HVUTIL_DEVICE_INIT)
318c7e490fcSVitaly Kuznetsov return fcopy_handle_handshake(*val);
31901325476SK. Y. Srinivasan
3204c93ccccSVitaly Kuznetsov if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ)
3214c93ccccSVitaly Kuznetsov return -EINVAL;
3224c93ccccSVitaly Kuznetsov
32301325476SK. Y. Srinivasan /*
32401325476SK. Y. Srinivasan * Complete the transaction by forwarding the result
32501325476SK. Y. Srinivasan * to the host. But first, cancel the timeout.
32601325476SK. Y. Srinivasan */
3274c93ccccSVitaly Kuznetsov if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
3284c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
329c7e490fcSVitaly Kuznetsov fcopy_respond_to_host(*val);
3303cace4a6SOlaf Hering hv_poll_channel(fcopy_transaction.recv_channel,
3313cace4a6SOlaf Hering fcopy_poll_wrapper);
332242f3122SVitaly Kuznetsov }
33301325476SK. Y. Srinivasan
33401325476SK. Y. Srinivasan return 0;
33501325476SK. Y. Srinivasan }
33601325476SK. Y. Srinivasan
fcopy_on_reset(void)337c7e490fcSVitaly Kuznetsov static void fcopy_on_reset(void)
33801325476SK. Y. Srinivasan {
33901325476SK. Y. Srinivasan /*
34001325476SK. Y. Srinivasan * The daemon has exited; reset the state.
34101325476SK. Y. Srinivasan */
3424c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_INIT;
343d9b16529SDexuan Cui
344c7e490fcSVitaly Kuznetsov if (cancel_delayed_work_sync(&fcopy_timeout_work))
345d9b16529SDexuan Cui fcopy_respond_to_host(HV_E_FAIL);
346d9b16529SDexuan Cui }
34701325476SK. Y. Srinivasan
hv_fcopy_init(struct hv_util_service * srv)34801325476SK. Y. Srinivasan int hv_fcopy_init(struct hv_util_service *srv)
34901325476SK. Y. Srinivasan {
35001325476SK. Y. Srinivasan recv_buffer = srv->recv_buffer;
351b9830d12SK. Y. Srinivasan fcopy_transaction.recv_channel = srv->channel;
352adae1e93SAndres Beltran fcopy_transaction.recv_channel->max_pkt_size = HV_HYP_PAGE_SIZE * 2;
35301325476SK. Y. Srinivasan
35401325476SK. Y. Srinivasan /*
35501325476SK. Y. Srinivasan * When this driver loads, the user level daemon that
35601325476SK. Y. Srinivasan * processes the host requests may not yet be running.
35701325476SK. Y. Srinivasan * Defer processing channel callbacks until the daemon
35801325476SK. Y. Srinivasan * has registered.
35901325476SK. Y. Srinivasan */
3604c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_INIT;
36101325476SK. Y. Srinivasan
362c7e490fcSVitaly Kuznetsov hvt = hvutil_transport_init(fcopy_devname, 0, 0,
363c7e490fcSVitaly Kuznetsov fcopy_on_msg, fcopy_on_reset);
364c7e490fcSVitaly Kuznetsov if (!hvt)
365c7e490fcSVitaly Kuznetsov return -EFAULT;
366c7e490fcSVitaly Kuznetsov
367c7e490fcSVitaly Kuznetsov return 0;
36801325476SK. Y. Srinivasan }
36901325476SK. Y. Srinivasan
hv_fcopy_cancel_work(void)37054e19d34SDexuan Cui static void hv_fcopy_cancel_work(void)
37154e19d34SDexuan Cui {
37254e19d34SDexuan Cui cancel_delayed_work_sync(&fcopy_timeout_work);
37354e19d34SDexuan Cui cancel_work_sync(&fcopy_send_work);
37454e19d34SDexuan Cui }
37554e19d34SDexuan Cui
hv_fcopy_pre_suspend(void)37654e19d34SDexuan Cui int hv_fcopy_pre_suspend(void)
37754e19d34SDexuan Cui {
37854e19d34SDexuan Cui struct vmbus_channel *channel = fcopy_transaction.recv_channel;
37954e19d34SDexuan Cui struct hv_fcopy_hdr *fcopy_msg;
38054e19d34SDexuan Cui
38154e19d34SDexuan Cui /*
38254e19d34SDexuan Cui * Fake a CANCEL_FCOPY message for the user space daemon in case the
38354e19d34SDexuan Cui * daemon is in the middle of copying some file. It doesn't matter if
38454e19d34SDexuan Cui * there is already a message pending to be delivered to the user
38554e19d34SDexuan Cui * space since we force fcopy_transaction.state to be HVUTIL_READY, so
38654e19d34SDexuan Cui * the user space daemon's write() will fail with EINVAL (see
38754e19d34SDexuan Cui * fcopy_on_msg()), and the daemon will reset the device by closing
38854e19d34SDexuan Cui * and re-opening it.
38954e19d34SDexuan Cui */
39054e19d34SDexuan Cui fcopy_msg = kzalloc(sizeof(*fcopy_msg), GFP_KERNEL);
39154e19d34SDexuan Cui if (!fcopy_msg)
39254e19d34SDexuan Cui return -ENOMEM;
39354e19d34SDexuan Cui
39454e19d34SDexuan Cui tasklet_disable(&channel->callback_event);
39554e19d34SDexuan Cui
39654e19d34SDexuan Cui fcopy_msg->operation = CANCEL_FCOPY;
39754e19d34SDexuan Cui
39854e19d34SDexuan Cui hv_fcopy_cancel_work();
39954e19d34SDexuan Cui
40054e19d34SDexuan Cui /* We don't care about the return value. */
40154e19d34SDexuan Cui hvutil_transport_send(hvt, fcopy_msg, sizeof(*fcopy_msg), NULL);
40254e19d34SDexuan Cui
40354e19d34SDexuan Cui kfree(fcopy_msg);
40454e19d34SDexuan Cui
40554e19d34SDexuan Cui fcopy_transaction.state = HVUTIL_READY;
40654e19d34SDexuan Cui
40754e19d34SDexuan Cui /* tasklet_enable() will be called in hv_fcopy_pre_resume(). */
40854e19d34SDexuan Cui return 0;
40954e19d34SDexuan Cui }
41054e19d34SDexuan Cui
hv_fcopy_pre_resume(void)41154e19d34SDexuan Cui int hv_fcopy_pre_resume(void)
41254e19d34SDexuan Cui {
41354e19d34SDexuan Cui struct vmbus_channel *channel = fcopy_transaction.recv_channel;
41454e19d34SDexuan Cui
41554e19d34SDexuan Cui tasklet_enable(&channel->callback_event);
41654e19d34SDexuan Cui
41754e19d34SDexuan Cui return 0;
41854e19d34SDexuan Cui }
41954e19d34SDexuan Cui
hv_fcopy_deinit(void)42001325476SK. Y. Srinivasan void hv_fcopy_deinit(void)
42101325476SK. Y. Srinivasan {
4224c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_DYING;
42354e19d34SDexuan Cui
42454e19d34SDexuan Cui hv_fcopy_cancel_work();
42554e19d34SDexuan Cui
426c7e490fcSVitaly Kuznetsov hvutil_transport_destroy(hvt);
42701325476SK. Y. Srinivasan }
428