hv_fcopy.c (11793B)
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}