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