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/semaphore.h>
  23#include <linux/fs.h>
  24#include <linux/nls.h>
  25#include <linux/workqueue.h>
  26#include <linux/cdev.h>
  27#include <linux/hyperv.h>
  28#include <linux/sched.h>
  29#include <linux/uaccess.h>
  30#include <linux/miscdevice.h>
  31
  32#include "hyperv_vmbus.h"
  33
  34#define WIN8_SRV_MAJOR          1
  35#define WIN8_SRV_MINOR          1
  36#define WIN8_SRV_VERSION        (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
  37
  38/*
  39 * Global state maintained for transaction that is being processed.
  40 * For a class of integration services, including the "file copy service",
  41 * the specified protocol is a "request/response" protocol which means that
  42 * there can only be single outstanding transaction from the host at any
  43 * given point in time. We use this to simplify memory management in this
  44 * driver - we cache and process only one message at a time.
  45 *
  46 * While the request/response protocol is guaranteed by the host, we further
  47 * ensure this by serializing packet processing in this driver - we do not
  48 * read additional packets from the VMBUs until the current packet is fully
  49 * handled.
  50 *
  51 * The transaction "active" state is set when we receive a request from the
  52 * host and we cleanup this state when the transaction is completed - when we
  53 * respond to the host with our response. When the transaction active state is
  54 * set, we defer handling incoming packets.
  55 */
  56
  57static struct {
  58        bool active; /* transaction status - active or not */
  59        int recv_len; /* number of bytes received. */
  60        struct hv_fcopy_hdr  *fcopy_msg; /* current message */
  61        struct hv_start_fcopy  message; /*  sent to daemon */
  62        struct vmbus_channel *recv_channel; /* chn we got the request */
  63        u64 recv_req_id; /* request ID. */
  64        void *fcopy_context; /* for the channel callback */
  65        struct semaphore read_sema;
  66} fcopy_transaction;
  67
  68static bool opened; /* currently device opened */
  69
  70/*
  71 * Before we can accept copy messages from the host, we need
  72 * to handshake with the user level daemon. This state tracks
  73 * if we are in the handshake phase.
  74 */
  75static bool in_hand_shake = true;
  76static void fcopy_send_data(void);
  77static void fcopy_respond_to_host(int error);
  78static void fcopy_work_func(struct work_struct *dummy);
  79static DECLARE_DELAYED_WORK(fcopy_work, fcopy_work_func);
  80static u8 *recv_buffer;
  81
  82static void fcopy_work_func(struct work_struct *dummy)
  83{
  84        /*
  85         * If the timer fires, the user-mode component has not responded;
  86         * process the pending transaction.
  87         */
  88        fcopy_respond_to_host(HV_E_FAIL);
  89}
  90
  91static int fcopy_handle_handshake(u32 version)
  92{
  93        switch (version) {
  94        case FCOPY_CURRENT_VERSION:
  95                break;
  96        default:
  97                /*
  98                 * For now we will fail the registration.
  99                 * If and when we have multiple versions to
 100                 * deal with, we will be backward compatible.
 101                 * We will add this code when needed.
 102                 */
 103                return -EINVAL;
 104        }
 105        pr_info("FCP: user-mode registering done. Daemon version: %d\n",
 106                version);
 107        fcopy_transaction.active = false;
 108        if (fcopy_transaction.fcopy_context)
 109                hv_fcopy_onchannelcallback(fcopy_transaction.fcopy_context);
 110        in_hand_shake = false;
 111        return 0;
 112}
 113
 114static void fcopy_send_data(void)
 115{
 116        struct hv_start_fcopy *smsg_out = &fcopy_transaction.message;
 117        int operation = fcopy_transaction.fcopy_msg->operation;
 118        struct hv_start_fcopy *smsg_in;
 119
 120        /*
 121         * The  strings sent from the host are encoded in
 122         * in utf16; convert it to utf8 strings.
 123         * The host assures us that the utf16 strings will not exceed
 124         * the max lengths specified. We will however, reserve room
 125         * for the string terminating character - in the utf16s_utf8s()
 126         * function we limit the size of the buffer where the converted
 127         * string is placed to W_MAX_PATH -1 to guarantee
 128         * that the strings can be properly terminated!
 129         */
 130
 131        switch (operation) {
 132        case START_FILE_COPY:
 133                memset(smsg_out, 0, sizeof(struct hv_start_fcopy));
 134                smsg_out->hdr.operation = operation;
 135                smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg;
 136
 137                utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH,
 138                                UTF16_LITTLE_ENDIAN,
 139                                (__u8 *)smsg_out->file_name, W_MAX_PATH - 1);
 140
 141                utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH,
 142                                UTF16_LITTLE_ENDIAN,
 143                                (__u8 *)smsg_out->path_name, W_MAX_PATH - 1);
 144
 145                smsg_out->copy_flags = smsg_in->copy_flags;
 146                smsg_out->file_size = smsg_in->file_size;
 147                break;
 148
 149        default:
 150                break;
 151        }
 152        up(&fcopy_transaction.read_sema);
 153        return;
 154}
 155
 156/*
 157 * Send a response back to the host.
 158 */
 159
 160static void
 161fcopy_respond_to_host(int error)
 162{
 163        struct icmsg_hdr *icmsghdr;
 164        u32 buf_len;
 165        struct vmbus_channel *channel;
 166        u64 req_id;
 167
 168        /*
 169         * Copy the global state for completing the transaction. Note that
 170         * only one transaction can be active at a time. This is guaranteed
 171         * by the file copy protocol implemented by the host. Furthermore,
 172         * the "transaction active" state we maintain ensures that there can
 173         * only be one active transaction at a time.
 174         */
 175
 176        buf_len = fcopy_transaction.recv_len;
 177        channel = fcopy_transaction.recv_channel;
 178        req_id = fcopy_transaction.recv_req_id;
 179
 180        fcopy_transaction.active = false;
 181
 182        icmsghdr = (struct icmsg_hdr *)
 183                        &recv_buffer[sizeof(struct vmbuspipe_hdr)];
 184
 185        if (channel->onchannel_callback == NULL)
 186                /*
 187                 * We have raced with util driver being unloaded;
 188                 * silently return.
 189                 */
 190                return;
 191
 192        icmsghdr->status = error;
 193        icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
 194        vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
 195                                VM_PKT_DATA_INBAND, 0);
 196}
 197
 198void hv_fcopy_onchannelcallback(void *context)
 199{
 200        struct vmbus_channel *channel = context;
 201        u32 recvlen;
 202        u64 requestid;
 203        struct hv_fcopy_hdr *fcopy_msg;
 204        struct icmsg_hdr *icmsghdr;
 205        struct icmsg_negotiate *negop = NULL;
 206        int util_fw_version;
 207        int fcopy_srv_version;
 208
 209        if (fcopy_transaction.active) {
 210                /*
 211                 * We will defer processing this callback once
 212                 * the current transaction is complete.
 213                 */
 214                fcopy_transaction.fcopy_context = context;
 215                return;
 216        }
 217
 218        vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
 219                         &requestid);
 220        if (recvlen <= 0)
 221                return;
 222
 223        icmsghdr = (struct icmsg_hdr *)&recv_buffer[
 224                        sizeof(struct vmbuspipe_hdr)];
 225        if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
 226                util_fw_version = UTIL_FW_VERSION;
 227                fcopy_srv_version = WIN8_SRV_VERSION;
 228                vmbus_prep_negotiate_resp(icmsghdr, negop, recv_buffer,
 229                                util_fw_version, fcopy_srv_version);
 230        } else {
 231                fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[
 232                                sizeof(struct vmbuspipe_hdr) +
 233                                sizeof(struct icmsg_hdr)];
 234
 235                /*
 236                 * Stash away this global state for completing the
 237                 * transaction; note transactions are serialized.
 238                 */
 239
 240                fcopy_transaction.active = true;
 241                fcopy_transaction.recv_len = recvlen;
 242                fcopy_transaction.recv_channel = channel;
 243                fcopy_transaction.recv_req_id = requestid;
 244                fcopy_transaction.fcopy_msg = fcopy_msg;
 245
 246                /*
 247                 * Send the information to the user-level daemon.
 248                 */
 249                schedule_delayed_work(&fcopy_work, 5*HZ);
 250                fcopy_send_data();
 251                return;
 252        }
 253        icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
 254        vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
 255                        VM_PKT_DATA_INBAND, 0);
 256}
 257
 258/*
 259 * Create a char device that can support read/write for passing
 260 * the payload.
 261 */
 262
 263static ssize_t fcopy_read(struct file *file, char __user *buf,
 264                size_t count, loff_t *ppos)
 265{
 266        void *src;
 267        size_t copy_size;
 268        int operation;
 269
 270        /*
 271         * Wait until there is something to be read.
 272         */
 273        if (down_interruptible(&fcopy_transaction.read_sema))
 274                return -EINTR;
 275
 276        /*
 277         * The channel may be rescinded and in this case, we will wakeup the
 278         * the thread blocked on the semaphore and we will use the opened
 279         * state to correctly handle this case.
 280         */
 281        if (!opened)
 282                return -ENODEV;
 283
 284        operation = fcopy_transaction.fcopy_msg->operation;
 285
 286        if (operation == START_FILE_COPY) {
 287                src = &fcopy_transaction.message;
 288                copy_size = sizeof(struct hv_start_fcopy);
 289                if (count < copy_size)
 290                        return 0;
 291        } else {
 292                src = fcopy_transaction.fcopy_msg;
 293                copy_size = sizeof(struct hv_do_fcopy);
 294                if (count < copy_size)
 295                        return 0;
 296        }
 297        if (copy_to_user(buf, src, copy_size))
 298                return -EFAULT;
 299
 300        return copy_size;
 301}
 302
 303static ssize_t fcopy_write(struct file *file, const char __user *buf,
 304                        size_t count, loff_t *ppos)
 305{
 306        int response = 0;
 307
 308        if (count != sizeof(int))
 309                return -EINVAL;
 310
 311        if (copy_from_user(&response, buf, sizeof(int)))
 312                return -EFAULT;
 313
 314        if (in_hand_shake) {
 315                if (fcopy_handle_handshake(response))
 316                        return -EINVAL;
 317                return sizeof(int);
 318        }
 319
 320        /*
 321         * Complete the transaction by forwarding the result
 322         * to the host. But first, cancel the timeout.
 323         */
 324        if (cancel_delayed_work_sync(&fcopy_work))
 325                fcopy_respond_to_host(response);
 326
 327        return sizeof(int);
 328}
 329
 330static int fcopy_open(struct inode *inode, struct file *f)
 331{
 332        /*
 333         * The user level daemon that will open this device is
 334         * really an extension of this driver. We can have only
 335         * active open at a time.
 336         */
 337        if (opened)
 338                return -EBUSY;
 339
 340        /*
 341         * The daemon is alive; setup the state.
 342         */
 343        opened = true;
 344        return 0;
 345}
 346
 347static int fcopy_release(struct inode *inode, struct file *f)
 348{
 349        /*
 350         * The daemon has exited; reset the state.
 351         */
 352        in_hand_shake = true;
 353        opened = false;
 354        return 0;
 355}
 356
 357
 358static const struct file_operations fcopy_fops = {
 359        .read           = fcopy_read,
 360        .write          = fcopy_write,
 361        .release        = fcopy_release,
 362        .open           = fcopy_open,
 363};
 364
 365static struct miscdevice fcopy_misc = {
 366        .minor          = MISC_DYNAMIC_MINOR,
 367        .name           = "vmbus/hv_fcopy",
 368        .fops           = &fcopy_fops,
 369};
 370
 371static int fcopy_dev_init(void)
 372{
 373        return misc_register(&fcopy_misc);
 374}
 375
 376static void fcopy_dev_deinit(void)
 377{
 378
 379        /*
 380         * The device is going away - perhaps because the
 381         * host has rescinded the channel. Setup state so that
 382         * user level daemon can gracefully exit if it is blocked
 383         * on the read semaphore.
 384         */
 385        opened = false;
 386        /*
 387         * Signal the semaphore as the device is
 388         * going away.
 389         */
 390        up(&fcopy_transaction.read_sema);
 391        misc_deregister(&fcopy_misc);
 392}
 393
 394int hv_fcopy_init(struct hv_util_service *srv)
 395{
 396        recv_buffer = srv->recv_buffer;
 397
 398        /*
 399         * When this driver loads, the user level daemon that
 400         * processes the host requests may not yet be running.
 401         * Defer processing channel callbacks until the daemon
 402         * has registered.
 403         */
 404        fcopy_transaction.active = true;
 405        sema_init(&fcopy_transaction.read_sema, 0);
 406
 407        return fcopy_dev_init();
 408}
 409
 410void hv_fcopy_deinit(void)
 411{
 412        cancel_delayed_work_sync(&fcopy_work);
 413        fcopy_dev_deinit();
 414}
 415