root/drivers/hv/hv_fcopy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fcopy_poll_wrapper
  2. fcopy_timeout_func
  3. fcopy_register_done
  4. fcopy_handle_handshake
  5. fcopy_send_data
  6. fcopy_respond_to_host
  7. hv_fcopy_onchannelcallback
  8. fcopy_on_msg
  9. fcopy_on_reset
  10. hv_fcopy_init
  11. hv_fcopy_deinit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * An implementation of file copy service.
   4  *
   5  * Copyright (C) 2014, Microsoft, Inc.
   6  *
   7  * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
   8  */
   9 
  10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  11 
  12 #include <linux/nls.h>
  13 #include <linux/workqueue.h>
  14 #include <linux/hyperv.h>
  15 #include <linux/sched.h>
  16 
  17 #include "hyperv_vmbus.h"
  18 #include "hv_utils_transport.h"
  19 
  20 #define WIN8_SRV_MAJOR          1
  21 #define WIN8_SRV_MINOR          1
  22 #define WIN8_SRV_VERSION        (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
  23 
  24 #define FCOPY_VER_COUNT 1
  25 static const int fcopy_versions[] = {
  26         WIN8_SRV_VERSION
  27 };
  28 
  29 #define FW_VER_COUNT 1
  30 static const int fw_versions[] = {
  31         UTIL_FW_VERSION
  32 };
  33 
  34 /*
  35  * Global state maintained for transaction that is being processed.
  36  * For a class of integration services, including the "file copy service",
  37  * the specified protocol is a "request/response" protocol which means that
  38  * there can only be single outstanding transaction from the host at any
  39  * given point in time. We use this to simplify memory management in this
  40  * driver - we cache and process only one message at a time.
  41  *
  42  * While the request/response protocol is guaranteed by the host, we further
  43  * ensure this by serializing packet processing in this driver - we do not
  44  * read additional packets from the VMBUs until the current packet is fully
  45  * handled.
  46  */
  47 
  48 static struct {
  49         int state;   /* hvutil_device_state */
  50         int recv_len; /* number of bytes received. */
  51         struct hv_fcopy_hdr  *fcopy_msg; /* current message */
  52         struct vmbus_channel *recv_channel; /* chn we got the request */
  53         u64 recv_req_id; /* request ID. */
  54 } fcopy_transaction;
  55 
  56 static void fcopy_respond_to_host(int error);
  57 static void fcopy_send_data(struct work_struct *dummy);
  58 static void fcopy_timeout_func(struct work_struct *dummy);
  59 static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func);
  60 static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
  61 static const char fcopy_devname[] = "vmbus/hv_fcopy";
  62 static u8 *recv_buffer;
  63 static struct hvutil_transport *hvt;
  64 /*
  65  * This state maintains the version number registered by the daemon.
  66  */
  67 static int dm_reg_value;
  68 
  69 static void fcopy_poll_wrapper(void *channel)
  70 {
  71         /* Transaction is finished, reset the state here to avoid races. */
  72         fcopy_transaction.state = HVUTIL_READY;
  73         hv_fcopy_onchannelcallback(channel);
  74 }
  75 
  76 static void fcopy_timeout_func(struct work_struct *dummy)
  77 {
  78         /*
  79          * If the timer fires, the user-mode component has not responded;
  80          * process the pending transaction.
  81          */
  82         fcopy_respond_to_host(HV_E_FAIL);
  83         hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
  84 }
  85 
  86 static void fcopy_register_done(void)
  87 {
  88         pr_debug("FCP: userspace daemon registered\n");
  89         hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
  90 }
  91 
  92 static int fcopy_handle_handshake(u32 version)
  93 {
  94         u32 our_ver = FCOPY_CURRENT_VERSION;
  95 
  96         switch (version) {
  97         case FCOPY_VERSION_0:
  98                 /* Daemon doesn't expect us to reply */
  99                 dm_reg_value = version;
 100                 break;
 101         case FCOPY_VERSION_1:
 102                 /* Daemon expects us to reply with our own version */
 103                 if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver),
 104                     fcopy_register_done))
 105                         return -EFAULT;
 106                 dm_reg_value = version;
 107                 break;
 108         default:
 109                 /*
 110                  * For now we will fail the registration.
 111                  * If and when we have multiple versions to
 112                  * deal with, we will be backward compatible.
 113                  * We will add this code when needed.
 114                  */
 115                 return -EINVAL;
 116         }
 117         pr_debug("FCP: userspace daemon ver. %d connected\n", version);
 118         return 0;
 119 }
 120 
 121 static void fcopy_send_data(struct work_struct *dummy)
 122 {
 123         struct hv_start_fcopy *smsg_out = NULL;
 124         int operation = fcopy_transaction.fcopy_msg->operation;
 125         struct hv_start_fcopy *smsg_in;
 126         void *out_src;
 127         int rc, out_len;
 128 
 129         /*
 130          * The  strings sent from the host are encoded in
 131          * in utf16; convert it to utf8 strings.
 132          * The host assures us that the utf16 strings will not exceed
 133          * the max lengths specified. We will however, reserve room
 134          * for the string terminating character - in the utf16s_utf8s()
 135          * function we limit the size of the buffer where the converted
 136          * string is placed to W_MAX_PATH -1 to guarantee
 137          * that the strings can be properly terminated!
 138          */
 139 
 140         switch (operation) {
 141         case START_FILE_COPY:
 142                 out_len = sizeof(struct hv_start_fcopy);
 143                 smsg_out = kzalloc(sizeof(*smsg_out), GFP_KERNEL);
 144                 if (!smsg_out)
 145                         return;
 146 
 147                 smsg_out->hdr.operation = operation;
 148                 smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg;
 149 
 150                 utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH,
 151                                 UTF16_LITTLE_ENDIAN,
 152                                 (__u8 *)&smsg_out->file_name, W_MAX_PATH - 1);
 153 
 154                 utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH,
 155                                 UTF16_LITTLE_ENDIAN,
 156                                 (__u8 *)&smsg_out->path_name, W_MAX_PATH - 1);
 157 
 158                 smsg_out->copy_flags = smsg_in->copy_flags;
 159                 smsg_out->file_size = smsg_in->file_size;
 160                 out_src = smsg_out;
 161                 break;
 162 
 163         case WRITE_TO_FILE:
 164                 out_src = fcopy_transaction.fcopy_msg;
 165                 out_len = sizeof(struct hv_do_fcopy);
 166                 break;
 167         default:
 168                 out_src = fcopy_transaction.fcopy_msg;
 169                 out_len = fcopy_transaction.recv_len;
 170                 break;
 171         }
 172 
 173         fcopy_transaction.state = HVUTIL_USERSPACE_REQ;
 174         rc = hvutil_transport_send(hvt, out_src, out_len, NULL);
 175         if (rc) {
 176                 pr_debug("FCP: failed to communicate to the daemon: %d\n", rc);
 177                 if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
 178                         fcopy_respond_to_host(HV_E_FAIL);
 179                         fcopy_transaction.state = HVUTIL_READY;
 180                 }
 181         }
 182         kfree(smsg_out);
 183 }
 184 
 185 /*
 186  * Send a response back to the host.
 187  */
 188 
 189 static void
 190 fcopy_respond_to_host(int error)
 191 {
 192         struct icmsg_hdr *icmsghdr;
 193         u32 buf_len;
 194         struct vmbus_channel *channel;
 195         u64 req_id;
 196 
 197         /*
 198          * Copy the global state for completing the transaction. Note that
 199          * only one transaction can be active at a time. This is guaranteed
 200          * by the file copy protocol implemented by the host. Furthermore,
 201          * the "transaction active" state we maintain ensures that there can
 202          * only be one active transaction at a time.
 203          */
 204 
 205         buf_len = fcopy_transaction.recv_len;
 206         channel = fcopy_transaction.recv_channel;
 207         req_id = fcopy_transaction.recv_req_id;
 208 
 209         icmsghdr = (struct icmsg_hdr *)
 210                         &recv_buffer[sizeof(struct vmbuspipe_hdr)];
 211 
 212         if (channel->onchannel_callback == NULL)
 213                 /*
 214                  * We have raced with util driver being unloaded;
 215                  * silently return.
 216                  */
 217                 return;
 218 
 219         icmsghdr->status = error;
 220         icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
 221         vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
 222                                 VM_PKT_DATA_INBAND, 0);
 223 }
 224 
 225 void hv_fcopy_onchannelcallback(void *context)
 226 {
 227         struct vmbus_channel *channel = context;
 228         u32 recvlen;
 229         u64 requestid;
 230         struct hv_fcopy_hdr *fcopy_msg;
 231         struct icmsg_hdr *icmsghdr;
 232         int fcopy_srv_version;
 233 
 234         if (fcopy_transaction.state > HVUTIL_READY)
 235                 return;
 236 
 237         vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
 238                          &requestid);
 239         if (recvlen <= 0)
 240                 return;
 241 
 242         icmsghdr = (struct icmsg_hdr *)&recv_buffer[
 243                         sizeof(struct vmbuspipe_hdr)];
 244         if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
 245                 if (vmbus_prep_negotiate_resp(icmsghdr, recv_buffer,
 246                                 fw_versions, FW_VER_COUNT,
 247                                 fcopy_versions, FCOPY_VER_COUNT,
 248                                 NULL, &fcopy_srv_version)) {
 249 
 250                         pr_info("FCopy IC version %d.%d\n",
 251                                 fcopy_srv_version >> 16,
 252                                 fcopy_srv_version & 0xFFFF);
 253                 }
 254         } else {
 255                 fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[
 256                                 sizeof(struct vmbuspipe_hdr) +
 257                                 sizeof(struct icmsg_hdr)];
 258 
 259                 /*
 260                  * Stash away this global state for completing the
 261                  * transaction; note transactions are serialized.
 262                  */
 263 
 264                 fcopy_transaction.recv_len = recvlen;
 265                 fcopy_transaction.recv_req_id = requestid;
 266                 fcopy_transaction.fcopy_msg = fcopy_msg;
 267 
 268                 if (fcopy_transaction.state < HVUTIL_READY) {
 269                         /* Userspace is not registered yet */
 270                         fcopy_respond_to_host(HV_E_FAIL);
 271                         return;
 272                 }
 273                 fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
 274 
 275                 /*
 276                  * Send the information to the user-level daemon.
 277                  */
 278                 schedule_work(&fcopy_send_work);
 279                 schedule_delayed_work(&fcopy_timeout_work,
 280                                       HV_UTIL_TIMEOUT * HZ);
 281                 return;
 282         }
 283         icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
 284         vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
 285                         VM_PKT_DATA_INBAND, 0);
 286 }
 287 
 288 /* Callback when data is received from userspace */
 289 static int fcopy_on_msg(void *msg, int len)
 290 {
 291         int *val = (int *)msg;
 292 
 293         if (len != sizeof(int))
 294                 return -EINVAL;
 295 
 296         if (fcopy_transaction.state == HVUTIL_DEVICE_INIT)
 297                 return fcopy_handle_handshake(*val);
 298 
 299         if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ)
 300                 return -EINVAL;
 301 
 302         /*
 303          * Complete the transaction by forwarding the result
 304          * to the host. But first, cancel the timeout.
 305          */
 306         if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
 307                 fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
 308                 fcopy_respond_to_host(*val);
 309                 hv_poll_channel(fcopy_transaction.recv_channel,
 310                                 fcopy_poll_wrapper);
 311         }
 312 
 313         return 0;
 314 }
 315 
 316 static void fcopy_on_reset(void)
 317 {
 318         /*
 319          * The daemon has exited; reset the state.
 320          */
 321         fcopy_transaction.state = HVUTIL_DEVICE_INIT;
 322 
 323         if (cancel_delayed_work_sync(&fcopy_timeout_work))
 324                 fcopy_respond_to_host(HV_E_FAIL);
 325 }
 326 
 327 int hv_fcopy_init(struct hv_util_service *srv)
 328 {
 329         recv_buffer = srv->recv_buffer;
 330         fcopy_transaction.recv_channel = srv->channel;
 331 
 332         /*
 333          * When this driver loads, the user level daemon that
 334          * processes the host requests may not yet be running.
 335          * Defer processing channel callbacks until the daemon
 336          * has registered.
 337          */
 338         fcopy_transaction.state = HVUTIL_DEVICE_INIT;
 339 
 340         hvt = hvutil_transport_init(fcopy_devname, 0, 0,
 341                                     fcopy_on_msg, fcopy_on_reset);
 342         if (!hvt)
 343                 return -EFAULT;
 344 
 345         return 0;
 346 }
 347 
 348 void hv_fcopy_deinit(void)
 349 {
 350         fcopy_transaction.state = HVUTIL_DEVICE_DYING;
 351         cancel_delayed_work_sync(&fcopy_timeout_work);
 352         hvutil_transport_destroy(hvt);
 353 }

/* [<][>][^][v][top][bottom][index][help] */