1168fce73SSepherosa Ziehau /*- 2168fce73SSepherosa Ziehau * Copyright (c) 2016 Microsoft Corp. 3168fce73SSepherosa Ziehau * All rights reserved. 4168fce73SSepherosa Ziehau * 5168fce73SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 6168fce73SSepherosa Ziehau * modification, are permitted provided that the following conditions 7168fce73SSepherosa Ziehau * are met: 8168fce73SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 9168fce73SSepherosa Ziehau * notice unmodified, this list of conditions, and the following 10168fce73SSepherosa Ziehau * disclaimer. 11168fce73SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 12168fce73SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 13168fce73SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 14168fce73SSepherosa Ziehau * 15168fce73SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16168fce73SSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17168fce73SSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18168fce73SSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19168fce73SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20168fce73SSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21168fce73SSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22168fce73SSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23168fce73SSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24168fce73SSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25168fce73SSepherosa Ziehau */ 26168fce73SSepherosa Ziehau 27168fce73SSepherosa Ziehau #include <sys/cdefs.h> 28168fce73SSepherosa Ziehau __FBSDID("$FreeBSD$"); 29168fce73SSepherosa Ziehau 30168fce73SSepherosa Ziehau #include <sys/param.h> 31168fce73SSepherosa Ziehau #include <sys/kernel.h> 32168fce73SSepherosa Ziehau #include <sys/conf.h> 33168fce73SSepherosa Ziehau #include <sys/uio.h> 34168fce73SSepherosa Ziehau #include <sys/bus.h> 35168fce73SSepherosa Ziehau #include <sys/malloc.h> 36168fce73SSepherosa Ziehau #include <sys/mbuf.h> 37168fce73SSepherosa Ziehau #include <sys/module.h> 38168fce73SSepherosa Ziehau #include <sys/lock.h> 39168fce73SSepherosa Ziehau #include <sys/taskqueue.h> 40168fce73SSepherosa Ziehau #include <sys/selinfo.h> 41168fce73SSepherosa Ziehau #include <sys/sysctl.h> 42168fce73SSepherosa Ziehau #include <sys/poll.h> 43168fce73SSepherosa Ziehau #include <sys/proc.h> 44168fce73SSepherosa Ziehau #include <sys/queue.h> 45168fce73SSepherosa Ziehau #include <sys/kthread.h> 46168fce73SSepherosa Ziehau #include <sys/syscallsubr.h> 47168fce73SSepherosa Ziehau #include <sys/sysproto.h> 48168fce73SSepherosa Ziehau #include <sys/un.h> 49168fce73SSepherosa Ziehau #include <sys/endian.h> 50168fce73SSepherosa Ziehau #include <sys/sema.h> 51168fce73SSepherosa Ziehau #include <sys/signal.h> 52168fce73SSepherosa Ziehau #include <sys/syslog.h> 53168fce73SSepherosa Ziehau #include <sys/systm.h> 54168fce73SSepherosa Ziehau #include <sys/mutex.h> 55168fce73SSepherosa Ziehau #include <sys/callout.h> 56168fce73SSepherosa Ziehau 57168fce73SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h> 58168fce73SSepherosa Ziehau #include <dev/hyperv/utilities/hv_utilreg.h> 59168fce73SSepherosa Ziehau #include <dev/hyperv/utilities/vmbus_icreg.h> 60ed8107d1SSepherosa Ziehau #include <dev/hyperv/utilities/vmbus_icvar.h> 61168fce73SSepherosa Ziehau 62168fce73SSepherosa Ziehau #include "hv_snapshot.h" 63168fce73SSepherosa Ziehau #include "vmbus_if.h" 64168fce73SSepherosa Ziehau 65168fce73SSepherosa Ziehau #define VSS_MAJOR 5 66168fce73SSepherosa Ziehau #define VSS_MINOR 0 67168fce73SSepherosa Ziehau #define VSS_MSGVER VMBUS_IC_VERSION(VSS_MAJOR, VSS_MINOR) 68168fce73SSepherosa Ziehau 69168fce73SSepherosa Ziehau #define VSS_FWVER_MAJOR 3 70168fce73SSepherosa Ziehau #define VSS_FWVER VMBUS_IC_VERSION(VSS_FWVER_MAJOR, 0) 71168fce73SSepherosa Ziehau 72168fce73SSepherosa Ziehau #define TIMEOUT_LIMIT (15) // seconds 73168fce73SSepherosa Ziehau enum hv_vss_op { 74168fce73SSepherosa Ziehau VSS_OP_CREATE = 0, 75168fce73SSepherosa Ziehau VSS_OP_DELETE, 76168fce73SSepherosa Ziehau VSS_OP_HOT_BACKUP, 77168fce73SSepherosa Ziehau VSS_OP_GET_DM_INFO, 78168fce73SSepherosa Ziehau VSS_OP_BU_COMPLETE, 79168fce73SSepherosa Ziehau /* 80168fce73SSepherosa Ziehau * Following operations are only supported with IC version >= 5.0 81168fce73SSepherosa Ziehau */ 82168fce73SSepherosa Ziehau VSS_OP_FREEZE, /* Freeze the file systems in the VM */ 83168fce73SSepherosa Ziehau VSS_OP_THAW, /* Unfreeze the file systems */ 84168fce73SSepherosa Ziehau VSS_OP_AUTO_RECOVER, 85168fce73SSepherosa Ziehau VSS_OP_COUNT /* Number of operations, must be last */ 86168fce73SSepherosa Ziehau }; 87168fce73SSepherosa Ziehau 88168fce73SSepherosa Ziehau /* 89168fce73SSepherosa Ziehau * Header for all VSS messages. 90168fce73SSepherosa Ziehau */ 91168fce73SSepherosa Ziehau struct hv_vss_hdr { 92168fce73SSepherosa Ziehau struct vmbus_icmsg_hdr ic_hdr; 93168fce73SSepherosa Ziehau uint8_t operation; 94168fce73SSepherosa Ziehau uint8_t reserved[7]; 95168fce73SSepherosa Ziehau } __packed; 96168fce73SSepherosa Ziehau 97168fce73SSepherosa Ziehau 98168fce73SSepherosa Ziehau /* 99168fce73SSepherosa Ziehau * Flag values for the hv_vss_check_feature. Here supports only 100168fce73SSepherosa Ziehau * one value. 101168fce73SSepherosa Ziehau */ 102168fce73SSepherosa Ziehau #define VSS_HBU_NO_AUTO_RECOVERY 0x00000005 103168fce73SSepherosa Ziehau 104168fce73SSepherosa Ziehau struct hv_vss_check_feature { 105168fce73SSepherosa Ziehau uint32_t flags; 106168fce73SSepherosa Ziehau } __packed; 107168fce73SSepherosa Ziehau 108168fce73SSepherosa Ziehau struct hv_vss_check_dm_info { 109168fce73SSepherosa Ziehau uint32_t flags; 110168fce73SSepherosa Ziehau } __packed; 111168fce73SSepherosa Ziehau 112168fce73SSepherosa Ziehau struct hv_vss_msg { 113168fce73SSepherosa Ziehau union { 114168fce73SSepherosa Ziehau struct hv_vss_hdr vss_hdr; 115168fce73SSepherosa Ziehau } hdr; 116168fce73SSepherosa Ziehau union { 117168fce73SSepherosa Ziehau struct hv_vss_check_feature vss_cf; 118168fce73SSepherosa Ziehau struct hv_vss_check_dm_info dm_info; 119168fce73SSepherosa Ziehau } body; 120168fce73SSepherosa Ziehau } __packed; 121168fce73SSepherosa Ziehau 122168fce73SSepherosa Ziehau struct hv_vss_req { 123168fce73SSepherosa Ziehau struct hv_vss_opt_msg opt_msg; /* used to communicate with daemon */ 124168fce73SSepherosa Ziehau struct hv_vss_msg msg; /* used to communicate with host */ 125168fce73SSepherosa Ziehau } __packed; 126168fce73SSepherosa Ziehau 127168fce73SSepherosa Ziehau /* hv_vss debug control */ 128168fce73SSepherosa Ziehau static int hv_vss_log = 0; 129168fce73SSepherosa Ziehau 130168fce73SSepherosa Ziehau #define hv_vss_log_error(...) do { \ 131168fce73SSepherosa Ziehau if (hv_vss_log > 0) \ 132168fce73SSepherosa Ziehau log(LOG_ERR, "hv_vss: " __VA_ARGS__); \ 133168fce73SSepherosa Ziehau } while (0) 134168fce73SSepherosa Ziehau 135168fce73SSepherosa Ziehau #define hv_vss_log_info(...) do { \ 136168fce73SSepherosa Ziehau if (hv_vss_log > 1) \ 137168fce73SSepherosa Ziehau log(LOG_INFO, "hv_vss: " __VA_ARGS__); \ 138168fce73SSepherosa Ziehau } while (0) 139168fce73SSepherosa Ziehau 140168fce73SSepherosa Ziehau static const struct vmbus_ic_desc vmbus_vss_descs[] = { 141168fce73SSepherosa Ziehau { 142168fce73SSepherosa Ziehau .ic_guid = { .hv_guid = { 143168fce73SSepherosa Ziehau 0x29, 0x2e, 0xfa, 0x35, 0x23, 0xea, 0x36, 0x42, 144168fce73SSepherosa Ziehau 0x96, 0xae, 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40} }, 145168fce73SSepherosa Ziehau .ic_desc = "Hyper-V VSS" 146168fce73SSepherosa Ziehau }, 147168fce73SSepherosa Ziehau VMBUS_IC_DESC_END 148168fce73SSepherosa Ziehau }; 149168fce73SSepherosa Ziehau 150168fce73SSepherosa Ziehau static const char * vss_opt_name[] = {"None", "VSSCheck", "Freeze", "Thaw"}; 151168fce73SSepherosa Ziehau 152168fce73SSepherosa Ziehau /* character device prototypes */ 153168fce73SSepherosa Ziehau static d_open_t hv_vss_dev_open; 154168fce73SSepherosa Ziehau static d_close_t hv_vss_dev_close; 155168fce73SSepherosa Ziehau static d_poll_t hv_vss_dev_daemon_poll; 156168fce73SSepherosa Ziehau static d_ioctl_t hv_vss_dev_daemon_ioctl; 157168fce73SSepherosa Ziehau 158168fce73SSepherosa Ziehau static d_open_t hv_appvss_dev_open; 159168fce73SSepherosa Ziehau static d_close_t hv_appvss_dev_close; 160168fce73SSepherosa Ziehau static d_poll_t hv_appvss_dev_poll; 161168fce73SSepherosa Ziehau static d_ioctl_t hv_appvss_dev_ioctl; 162168fce73SSepherosa Ziehau 163168fce73SSepherosa Ziehau /* hv_vss character device structure */ 164168fce73SSepherosa Ziehau static struct cdevsw hv_vss_cdevsw = 165168fce73SSepherosa Ziehau { 166168fce73SSepherosa Ziehau .d_version = D_VERSION, 167168fce73SSepherosa Ziehau .d_open = hv_vss_dev_open, 168168fce73SSepherosa Ziehau .d_close = hv_vss_dev_close, 169168fce73SSepherosa Ziehau .d_poll = hv_vss_dev_daemon_poll, 170168fce73SSepherosa Ziehau .d_ioctl = hv_vss_dev_daemon_ioctl, 171168fce73SSepherosa Ziehau .d_name = FS_VSS_DEV_NAME, 172168fce73SSepherosa Ziehau }; 173168fce73SSepherosa Ziehau 174168fce73SSepherosa Ziehau static struct cdevsw hv_appvss_cdevsw = 175168fce73SSepherosa Ziehau { 176168fce73SSepherosa Ziehau .d_version = D_VERSION, 177168fce73SSepherosa Ziehau .d_open = hv_appvss_dev_open, 178168fce73SSepherosa Ziehau .d_close = hv_appvss_dev_close, 179168fce73SSepherosa Ziehau .d_poll = hv_appvss_dev_poll, 180168fce73SSepherosa Ziehau .d_ioctl = hv_appvss_dev_ioctl, 181168fce73SSepherosa Ziehau .d_name = APP_VSS_DEV_NAME, 182168fce73SSepherosa Ziehau }; 183168fce73SSepherosa Ziehau 184168fce73SSepherosa Ziehau struct hv_vss_sc; 185168fce73SSepherosa Ziehau /* 186168fce73SSepherosa Ziehau * Global state to track cdev 187168fce73SSepherosa Ziehau */ 188168fce73SSepherosa Ziehau struct hv_vss_dev_sc { 189168fce73SSepherosa Ziehau /* 190168fce73SSepherosa Ziehau * msg was transferred from host to notify queue, and 191168fce73SSepherosa Ziehau * ack queue. Finally, it was recyled to free list. 192168fce73SSepherosa Ziehau */ 193168fce73SSepherosa Ziehau STAILQ_HEAD(, hv_vss_req_internal) to_notify_queue; 194168fce73SSepherosa Ziehau STAILQ_HEAD(, hv_vss_req_internal) to_ack_queue; 195168fce73SSepherosa Ziehau struct hv_vss_sc *sc; 196168fce73SSepherosa Ziehau struct proc *proc_task; 197168fce73SSepherosa Ziehau struct selinfo hv_vss_selinfo; 198168fce73SSepherosa Ziehau }; 199168fce73SSepherosa Ziehau /* 200168fce73SSepherosa Ziehau * Global state to track and synchronize the transaction requests from the host. 201168fce73SSepherosa Ziehau * The VSS allows user to register their function to do freeze/thaw for application. 202168fce73SSepherosa Ziehau * VSS kernel will notify both vss daemon and user application if it is registered. 203168fce73SSepherosa Ziehau * The implementation state transition is illustrated by: 204168fce73SSepherosa Ziehau * https://clovertrail.github.io/assets/vssdot.png 205168fce73SSepherosa Ziehau */ 206168fce73SSepherosa Ziehau typedef struct hv_vss_sc { 2071eb6d711SSepherosa Ziehau struct vmbus_ic_softc util_sc; 208168fce73SSepherosa Ziehau device_t dev; 209168fce73SSepherosa Ziehau 210168fce73SSepherosa Ziehau struct task task; 211168fce73SSepherosa Ziehau 212168fce73SSepherosa Ziehau /* 213168fce73SSepherosa Ziehau * mutex is used to protect access of list/queue, 214168fce73SSepherosa Ziehau * callout in request is also used this mutex. 215168fce73SSepherosa Ziehau */ 216168fce73SSepherosa Ziehau struct mtx pending_mutex; 217168fce73SSepherosa Ziehau /* 218168fce73SSepherosa Ziehau * req_free_list contains all free items 219168fce73SSepherosa Ziehau */ 220168fce73SSepherosa Ziehau LIST_HEAD(, hv_vss_req_internal) req_free_list; 221168fce73SSepherosa Ziehau 222168fce73SSepherosa Ziehau /* Indicates if daemon registered with driver */ 223168fce73SSepherosa Ziehau boolean_t register_done; 224168fce73SSepherosa Ziehau 225168fce73SSepherosa Ziehau boolean_t app_register_done; 226168fce73SSepherosa Ziehau 227168fce73SSepherosa Ziehau /* cdev for file system freeze/thaw */ 228168fce73SSepherosa Ziehau struct cdev *hv_vss_dev; 229168fce73SSepherosa Ziehau /* cdev for application freeze/thaw */ 230168fce73SSepherosa Ziehau struct cdev *hv_appvss_dev; 231168fce73SSepherosa Ziehau 232168fce73SSepherosa Ziehau /* sc for app */ 233168fce73SSepherosa Ziehau struct hv_vss_dev_sc app_sc; 234168fce73SSepherosa Ziehau /* sc for deamon */ 235168fce73SSepherosa Ziehau struct hv_vss_dev_sc daemon_sc; 236168fce73SSepherosa Ziehau } hv_vss_sc; 237168fce73SSepherosa Ziehau 238168fce73SSepherosa Ziehau typedef struct hv_vss_req_internal { 239168fce73SSepherosa Ziehau LIST_ENTRY(hv_vss_req_internal) link; 240168fce73SSepherosa Ziehau STAILQ_ENTRY(hv_vss_req_internal) slink; 241168fce73SSepherosa Ziehau struct hv_vss_req vss_req; 242168fce73SSepherosa Ziehau 243168fce73SSepherosa Ziehau /* Rcv buffer for communicating with the host*/ 244168fce73SSepherosa Ziehau uint8_t *rcv_buf; 245168fce73SSepherosa Ziehau /* Length of host message */ 246168fce73SSepherosa Ziehau uint32_t host_msg_len; 247168fce73SSepherosa Ziehau /* Host message id */ 248168fce73SSepherosa Ziehau uint64_t host_msg_id; 249168fce73SSepherosa Ziehau 250168fce73SSepherosa Ziehau hv_vss_sc *sc; 251168fce73SSepherosa Ziehau 252168fce73SSepherosa Ziehau struct callout callout; 253168fce73SSepherosa Ziehau } hv_vss_req_internal; 254168fce73SSepherosa Ziehau 255168fce73SSepherosa Ziehau #define SEARCH_REMOVE_REQ_LOCKED(reqp, queue, link, tmp, id) \ 256168fce73SSepherosa Ziehau do { \ 257168fce73SSepherosa Ziehau STAILQ_FOREACH_SAFE(reqp, queue, link, tmp) { \ 258168fce73SSepherosa Ziehau if (reqp->vss_req.opt_msg.msgid == id) { \ 259168fce73SSepherosa Ziehau STAILQ_REMOVE(queue, \ 260168fce73SSepherosa Ziehau reqp, hv_vss_req_internal, link); \ 261168fce73SSepherosa Ziehau break; \ 262168fce73SSepherosa Ziehau } \ 263168fce73SSepherosa Ziehau } \ 264168fce73SSepherosa Ziehau } while (0) 265168fce73SSepherosa Ziehau 266168fce73SSepherosa Ziehau static bool 267168fce73SSepherosa Ziehau hv_vss_is_daemon_killed_after_launch(hv_vss_sc *sc) 268168fce73SSepherosa Ziehau { 269168fce73SSepherosa Ziehau return (!sc->register_done && sc->daemon_sc.proc_task); 270168fce73SSepherosa Ziehau } 271168fce73SSepherosa Ziehau 272168fce73SSepherosa Ziehau /* 273168fce73SSepherosa Ziehau * Callback routine that gets called whenever there is a message from host 274168fce73SSepherosa Ziehau */ 275168fce73SSepherosa Ziehau static void 276168fce73SSepherosa Ziehau hv_vss_callback(struct vmbus_channel *chan __unused, void *context) 277168fce73SSepherosa Ziehau { 278168fce73SSepherosa Ziehau hv_vss_sc *sc = (hv_vss_sc*)context; 279168fce73SSepherosa Ziehau if (hv_vss_is_daemon_killed_after_launch(sc)) 280168fce73SSepherosa Ziehau hv_vss_log_info("%s: daemon was killed!\n", __func__); 281168fce73SSepherosa Ziehau if (sc->register_done || sc->daemon_sc.proc_task) { 282168fce73SSepherosa Ziehau hv_vss_log_info("%s: Queuing work item\n", __func__); 283168fce73SSepherosa Ziehau if (hv_vss_is_daemon_killed_after_launch(sc)) 284168fce73SSepherosa Ziehau hv_vss_log_info("%s: daemon was killed!\n", __func__); 285168fce73SSepherosa Ziehau taskqueue_enqueue(taskqueue_thread, &sc->task); 286168fce73SSepherosa Ziehau } else { 287168fce73SSepherosa Ziehau hv_vss_log_info("%s: daemon has never been registered\n", __func__); 288168fce73SSepherosa Ziehau } 289168fce73SSepherosa Ziehau hv_vss_log_info("%s: received msg from host\n", __func__); 290168fce73SSepherosa Ziehau } 291168fce73SSepherosa Ziehau /* 292168fce73SSepherosa Ziehau * Send the response back to the host. 293168fce73SSepherosa Ziehau */ 294168fce73SSepherosa Ziehau static void 295168fce73SSepherosa Ziehau hv_vss_respond_host(uint8_t *rcv_buf, struct vmbus_channel *ch, 296168fce73SSepherosa Ziehau uint32_t recvlen, uint64_t requestid, uint32_t error) 297168fce73SSepherosa Ziehau { 298168fce73SSepherosa Ziehau struct vmbus_icmsg_hdr *hv_icmsg_hdrp; 299168fce73SSepherosa Ziehau 300168fce73SSepherosa Ziehau hv_icmsg_hdrp = (struct vmbus_icmsg_hdr *)rcv_buf; 301168fce73SSepherosa Ziehau 302168fce73SSepherosa Ziehau hv_icmsg_hdrp->ic_status = error; 303168fce73SSepherosa Ziehau hv_icmsg_hdrp->ic_flags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE; 304168fce73SSepherosa Ziehau 305168fce73SSepherosa Ziehau error = vmbus_chan_send(ch, VMBUS_CHANPKT_TYPE_INBAND, 0, 306168fce73SSepherosa Ziehau rcv_buf, recvlen, requestid); 307168fce73SSepherosa Ziehau if (error) 308168fce73SSepherosa Ziehau hv_vss_log_info("%s: hv_vss_respond_host: sendpacket error:%d\n", 309168fce73SSepherosa Ziehau __func__, error); 310168fce73SSepherosa Ziehau } 311168fce73SSepherosa Ziehau 312168fce73SSepherosa Ziehau static void 313168fce73SSepherosa Ziehau hv_vss_notify_host_result_locked(struct hv_vss_req_internal *reqp, uint32_t status) 314168fce73SSepherosa Ziehau { 315168fce73SSepherosa Ziehau struct hv_vss_msg* msg = (struct hv_vss_msg *)reqp->rcv_buf; 316168fce73SSepherosa Ziehau hv_vss_sc *sc = reqp->sc; 317168fce73SSepherosa Ziehau if (reqp->vss_req.opt_msg.opt == HV_VSS_CHECK) { 318168fce73SSepherosa Ziehau msg->body.vss_cf.flags = VSS_HBU_NO_AUTO_RECOVERY; 319168fce73SSepherosa Ziehau } 320168fce73SSepherosa Ziehau hv_vss_log_info("%s, %s response %s to host\n", __func__, 321168fce73SSepherosa Ziehau vss_opt_name[reqp->vss_req.opt_msg.opt], 322168fce73SSepherosa Ziehau status == HV_S_OK ? "Success" : "Fail"); 323168fce73SSepherosa Ziehau hv_vss_respond_host(reqp->rcv_buf, vmbus_get_channel(reqp->sc->dev), 324168fce73SSepherosa Ziehau reqp->host_msg_len, reqp->host_msg_id, status); 325168fce73SSepherosa Ziehau /* recycle the request */ 326168fce73SSepherosa Ziehau LIST_INSERT_HEAD(&sc->req_free_list, reqp, link); 327168fce73SSepherosa Ziehau } 328168fce73SSepherosa Ziehau 329168fce73SSepherosa Ziehau static void 330168fce73SSepherosa Ziehau hv_vss_notify_host_result(struct hv_vss_req_internal *reqp, uint32_t status) 331168fce73SSepherosa Ziehau { 332168fce73SSepherosa Ziehau mtx_lock(&reqp->sc->pending_mutex); 333168fce73SSepherosa Ziehau hv_vss_notify_host_result_locked(reqp, status); 334168fce73SSepherosa Ziehau mtx_unlock(&reqp->sc->pending_mutex); 335168fce73SSepherosa Ziehau } 336168fce73SSepherosa Ziehau 337168fce73SSepherosa Ziehau static void 338168fce73SSepherosa Ziehau hv_vss_cp_vssreq_to_user(struct hv_vss_req_internal *reqp, 339168fce73SSepherosa Ziehau struct hv_vss_opt_msg *userdata) 340168fce73SSepherosa Ziehau { 341168fce73SSepherosa Ziehau struct hv_vss_req *hv_vss_dev_buf; 342168fce73SSepherosa Ziehau hv_vss_dev_buf = &reqp->vss_req; 343168fce73SSepherosa Ziehau hv_vss_dev_buf->opt_msg.opt = HV_VSS_NONE; 344168fce73SSepherosa Ziehau switch (reqp->vss_req.msg.hdr.vss_hdr.operation) { 345168fce73SSepherosa Ziehau case VSS_OP_FREEZE: 346168fce73SSepherosa Ziehau hv_vss_dev_buf->opt_msg.opt = HV_VSS_FREEZE; 347168fce73SSepherosa Ziehau break; 348168fce73SSepherosa Ziehau case VSS_OP_THAW: 349168fce73SSepherosa Ziehau hv_vss_dev_buf->opt_msg.opt = HV_VSS_THAW; 350168fce73SSepherosa Ziehau break; 351168fce73SSepherosa Ziehau case VSS_OP_HOT_BACKUP: 352168fce73SSepherosa Ziehau hv_vss_dev_buf->opt_msg.opt = HV_VSS_CHECK; 353168fce73SSepherosa Ziehau break; 354168fce73SSepherosa Ziehau } 355168fce73SSepherosa Ziehau *userdata = hv_vss_dev_buf->opt_msg; 356168fce73SSepherosa Ziehau hv_vss_log_info("%s, read data from user for " 357168fce73SSepherosa Ziehau "%s (%ju) \n", __func__, vss_opt_name[userdata->opt], 358168fce73SSepherosa Ziehau (uintmax_t)userdata->msgid); 359168fce73SSepherosa Ziehau } 360168fce73SSepherosa Ziehau 361168fce73SSepherosa Ziehau /** 362168fce73SSepherosa Ziehau * Remove the request id from app notifiy or ack queue, 363168fce73SSepherosa Ziehau * and recyle the request by inserting it to free list. 364168fce73SSepherosa Ziehau * 365168fce73SSepherosa Ziehau * When app was notified but not yet sending ack, the request 366168fce73SSepherosa Ziehau * should locate in either notify queue or ack queue. 367168fce73SSepherosa Ziehau */ 368168fce73SSepherosa Ziehau static struct hv_vss_req_internal* 369168fce73SSepherosa Ziehau hv_vss_drain_req_queue_locked(hv_vss_sc *sc, uint64_t req_id) 370168fce73SSepherosa Ziehau { 371168fce73SSepherosa Ziehau struct hv_vss_req_internal *reqp, *tmp; 372168fce73SSepherosa Ziehau SEARCH_REMOVE_REQ_LOCKED(reqp, &sc->daemon_sc.to_notify_queue, 373168fce73SSepherosa Ziehau slink, tmp, req_id); 374168fce73SSepherosa Ziehau if (reqp == NULL) 375168fce73SSepherosa Ziehau SEARCH_REMOVE_REQ_LOCKED(reqp, &sc->daemon_sc.to_ack_queue, 376168fce73SSepherosa Ziehau slink, tmp, req_id); 377168fce73SSepherosa Ziehau if (reqp == NULL) 378168fce73SSepherosa Ziehau SEARCH_REMOVE_REQ_LOCKED(reqp, &sc->app_sc.to_notify_queue, 379168fce73SSepherosa Ziehau slink, tmp, req_id); 380168fce73SSepherosa Ziehau if (reqp == NULL) 381168fce73SSepherosa Ziehau SEARCH_REMOVE_REQ_LOCKED(reqp, &sc->app_sc.to_ack_queue, slink, 382168fce73SSepherosa Ziehau tmp, req_id); 383168fce73SSepherosa Ziehau return (reqp); 384168fce73SSepherosa Ziehau } 385168fce73SSepherosa Ziehau /** 386168fce73SSepherosa Ziehau * Actions for daemon who has been notified. 387168fce73SSepherosa Ziehau */ 388168fce73SSepherosa Ziehau static void 389168fce73SSepherosa Ziehau hv_vss_notified(struct hv_vss_dev_sc *dev_sc, struct hv_vss_opt_msg *userdata) 390168fce73SSepherosa Ziehau { 391168fce73SSepherosa Ziehau struct hv_vss_req_internal *reqp; 392168fce73SSepherosa Ziehau mtx_lock(&dev_sc->sc->pending_mutex); 393168fce73SSepherosa Ziehau if (!STAILQ_EMPTY(&dev_sc->to_notify_queue)) { 394168fce73SSepherosa Ziehau reqp = STAILQ_FIRST(&dev_sc->to_notify_queue); 395168fce73SSepherosa Ziehau hv_vss_cp_vssreq_to_user(reqp, userdata); 396168fce73SSepherosa Ziehau STAILQ_REMOVE_HEAD(&dev_sc->to_notify_queue, slink); 397168fce73SSepherosa Ziehau /* insert the msg to queue for write */ 398168fce73SSepherosa Ziehau STAILQ_INSERT_TAIL(&dev_sc->to_ack_queue, reqp, slink); 399168fce73SSepherosa Ziehau userdata->status = VSS_SUCCESS; 400168fce73SSepherosa Ziehau } else { 401168fce73SSepherosa Ziehau /* Timeout occur, thus request was removed from queue. */ 402168fce73SSepherosa Ziehau hv_vss_log_info("%s: notify queue is empty!\n", __func__); 403168fce73SSepherosa Ziehau userdata->status = VSS_FAIL; 404168fce73SSepherosa Ziehau } 405168fce73SSepherosa Ziehau mtx_unlock(&dev_sc->sc->pending_mutex); 406168fce73SSepherosa Ziehau } 407168fce73SSepherosa Ziehau 408168fce73SSepherosa Ziehau static void 409168fce73SSepherosa Ziehau hv_vss_notify(struct hv_vss_dev_sc *dev_sc, struct hv_vss_req_internal *reqp) 410168fce73SSepherosa Ziehau { 411168fce73SSepherosa Ziehau uint32_t opt = reqp->vss_req.opt_msg.opt; 412168fce73SSepherosa Ziehau mtx_lock(&dev_sc->sc->pending_mutex); 413168fce73SSepherosa Ziehau STAILQ_INSERT_TAIL(&dev_sc->to_notify_queue, reqp, slink); 414168fce73SSepherosa Ziehau hv_vss_log_info("%s: issuing query %s (%ju) to %s\n", __func__, 415168fce73SSepherosa Ziehau vss_opt_name[opt], (uintmax_t)reqp->vss_req.opt_msg.msgid, 416168fce73SSepherosa Ziehau &dev_sc->sc->app_sc == dev_sc ? "app" : "daemon"); 417168fce73SSepherosa Ziehau mtx_unlock(&dev_sc->sc->pending_mutex); 418168fce73SSepherosa Ziehau selwakeup(&dev_sc->hv_vss_selinfo); 419168fce73SSepherosa Ziehau } 420168fce73SSepherosa Ziehau 421168fce73SSepherosa Ziehau /** 422168fce73SSepherosa Ziehau * Actions for daemon who has acknowledged. 423168fce73SSepherosa Ziehau */ 424168fce73SSepherosa Ziehau static void 425168fce73SSepherosa Ziehau hv_vss_daemon_acked(struct hv_vss_dev_sc *dev_sc, struct hv_vss_opt_msg *userdata) 426168fce73SSepherosa Ziehau { 427168fce73SSepherosa Ziehau struct hv_vss_req_internal *reqp, *tmp; 428168fce73SSepherosa Ziehau uint64_t req_id; 429168fce73SSepherosa Ziehau int opt; 430168fce73SSepherosa Ziehau uint32_t status; 431168fce73SSepherosa Ziehau 432168fce73SSepherosa Ziehau opt = userdata->opt; 433168fce73SSepherosa Ziehau req_id = userdata->msgid; 434168fce73SSepherosa Ziehau status = userdata->status; 435168fce73SSepherosa Ziehau /* make sure the reserved fields are all zeros. */ 436168fce73SSepherosa Ziehau memset(&userdata->reserved, 0, sizeof(struct hv_vss_opt_msg) - 437168fce73SSepherosa Ziehau __offsetof(struct hv_vss_opt_msg, reserved)); 438168fce73SSepherosa Ziehau mtx_lock(&dev_sc->sc->pending_mutex); 439168fce73SSepherosa Ziehau SEARCH_REMOVE_REQ_LOCKED(reqp, &dev_sc->to_ack_queue, slink, tmp, req_id); 440168fce73SSepherosa Ziehau mtx_unlock(&dev_sc->sc->pending_mutex); 441168fce73SSepherosa Ziehau if (reqp == NULL) { 442168fce73SSepherosa Ziehau hv_vss_log_info("%s Timeout: fail to find daemon ack request\n", 443168fce73SSepherosa Ziehau __func__); 444168fce73SSepherosa Ziehau userdata->status = VSS_FAIL; 445168fce73SSepherosa Ziehau return; 446168fce73SSepherosa Ziehau } 447168fce73SSepherosa Ziehau KASSERT(opt == reqp->vss_req.opt_msg.opt, ("Mismatched VSS operation!")); 448168fce73SSepherosa Ziehau hv_vss_log_info("%s, get response %d from daemon for %s (%ju) \n", __func__, 449168fce73SSepherosa Ziehau status, vss_opt_name[opt], (uintmax_t)req_id); 450168fce73SSepherosa Ziehau switch (opt) { 451168fce73SSepherosa Ziehau case HV_VSS_CHECK: 452168fce73SSepherosa Ziehau case HV_VSS_FREEZE: 453168fce73SSepherosa Ziehau callout_drain(&reqp->callout); 454168fce73SSepherosa Ziehau hv_vss_notify_host_result(reqp, 455168fce73SSepherosa Ziehau status == VSS_SUCCESS ? HV_S_OK : HV_E_FAIL); 456168fce73SSepherosa Ziehau break; 457168fce73SSepherosa Ziehau case HV_VSS_THAW: 458168fce73SSepherosa Ziehau if (dev_sc->sc->app_register_done) { 459168fce73SSepherosa Ziehau if (status == VSS_SUCCESS) { 460168fce73SSepherosa Ziehau hv_vss_notify(&dev_sc->sc->app_sc, reqp); 461168fce73SSepherosa Ziehau } else { 462168fce73SSepherosa Ziehau /* handle error */ 463168fce73SSepherosa Ziehau callout_drain(&reqp->callout); 464168fce73SSepherosa Ziehau hv_vss_notify_host_result(reqp, HV_E_FAIL); 465168fce73SSepherosa Ziehau } 466168fce73SSepherosa Ziehau } else { 467168fce73SSepherosa Ziehau callout_drain(&reqp->callout); 468168fce73SSepherosa Ziehau hv_vss_notify_host_result(reqp, 469168fce73SSepherosa Ziehau status == VSS_SUCCESS ? HV_S_OK : HV_E_FAIL); 470168fce73SSepherosa Ziehau } 471168fce73SSepherosa Ziehau break; 472168fce73SSepherosa Ziehau } 473168fce73SSepherosa Ziehau } 474168fce73SSepherosa Ziehau 475168fce73SSepherosa Ziehau /** 476168fce73SSepherosa Ziehau * Actions for app who has acknowledged. 477168fce73SSepherosa Ziehau */ 478168fce73SSepherosa Ziehau static void 479168fce73SSepherosa Ziehau hv_vss_app_acked(struct hv_vss_dev_sc *dev_sc, struct hv_vss_opt_msg *userdata) 480168fce73SSepherosa Ziehau { 481168fce73SSepherosa Ziehau struct hv_vss_req_internal *reqp, *tmp; 482168fce73SSepherosa Ziehau uint64_t req_id; 483168fce73SSepherosa Ziehau int opt; 484168fce73SSepherosa Ziehau uint8_t status; 485168fce73SSepherosa Ziehau 486168fce73SSepherosa Ziehau opt = userdata->opt; 487168fce73SSepherosa Ziehau req_id = userdata->msgid; 488168fce73SSepherosa Ziehau status = userdata->status; 489168fce73SSepherosa Ziehau /* make sure the reserved fields are all zeros. */ 490168fce73SSepherosa Ziehau memset(&userdata->reserved, 0, sizeof(struct hv_vss_opt_msg) - 491168fce73SSepherosa Ziehau __offsetof(struct hv_vss_opt_msg, reserved)); 492168fce73SSepherosa Ziehau mtx_lock(&dev_sc->sc->pending_mutex); 493168fce73SSepherosa Ziehau SEARCH_REMOVE_REQ_LOCKED(reqp, &dev_sc->to_ack_queue, slink, tmp, req_id); 494168fce73SSepherosa Ziehau mtx_unlock(&dev_sc->sc->pending_mutex); 495168fce73SSepherosa Ziehau if (reqp == NULL) { 496168fce73SSepherosa Ziehau hv_vss_log_info("%s Timeout: fail to find app ack request\n", 497168fce73SSepherosa Ziehau __func__); 498168fce73SSepherosa Ziehau userdata->status = VSS_FAIL; 499168fce73SSepherosa Ziehau return; 500168fce73SSepherosa Ziehau } 501168fce73SSepherosa Ziehau KASSERT(opt == reqp->vss_req.opt_msg.opt, ("Mismatched VSS operation!")); 502168fce73SSepherosa Ziehau hv_vss_log_info("%s, get response %d from app for %s (%ju) \n", 503168fce73SSepherosa Ziehau __func__, status, vss_opt_name[opt], (uintmax_t)req_id); 504168fce73SSepherosa Ziehau if (dev_sc->sc->register_done) { 505168fce73SSepherosa Ziehau switch (opt) { 506168fce73SSepherosa Ziehau case HV_VSS_CHECK: 507168fce73SSepherosa Ziehau case HV_VSS_FREEZE: 508168fce73SSepherosa Ziehau if (status == VSS_SUCCESS) { 509168fce73SSepherosa Ziehau hv_vss_notify(&dev_sc->sc->daemon_sc, reqp); 510168fce73SSepherosa Ziehau } else { 511168fce73SSepherosa Ziehau /* handle error */ 512168fce73SSepherosa Ziehau callout_drain(&reqp->callout); 513168fce73SSepherosa Ziehau hv_vss_notify_host_result(reqp, HV_E_FAIL); 514168fce73SSepherosa Ziehau } 515168fce73SSepherosa Ziehau break; 516168fce73SSepherosa Ziehau case HV_VSS_THAW: 517168fce73SSepherosa Ziehau callout_drain(&reqp->callout); 518168fce73SSepherosa Ziehau hv_vss_notify_host_result(reqp, 519168fce73SSepherosa Ziehau status == VSS_SUCCESS ? HV_S_OK : HV_E_FAIL); 520168fce73SSepherosa Ziehau break; 521168fce73SSepherosa Ziehau } 522168fce73SSepherosa Ziehau } else { 523168fce73SSepherosa Ziehau hv_vss_log_info("%s, Fatal: vss daemon was killed\n", __func__); 524168fce73SSepherosa Ziehau } 525168fce73SSepherosa Ziehau } 526168fce73SSepherosa Ziehau 527168fce73SSepherosa Ziehau static int 528168fce73SSepherosa Ziehau hv_vss_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 529168fce73SSepherosa Ziehau { 530168fce73SSepherosa Ziehau struct proc *td_proc; 531168fce73SSepherosa Ziehau td_proc = td->td_proc; 532168fce73SSepherosa Ziehau 533168fce73SSepherosa Ziehau struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1; 534168fce73SSepherosa Ziehau hv_vss_log_info("%s: %s opens device \"%s\" successfully.\n", 535168fce73SSepherosa Ziehau __func__, td_proc->p_comm, FS_VSS_DEV_NAME); 536168fce73SSepherosa Ziehau 537168fce73SSepherosa Ziehau if (dev_sc->sc->register_done) 538168fce73SSepherosa Ziehau return (EBUSY); 539168fce73SSepherosa Ziehau 540168fce73SSepherosa Ziehau dev_sc->sc->register_done = true; 541168fce73SSepherosa Ziehau hv_vss_callback(vmbus_get_channel(dev_sc->sc->dev), dev_sc->sc); 542168fce73SSepherosa Ziehau 543168fce73SSepherosa Ziehau dev_sc->proc_task = curproc; 544168fce73SSepherosa Ziehau return (0); 545168fce73SSepherosa Ziehau } 546168fce73SSepherosa Ziehau 547168fce73SSepherosa Ziehau static int 548168fce73SSepherosa Ziehau hv_vss_dev_close(struct cdev *dev, int fflag __unused, int devtype __unused, 549168fce73SSepherosa Ziehau struct thread *td) 550168fce73SSepherosa Ziehau { 551168fce73SSepherosa Ziehau struct proc *td_proc; 552168fce73SSepherosa Ziehau td_proc = td->td_proc; 553168fce73SSepherosa Ziehau 554168fce73SSepherosa Ziehau struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1; 555168fce73SSepherosa Ziehau 556168fce73SSepherosa Ziehau hv_vss_log_info("%s: %s closes device \"%s\"\n", 557168fce73SSepherosa Ziehau __func__, td_proc->p_comm, FS_VSS_DEV_NAME); 558168fce73SSepherosa Ziehau dev_sc->sc->register_done = false; 559168fce73SSepherosa Ziehau return (0); 560168fce73SSepherosa Ziehau } 561168fce73SSepherosa Ziehau 562168fce73SSepherosa Ziehau static int 563168fce73SSepherosa Ziehau hv_vss_dev_daemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, 564168fce73SSepherosa Ziehau struct thread *td) 565168fce73SSepherosa Ziehau { 566168fce73SSepherosa Ziehau struct proc *td_proc; 567168fce73SSepherosa Ziehau struct hv_vss_dev_sc *sc; 568168fce73SSepherosa Ziehau 569168fce73SSepherosa Ziehau td_proc = td->td_proc; 570168fce73SSepherosa Ziehau sc = (struct hv_vss_dev_sc*)dev->si_drv1; 571168fce73SSepherosa Ziehau 572168fce73SSepherosa Ziehau hv_vss_log_info("%s: %s invoked vss ioctl\n", __func__, td_proc->p_comm); 573168fce73SSepherosa Ziehau 574168fce73SSepherosa Ziehau struct hv_vss_opt_msg* userdata = (struct hv_vss_opt_msg*)data; 575168fce73SSepherosa Ziehau switch(cmd) { 576168fce73SSepherosa Ziehau case IOCHVVSSREAD: 577168fce73SSepherosa Ziehau hv_vss_notified(sc, userdata); 578168fce73SSepherosa Ziehau break; 579168fce73SSepherosa Ziehau case IOCHVVSSWRITE: 580168fce73SSepherosa Ziehau hv_vss_daemon_acked(sc, userdata); 581168fce73SSepherosa Ziehau break; 582168fce73SSepherosa Ziehau } 583168fce73SSepherosa Ziehau return (0); 584168fce73SSepherosa Ziehau } 585168fce73SSepherosa Ziehau 586168fce73SSepherosa Ziehau /* 587168fce73SSepherosa Ziehau * hv_vss_daemon poll invokes this function to check if data is available 588168fce73SSepherosa Ziehau * for daemon to read. 589168fce73SSepherosa Ziehau */ 590168fce73SSepherosa Ziehau static int 591168fce73SSepherosa Ziehau hv_vss_dev_daemon_poll(struct cdev *dev, int events, struct thread *td) 592168fce73SSepherosa Ziehau { 593168fce73SSepherosa Ziehau int revent = 0; 594168fce73SSepherosa Ziehau struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1; 595168fce73SSepherosa Ziehau 596168fce73SSepherosa Ziehau mtx_lock(&dev_sc->sc->pending_mutex); 597168fce73SSepherosa Ziehau /** 598168fce73SSepherosa Ziehau * if there is data ready, inform daemon's poll 599168fce73SSepherosa Ziehau */ 600168fce73SSepherosa Ziehau if (!STAILQ_EMPTY(&dev_sc->to_notify_queue)) 601168fce73SSepherosa Ziehau revent = POLLIN; 602168fce73SSepherosa Ziehau if (revent == 0) 603168fce73SSepherosa Ziehau selrecord(td, &dev_sc->hv_vss_selinfo); 604168fce73SSepherosa Ziehau hv_vss_log_info("%s return 0x%x\n", __func__, revent); 605168fce73SSepherosa Ziehau mtx_unlock(&dev_sc->sc->pending_mutex); 606168fce73SSepherosa Ziehau return (revent); 607168fce73SSepherosa Ziehau } 608168fce73SSepherosa Ziehau 609168fce73SSepherosa Ziehau static int 610168fce73SSepherosa Ziehau hv_appvss_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 611168fce73SSepherosa Ziehau { 612168fce73SSepherosa Ziehau struct proc *td_proc; 613168fce73SSepherosa Ziehau td_proc = td->td_proc; 614168fce73SSepherosa Ziehau 615168fce73SSepherosa Ziehau struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1; 616168fce73SSepherosa Ziehau hv_vss_log_info("%s: %s opens device \"%s\" successfully.\n", 617168fce73SSepherosa Ziehau __func__, td_proc->p_comm, APP_VSS_DEV_NAME); 618168fce73SSepherosa Ziehau 619168fce73SSepherosa Ziehau if (dev_sc->sc->app_register_done) 620168fce73SSepherosa Ziehau return (EBUSY); 621168fce73SSepherosa Ziehau 622168fce73SSepherosa Ziehau dev_sc->sc->app_register_done = true; 623168fce73SSepherosa Ziehau dev_sc->proc_task = curproc; 624168fce73SSepherosa Ziehau return (0); 625168fce73SSepherosa Ziehau } 626168fce73SSepherosa Ziehau 627168fce73SSepherosa Ziehau static int 628168fce73SSepherosa Ziehau hv_appvss_dev_close(struct cdev *dev, int fflag __unused, int devtype __unused, 629168fce73SSepherosa Ziehau struct thread *td) 630168fce73SSepherosa Ziehau { 631168fce73SSepherosa Ziehau struct proc *td_proc; 632168fce73SSepherosa Ziehau td_proc = td->td_proc; 633168fce73SSepherosa Ziehau 634168fce73SSepherosa Ziehau struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1; 635168fce73SSepherosa Ziehau 636168fce73SSepherosa Ziehau hv_vss_log_info("%s: %s closes device \"%s\".\n", 637168fce73SSepherosa Ziehau __func__, td_proc->p_comm, APP_VSS_DEV_NAME); 638168fce73SSepherosa Ziehau dev_sc->sc->app_register_done = false; 639168fce73SSepherosa Ziehau return (0); 640168fce73SSepherosa Ziehau } 641168fce73SSepherosa Ziehau 642168fce73SSepherosa Ziehau static int 643168fce73SSepherosa Ziehau hv_appvss_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, 644168fce73SSepherosa Ziehau struct thread *td) 645168fce73SSepherosa Ziehau { 646168fce73SSepherosa Ziehau struct proc *td_proc; 647168fce73SSepherosa Ziehau struct hv_vss_dev_sc *dev_sc; 648168fce73SSepherosa Ziehau 649168fce73SSepherosa Ziehau td_proc = td->td_proc; 650168fce73SSepherosa Ziehau dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1; 651168fce73SSepherosa Ziehau 652168fce73SSepherosa Ziehau hv_vss_log_info("%s: %s invoked vss ioctl\n", __func__, td_proc->p_comm); 653168fce73SSepherosa Ziehau 654168fce73SSepherosa Ziehau struct hv_vss_opt_msg* userdata = (struct hv_vss_opt_msg*)data; 655168fce73SSepherosa Ziehau switch(cmd) { 656168fce73SSepherosa Ziehau case IOCHVVSSREAD: 657168fce73SSepherosa Ziehau hv_vss_notified(dev_sc, userdata); 658168fce73SSepherosa Ziehau break; 659168fce73SSepherosa Ziehau case IOCHVVSSWRITE: 660168fce73SSepherosa Ziehau hv_vss_app_acked(dev_sc, userdata); 661168fce73SSepherosa Ziehau break; 662168fce73SSepherosa Ziehau } 663168fce73SSepherosa Ziehau return (0); 664168fce73SSepherosa Ziehau } 665168fce73SSepherosa Ziehau 666168fce73SSepherosa Ziehau /* 667168fce73SSepherosa Ziehau * hv_vss_daemon poll invokes this function to check if data is available 668168fce73SSepherosa Ziehau * for daemon to read. 669168fce73SSepherosa Ziehau */ 670168fce73SSepherosa Ziehau static int 671168fce73SSepherosa Ziehau hv_appvss_dev_poll(struct cdev *dev, int events, struct thread *td) 672168fce73SSepherosa Ziehau { 673168fce73SSepherosa Ziehau int revent = 0; 674168fce73SSepherosa Ziehau struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1; 675168fce73SSepherosa Ziehau 676168fce73SSepherosa Ziehau mtx_lock(&dev_sc->sc->pending_mutex); 677168fce73SSepherosa Ziehau /** 678168fce73SSepherosa Ziehau * if there is data ready, inform daemon's poll 679168fce73SSepherosa Ziehau */ 680168fce73SSepherosa Ziehau if (!STAILQ_EMPTY(&dev_sc->to_notify_queue)) 681168fce73SSepherosa Ziehau revent = POLLIN; 682168fce73SSepherosa Ziehau if (revent == 0) 683168fce73SSepherosa Ziehau selrecord(td, &dev_sc->hv_vss_selinfo); 684168fce73SSepherosa Ziehau hv_vss_log_info("%s return 0x%x\n", __func__, revent); 685168fce73SSepherosa Ziehau mtx_unlock(&dev_sc->sc->pending_mutex); 686168fce73SSepherosa Ziehau return (revent); 687168fce73SSepherosa Ziehau } 688168fce73SSepherosa Ziehau 689168fce73SSepherosa Ziehau static void 690168fce73SSepherosa Ziehau hv_vss_timeout(void *arg) 691168fce73SSepherosa Ziehau { 692168fce73SSepherosa Ziehau hv_vss_req_internal *reqp = arg; 69303988000SJohn Baldwin hv_vss_req_internal *request __diagused; 694168fce73SSepherosa Ziehau hv_vss_sc* sc = reqp->sc; 695168fce73SSepherosa Ziehau uint64_t req_id = reqp->vss_req.opt_msg.msgid; 696168fce73SSepherosa Ziehau /* This thread is locked */ 697168fce73SSepherosa Ziehau KASSERT(mtx_owned(&sc->pending_mutex), ("mutex lock is not owned!")); 698168fce73SSepherosa Ziehau request = hv_vss_drain_req_queue_locked(sc, req_id); 699168fce73SSepherosa Ziehau KASSERT(request != NULL, ("timeout but fail to find request")); 700168fce73SSepherosa Ziehau hv_vss_notify_host_result_locked(reqp, HV_E_FAIL); 701168fce73SSepherosa Ziehau } 702168fce73SSepherosa Ziehau 703168fce73SSepherosa Ziehau /* 704168fce73SSepherosa Ziehau * This routine is called whenever a message is received from the host 705168fce73SSepherosa Ziehau */ 706168fce73SSepherosa Ziehau static void 707168fce73SSepherosa Ziehau hv_vss_init_req(hv_vss_req_internal *reqp, 708168fce73SSepherosa Ziehau uint32_t recvlen, uint64_t requestid, uint8_t *vss_buf, hv_vss_sc *sc) 709168fce73SSepherosa Ziehau { 710168fce73SSepherosa Ziehau struct timespec vm_ts; 711168fce73SSepherosa Ziehau struct hv_vss_msg* msg = (struct hv_vss_msg *)vss_buf; 712168fce73SSepherosa Ziehau 713168fce73SSepherosa Ziehau memset(reqp, 0, __offsetof(hv_vss_req_internal, callout)); 714168fce73SSepherosa Ziehau reqp->host_msg_len = recvlen; 715168fce73SSepherosa Ziehau reqp->host_msg_id = requestid; 716168fce73SSepherosa Ziehau reqp->rcv_buf = vss_buf; 717168fce73SSepherosa Ziehau reqp->sc = sc; 718168fce73SSepherosa Ziehau memcpy(&reqp->vss_req.msg, 719168fce73SSepherosa Ziehau (struct hv_vss_msg *)vss_buf, sizeof(struct hv_vss_msg)); 720168fce73SSepherosa Ziehau /* set the opt for users */ 721168fce73SSepherosa Ziehau switch (msg->hdr.vss_hdr.operation) { 722168fce73SSepherosa Ziehau case VSS_OP_FREEZE: 723168fce73SSepherosa Ziehau reqp->vss_req.opt_msg.opt = HV_VSS_FREEZE; 724168fce73SSepherosa Ziehau break; 725168fce73SSepherosa Ziehau case VSS_OP_THAW: 726168fce73SSepherosa Ziehau reqp->vss_req.opt_msg.opt = HV_VSS_THAW; 727168fce73SSepherosa Ziehau break; 728168fce73SSepherosa Ziehau case VSS_OP_HOT_BACKUP: 729168fce73SSepherosa Ziehau reqp->vss_req.opt_msg.opt = HV_VSS_CHECK; 730168fce73SSepherosa Ziehau break; 731168fce73SSepherosa Ziehau } 732168fce73SSepherosa Ziehau /* Use a timestamp as msg request ID */ 733168fce73SSepherosa Ziehau nanotime(&vm_ts); 734168fce73SSepherosa Ziehau reqp->vss_req.opt_msg.msgid = (vm_ts.tv_sec * NANOSEC) + vm_ts.tv_nsec; 735168fce73SSepherosa Ziehau } 736168fce73SSepherosa Ziehau 737168fce73SSepherosa Ziehau static hv_vss_req_internal* 738168fce73SSepherosa Ziehau hv_vss_get_new_req_locked(hv_vss_sc *sc) 739168fce73SSepherosa Ziehau { 740168fce73SSepherosa Ziehau hv_vss_req_internal *reqp; 741168fce73SSepherosa Ziehau if (!STAILQ_EMPTY(&sc->daemon_sc.to_notify_queue) || 742168fce73SSepherosa Ziehau !STAILQ_EMPTY(&sc->daemon_sc.to_ack_queue) || 743168fce73SSepherosa Ziehau !STAILQ_EMPTY(&sc->app_sc.to_notify_queue) || 744168fce73SSepherosa Ziehau !STAILQ_EMPTY(&sc->app_sc.to_ack_queue)) { 745168fce73SSepherosa Ziehau /* 746168fce73SSepherosa Ziehau * There is request coming from host before 747168fce73SSepherosa Ziehau * finishing previous requests 748168fce73SSepherosa Ziehau */ 749168fce73SSepherosa Ziehau hv_vss_log_info("%s: Warning: there is new request " 750168fce73SSepherosa Ziehau "coming before finishing previous requests\n", __func__); 751168fce73SSepherosa Ziehau return (NULL); 752168fce73SSepherosa Ziehau } 753168fce73SSepherosa Ziehau if (LIST_EMPTY(&sc->req_free_list)) { 754168fce73SSepherosa Ziehau /* TODO Error: no buffer */ 755168fce73SSepherosa Ziehau hv_vss_log_info("Error: No buffer\n"); 756168fce73SSepherosa Ziehau return (NULL); 757168fce73SSepherosa Ziehau } 758168fce73SSepherosa Ziehau reqp = LIST_FIRST(&sc->req_free_list); 759168fce73SSepherosa Ziehau LIST_REMOVE(reqp, link); 760168fce73SSepherosa Ziehau return (reqp); 761168fce73SSepherosa Ziehau } 762168fce73SSepherosa Ziehau 763168fce73SSepherosa Ziehau static void 764168fce73SSepherosa Ziehau hv_vss_start_notify(hv_vss_req_internal *reqp, uint32_t opt) 765168fce73SSepherosa Ziehau { 766168fce73SSepherosa Ziehau hv_vss_sc *sc = reqp->sc; 767168fce73SSepherosa Ziehau /* 768168fce73SSepherosa Ziehau * Freeze/Check notification sequence: kernel -> app -> daemon(fs) 769168fce73SSepherosa Ziehau * Thaw notification sequence: kernel -> daemon(fs) -> app 770168fce73SSepherosa Ziehau * 771168fce73SSepherosa Ziehau * We should wake up the daemon, in case it's doing poll(). 772168fce73SSepherosa Ziehau * The response should be received after 5s, otherwise, trigger timeout. 773168fce73SSepherosa Ziehau */ 774168fce73SSepherosa Ziehau switch (opt) { 775168fce73SSepherosa Ziehau case VSS_OP_FREEZE: 776168fce73SSepherosa Ziehau case VSS_OP_HOT_BACKUP: 777168fce73SSepherosa Ziehau if (sc->app_register_done) 778168fce73SSepherosa Ziehau hv_vss_notify(&sc->app_sc, reqp); 779168fce73SSepherosa Ziehau else 780168fce73SSepherosa Ziehau hv_vss_notify(&sc->daemon_sc, reqp); 781168fce73SSepherosa Ziehau callout_reset(&reqp->callout, TIMEOUT_LIMIT * hz, 782168fce73SSepherosa Ziehau hv_vss_timeout, reqp); 783168fce73SSepherosa Ziehau break; 784168fce73SSepherosa Ziehau case VSS_OP_THAW: 785168fce73SSepherosa Ziehau hv_vss_notify(&sc->daemon_sc, reqp); 786168fce73SSepherosa Ziehau callout_reset(&reqp->callout, TIMEOUT_LIMIT * hz, 787168fce73SSepherosa Ziehau hv_vss_timeout, reqp); 788168fce73SSepherosa Ziehau break; 789168fce73SSepherosa Ziehau } 790168fce73SSepherosa Ziehau } 791168fce73SSepherosa Ziehau 792168fce73SSepherosa Ziehau /* 793168fce73SSepherosa Ziehau * Function to read the vss request buffer from host 794168fce73SSepherosa Ziehau * and interact with daemon 795168fce73SSepherosa Ziehau */ 796168fce73SSepherosa Ziehau static void 797168fce73SSepherosa Ziehau hv_vss_process_request(void *context, int pending __unused) 798168fce73SSepherosa Ziehau { 799168fce73SSepherosa Ziehau uint8_t *vss_buf; 800168fce73SSepherosa Ziehau struct vmbus_channel *channel; 801168fce73SSepherosa Ziehau uint32_t recvlen = 0; 802168fce73SSepherosa Ziehau uint64_t requestid; 803168fce73SSepherosa Ziehau struct vmbus_icmsg_hdr *icmsghdrp; 804168fce73SSepherosa Ziehau int ret = 0; 805168fce73SSepherosa Ziehau hv_vss_sc *sc; 806168fce73SSepherosa Ziehau hv_vss_req_internal *reqp; 807168fce73SSepherosa Ziehau 808168fce73SSepherosa Ziehau hv_vss_log_info("%s: entering hv_vss_process_request\n", __func__); 809168fce73SSepherosa Ziehau 810168fce73SSepherosa Ziehau sc = (hv_vss_sc*)context; 8111eb6d711SSepherosa Ziehau vss_buf = sc->util_sc.ic_buf; 812168fce73SSepherosa Ziehau channel = vmbus_get_channel(sc->dev); 813168fce73SSepherosa Ziehau 814168fce73SSepherosa Ziehau recvlen = sc->util_sc.ic_buflen; 815168fce73SSepherosa Ziehau ret = vmbus_chan_recv(channel, vss_buf, &recvlen, &requestid); 816168fce73SSepherosa Ziehau KASSERT(ret != ENOBUFS, ("hvvss recvbuf is not large enough")); 817168fce73SSepherosa Ziehau /* XXX check recvlen to make sure that it contains enough data */ 818168fce73SSepherosa Ziehau 819168fce73SSepherosa Ziehau while ((ret == 0) && (recvlen > 0)) { 820168fce73SSepherosa Ziehau icmsghdrp = (struct vmbus_icmsg_hdr *)vss_buf; 821168fce73SSepherosa Ziehau 822168fce73SSepherosa Ziehau if (icmsghdrp->ic_type == HV_ICMSGTYPE_NEGOTIATE) { 823168fce73SSepherosa Ziehau ret = vmbus_ic_negomsg(&sc->util_sc, vss_buf, 824168fce73SSepherosa Ziehau &recvlen, VSS_FWVER, VSS_MSGVER); 825168fce73SSepherosa Ziehau hv_vss_respond_host(vss_buf, vmbus_get_channel(sc->dev), 826168fce73SSepherosa Ziehau recvlen, requestid, ret); 827168fce73SSepherosa Ziehau hv_vss_log_info("%s: version negotiated\n", __func__); 828168fce73SSepherosa Ziehau } else if (!hv_vss_is_daemon_killed_after_launch(sc)) { 829168fce73SSepherosa Ziehau struct hv_vss_msg* msg = (struct hv_vss_msg *)vss_buf; 830168fce73SSepherosa Ziehau switch(msg->hdr.vss_hdr.operation) { 831168fce73SSepherosa Ziehau case VSS_OP_FREEZE: 832168fce73SSepherosa Ziehau case VSS_OP_THAW: 833168fce73SSepherosa Ziehau case VSS_OP_HOT_BACKUP: 834168fce73SSepherosa Ziehau mtx_lock(&sc->pending_mutex); 835168fce73SSepherosa Ziehau reqp = hv_vss_get_new_req_locked(sc); 836168fce73SSepherosa Ziehau mtx_unlock(&sc->pending_mutex); 837168fce73SSepherosa Ziehau if (reqp == NULL) { 838168fce73SSepherosa Ziehau /* ignore this request from host */ 839168fce73SSepherosa Ziehau break; 840168fce73SSepherosa Ziehau } 841168fce73SSepherosa Ziehau hv_vss_init_req(reqp, recvlen, requestid, vss_buf, sc); 842168fce73SSepherosa Ziehau hv_vss_log_info("%s: receive %s (%ju) from host\n", 843168fce73SSepherosa Ziehau __func__, 844168fce73SSepherosa Ziehau vss_opt_name[reqp->vss_req.opt_msg.opt], 845168fce73SSepherosa Ziehau (uintmax_t)reqp->vss_req.opt_msg.msgid); 846168fce73SSepherosa Ziehau hv_vss_start_notify(reqp, msg->hdr.vss_hdr.operation); 847168fce73SSepherosa Ziehau break; 848168fce73SSepherosa Ziehau case VSS_OP_GET_DM_INFO: 849168fce73SSepherosa Ziehau hv_vss_log_info("%s: receive GET_DM_INFO from host\n", 850168fce73SSepherosa Ziehau __func__); 851168fce73SSepherosa Ziehau msg->body.dm_info.flags = 0; 852168fce73SSepherosa Ziehau hv_vss_respond_host(vss_buf, vmbus_get_channel(sc->dev), 853168fce73SSepherosa Ziehau recvlen, requestid, HV_S_OK); 854168fce73SSepherosa Ziehau break; 855168fce73SSepherosa Ziehau default: 856168fce73SSepherosa Ziehau device_printf(sc->dev, "Unknown opt from host: %d\n", 857168fce73SSepherosa Ziehau msg->hdr.vss_hdr.operation); 858168fce73SSepherosa Ziehau break; 859168fce73SSepherosa Ziehau } 860168fce73SSepherosa Ziehau } else { 861168fce73SSepherosa Ziehau /* daemon was killed for some reason after it was launched */ 862168fce73SSepherosa Ziehau struct hv_vss_msg* msg = (struct hv_vss_msg *)vss_buf; 863168fce73SSepherosa Ziehau switch(msg->hdr.vss_hdr.operation) { 864168fce73SSepherosa Ziehau case VSS_OP_FREEZE: 865168fce73SSepherosa Ziehau hv_vss_log_info("%s: response fail for FREEZE\n", 866168fce73SSepherosa Ziehau __func__); 867168fce73SSepherosa Ziehau break; 868168fce73SSepherosa Ziehau case VSS_OP_THAW: 869168fce73SSepherosa Ziehau hv_vss_log_info("%s: response fail for THAW\n", 870168fce73SSepherosa Ziehau __func__); 871168fce73SSepherosa Ziehau break; 872168fce73SSepherosa Ziehau case VSS_OP_HOT_BACKUP: 873168fce73SSepherosa Ziehau hv_vss_log_info("%s: response fail for HOT_BACKUP\n", 874168fce73SSepherosa Ziehau __func__); 875168fce73SSepherosa Ziehau msg->body.vss_cf.flags = VSS_HBU_NO_AUTO_RECOVERY; 876168fce73SSepherosa Ziehau break; 877168fce73SSepherosa Ziehau case VSS_OP_GET_DM_INFO: 878168fce73SSepherosa Ziehau hv_vss_log_info("%s: response fail for GET_DM_INFO\n", 879168fce73SSepherosa Ziehau __func__); 880168fce73SSepherosa Ziehau msg->body.dm_info.flags = 0; 881168fce73SSepherosa Ziehau break; 882168fce73SSepherosa Ziehau default: 883168fce73SSepherosa Ziehau device_printf(sc->dev, "Unknown opt from host: %d\n", 884168fce73SSepherosa Ziehau msg->hdr.vss_hdr.operation); 885168fce73SSepherosa Ziehau break; 886168fce73SSepherosa Ziehau } 887168fce73SSepherosa Ziehau hv_vss_respond_host(vss_buf, vmbus_get_channel(sc->dev), 888168fce73SSepherosa Ziehau recvlen, requestid, HV_E_FAIL); 889168fce73SSepherosa Ziehau } 890168fce73SSepherosa Ziehau /* 891168fce73SSepherosa Ziehau * Try reading next buffer 892168fce73SSepherosa Ziehau */ 893168fce73SSepherosa Ziehau recvlen = sc->util_sc.ic_buflen; 894168fce73SSepherosa Ziehau ret = vmbus_chan_recv(channel, vss_buf, &recvlen, &requestid); 895168fce73SSepherosa Ziehau KASSERT(ret != ENOBUFS, ("hvvss recvbuf is not large enough")); 896168fce73SSepherosa Ziehau /* XXX check recvlen to make sure that it contains enough data */ 897168fce73SSepherosa Ziehau 898168fce73SSepherosa Ziehau hv_vss_log_info("%s: read: context %p, ret =%d, recvlen=%d\n", 899168fce73SSepherosa Ziehau __func__, context, ret, recvlen); 900168fce73SSepherosa Ziehau } 901168fce73SSepherosa Ziehau } 902168fce73SSepherosa Ziehau 903168fce73SSepherosa Ziehau static int 904168fce73SSepherosa Ziehau hv_vss_probe(device_t dev) 905168fce73SSepherosa Ziehau { 906168fce73SSepherosa Ziehau return (vmbus_ic_probe(dev, vmbus_vss_descs)); 907168fce73SSepherosa Ziehau } 908168fce73SSepherosa Ziehau 909168fce73SSepherosa Ziehau static int 910168fce73SSepherosa Ziehau hv_vss_init_send_receive_queue(device_t dev) 911168fce73SSepherosa Ziehau { 912168fce73SSepherosa Ziehau hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev); 913168fce73SSepherosa Ziehau int i; 914168fce73SSepherosa Ziehau const int max_list = 4; /* It is big enough for the list */ 915168fce73SSepherosa Ziehau struct hv_vss_req_internal* reqp; 916168fce73SSepherosa Ziehau 917168fce73SSepherosa Ziehau LIST_INIT(&sc->req_free_list); 918168fce73SSepherosa Ziehau STAILQ_INIT(&sc->daemon_sc.to_notify_queue); 919168fce73SSepherosa Ziehau STAILQ_INIT(&sc->daemon_sc.to_ack_queue); 920168fce73SSepherosa Ziehau STAILQ_INIT(&sc->app_sc.to_notify_queue); 921168fce73SSepherosa Ziehau STAILQ_INIT(&sc->app_sc.to_ack_queue); 922168fce73SSepherosa Ziehau 923168fce73SSepherosa Ziehau for (i = 0; i < max_list; i++) { 924168fce73SSepherosa Ziehau reqp = malloc(sizeof(struct hv_vss_req_internal), 925168fce73SSepherosa Ziehau M_DEVBUF, M_WAITOK|M_ZERO); 926168fce73SSepherosa Ziehau LIST_INSERT_HEAD(&sc->req_free_list, reqp, link); 927168fce73SSepherosa Ziehau callout_init_mtx(&reqp->callout, &sc->pending_mutex, 0); 928168fce73SSepherosa Ziehau } 929168fce73SSepherosa Ziehau return (0); 930168fce73SSepherosa Ziehau } 931168fce73SSepherosa Ziehau 932168fce73SSepherosa Ziehau static int 933168fce73SSepherosa Ziehau hv_vss_destroy_send_receive_queue(device_t dev) 934168fce73SSepherosa Ziehau { 935168fce73SSepherosa Ziehau hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev); 936168fce73SSepherosa Ziehau hv_vss_req_internal* reqp; 937168fce73SSepherosa Ziehau 938168fce73SSepherosa Ziehau while (!LIST_EMPTY(&sc->req_free_list)) { 939168fce73SSepherosa Ziehau reqp = LIST_FIRST(&sc->req_free_list); 940168fce73SSepherosa Ziehau LIST_REMOVE(reqp, link); 941168fce73SSepherosa Ziehau free(reqp, M_DEVBUF); 942168fce73SSepherosa Ziehau } 943168fce73SSepherosa Ziehau 944168fce73SSepherosa Ziehau while (!STAILQ_EMPTY(&sc->daemon_sc.to_notify_queue)) { 945168fce73SSepherosa Ziehau reqp = STAILQ_FIRST(&sc->daemon_sc.to_notify_queue); 946168fce73SSepherosa Ziehau STAILQ_REMOVE_HEAD(&sc->daemon_sc.to_notify_queue, slink); 947168fce73SSepherosa Ziehau free(reqp, M_DEVBUF); 948168fce73SSepherosa Ziehau } 949168fce73SSepherosa Ziehau 950168fce73SSepherosa Ziehau while (!STAILQ_EMPTY(&sc->daemon_sc.to_ack_queue)) { 951168fce73SSepherosa Ziehau reqp = STAILQ_FIRST(&sc->daemon_sc.to_ack_queue); 952168fce73SSepherosa Ziehau STAILQ_REMOVE_HEAD(&sc->daemon_sc.to_ack_queue, slink); 953168fce73SSepherosa Ziehau free(reqp, M_DEVBUF); 954168fce73SSepherosa Ziehau } 955168fce73SSepherosa Ziehau 956168fce73SSepherosa Ziehau while (!STAILQ_EMPTY(&sc->app_sc.to_notify_queue)) { 957168fce73SSepherosa Ziehau reqp = STAILQ_FIRST(&sc->app_sc.to_notify_queue); 958168fce73SSepherosa Ziehau STAILQ_REMOVE_HEAD(&sc->app_sc.to_notify_queue, slink); 959168fce73SSepherosa Ziehau free(reqp, M_DEVBUF); 960168fce73SSepherosa Ziehau } 961168fce73SSepherosa Ziehau 962168fce73SSepherosa Ziehau while (!STAILQ_EMPTY(&sc->app_sc.to_ack_queue)) { 963168fce73SSepherosa Ziehau reqp = STAILQ_FIRST(&sc->app_sc.to_ack_queue); 964168fce73SSepherosa Ziehau STAILQ_REMOVE_HEAD(&sc->app_sc.to_ack_queue, slink); 965168fce73SSepherosa Ziehau free(reqp, M_DEVBUF); 966168fce73SSepherosa Ziehau } 967168fce73SSepherosa Ziehau return (0); 968168fce73SSepherosa Ziehau } 969168fce73SSepherosa Ziehau 970168fce73SSepherosa Ziehau static int 971168fce73SSepherosa Ziehau hv_vss_attach(device_t dev) 972168fce73SSepherosa Ziehau { 973168fce73SSepherosa Ziehau int error; 974168fce73SSepherosa Ziehau struct sysctl_oid_list *child; 975168fce73SSepherosa Ziehau struct sysctl_ctx_list *ctx; 976168fce73SSepherosa Ziehau 977168fce73SSepherosa Ziehau hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev); 978168fce73SSepherosa Ziehau 979168fce73SSepherosa Ziehau sc->dev = dev; 980168fce73SSepherosa Ziehau mtx_init(&sc->pending_mutex, "hv_vss pending mutex", NULL, MTX_DEF); 981168fce73SSepherosa Ziehau 982168fce73SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 983168fce73SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 984168fce73SSepherosa Ziehau 985168fce73SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "hv_vss_log", 986168fce73SSepherosa Ziehau CTLFLAG_RWTUN, &hv_vss_log, 0, "Hyperv VSS service log level"); 987168fce73SSepherosa Ziehau 988168fce73SSepherosa Ziehau TASK_INIT(&sc->task, 0, hv_vss_process_request, sc); 989168fce73SSepherosa Ziehau hv_vss_init_send_receive_queue(dev); 990168fce73SSepherosa Ziehau /* create character device for file system freeze/thaw */ 991168fce73SSepherosa Ziehau error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, 992168fce73SSepherosa Ziehau &sc->hv_vss_dev, 993168fce73SSepherosa Ziehau &hv_vss_cdevsw, 994168fce73SSepherosa Ziehau 0, 995168fce73SSepherosa Ziehau UID_ROOT, 996168fce73SSepherosa Ziehau GID_WHEEL, 997168fce73SSepherosa Ziehau 0640, 998168fce73SSepherosa Ziehau FS_VSS_DEV_NAME); 999168fce73SSepherosa Ziehau 1000168fce73SSepherosa Ziehau if (error != 0) { 1001168fce73SSepherosa Ziehau hv_vss_log_info("Fail to create '%s': %d\n", FS_VSS_DEV_NAME, error); 1002168fce73SSepherosa Ziehau return (error); 1003168fce73SSepherosa Ziehau } 1004168fce73SSepherosa Ziehau sc->hv_vss_dev->si_drv1 = &sc->daemon_sc; 1005168fce73SSepherosa Ziehau sc->daemon_sc.sc = sc; 1006168fce73SSepherosa Ziehau /* create character device for application freeze/thaw */ 1007168fce73SSepherosa Ziehau error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, 1008168fce73SSepherosa Ziehau &sc->hv_appvss_dev, 1009168fce73SSepherosa Ziehau &hv_appvss_cdevsw, 1010168fce73SSepherosa Ziehau 0, 1011168fce73SSepherosa Ziehau UID_ROOT, 1012168fce73SSepherosa Ziehau GID_WHEEL, 1013168fce73SSepherosa Ziehau 0640, 1014168fce73SSepherosa Ziehau APP_VSS_DEV_NAME); 1015168fce73SSepherosa Ziehau 1016168fce73SSepherosa Ziehau if (error != 0) { 1017168fce73SSepherosa Ziehau hv_vss_log_info("Fail to create '%s': %d\n", APP_VSS_DEV_NAME, error); 1018168fce73SSepherosa Ziehau return (error); 1019168fce73SSepherosa Ziehau } 1020168fce73SSepherosa Ziehau sc->hv_appvss_dev->si_drv1 = &sc->app_sc; 1021168fce73SSepherosa Ziehau sc->app_sc.sc = sc; 1022168fce73SSepherosa Ziehau 10231eb6d711SSepherosa Ziehau return (vmbus_ic_attach(dev, hv_vss_callback)); 1024168fce73SSepherosa Ziehau } 1025168fce73SSepherosa Ziehau 1026168fce73SSepherosa Ziehau static int 1027168fce73SSepherosa Ziehau hv_vss_detach(device_t dev) 1028168fce73SSepherosa Ziehau { 1029168fce73SSepherosa Ziehau hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev); 1030168fce73SSepherosa Ziehau mtx_destroy(&sc->pending_mutex); 1031168fce73SSepherosa Ziehau if (sc->daemon_sc.proc_task != NULL) { 1032168fce73SSepherosa Ziehau PROC_LOCK(sc->daemon_sc.proc_task); 1033168fce73SSepherosa Ziehau kern_psignal(sc->daemon_sc.proc_task, SIGKILL); 1034168fce73SSepherosa Ziehau PROC_UNLOCK(sc->daemon_sc.proc_task); 1035168fce73SSepherosa Ziehau } 1036168fce73SSepherosa Ziehau if (sc->app_sc.proc_task != NULL) { 1037168fce73SSepherosa Ziehau PROC_LOCK(sc->app_sc.proc_task); 1038168fce73SSepherosa Ziehau kern_psignal(sc->app_sc.proc_task, SIGKILL); 1039168fce73SSepherosa Ziehau PROC_UNLOCK(sc->app_sc.proc_task); 1040168fce73SSepherosa Ziehau } 1041168fce73SSepherosa Ziehau hv_vss_destroy_send_receive_queue(dev); 1042168fce73SSepherosa Ziehau destroy_dev(sc->hv_vss_dev); 1043168fce73SSepherosa Ziehau destroy_dev(sc->hv_appvss_dev); 10441eb6d711SSepherosa Ziehau return (vmbus_ic_detach(dev)); 1045168fce73SSepherosa Ziehau } 1046168fce73SSepherosa Ziehau 1047168fce73SSepherosa Ziehau static device_method_t vss_methods[] = { 1048168fce73SSepherosa Ziehau /* Device interface */ 1049168fce73SSepherosa Ziehau DEVMETHOD(device_probe, hv_vss_probe), 1050168fce73SSepherosa Ziehau DEVMETHOD(device_attach, hv_vss_attach), 1051168fce73SSepherosa Ziehau DEVMETHOD(device_detach, hv_vss_detach), 1052168fce73SSepherosa Ziehau { 0, 0 } 1053168fce73SSepherosa Ziehau }; 1054168fce73SSepherosa Ziehau 1055168fce73SSepherosa Ziehau static driver_t vss_driver = { "hvvss", vss_methods, sizeof(hv_vss_sc)}; 1056168fce73SSepherosa Ziehau 1057*c1cef544SJohn Baldwin DRIVER_MODULE(hv_vss, vmbus, vss_driver, NULL, NULL); 1058168fce73SSepherosa Ziehau MODULE_VERSION(hv_vss, 1); 1059168fce73SSepherosa Ziehau MODULE_DEPEND(hv_vss, vmbus, 1, 1, 1); 1060