linux/drivers/hv/hv_fcopy.c
<<
>>
Prefs
   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
  25static const int fcopy_versions[] = {
  26        WIN8_SRV_VERSION
  27};
  28
  29#define FW_VER_COUNT 1
  30static 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
  48static 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
  56static void fcopy_respond_to_host(int error);
  57static void fcopy_send_data(struct work_struct *dummy);
  58static void fcopy_timeout_func(struct work_struct *dummy);
  59static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func);
  60static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
  61static const char fcopy_devname[] = "vmbus/hv_fcopy";
  62static u8 *recv_buffer;
  63static struct hvutil_transport *hvt;
  64/*
  65 * This state maintains the version number registered by the daemon.
  66 */
  67static int dm_reg_value;
  68
  69static 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
  76static 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
  86static 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
  92static 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
 121static 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
 189static void
 190fcopy_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
 225void 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 */
 289static 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
 316static 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
 327int 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
 348void 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}
 354