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