2 * Copyright (c) 2016 Microsoft Corp.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/kernel.h>
35 #include <sys/malloc.h>
37 #include <sys/module.h>
39 #include <sys/taskqueue.h>
40 #include <sys/selinfo.h>
41 #include <sys/sysctl.h>
44 #include <sys/queue.h>
45 #include <sys/kthread.h>
46 #include <sys/syscallsubr.h>
47 #include <sys/sysproto.h>
49 #include <sys/endian.h>
51 #include <sys/signal.h>
52 #include <sys/syslog.h>
53 #include <sys/systm.h>
54 #include <sys/mutex.h>
55 #include <sys/callout.h>
57 #include <dev/hyperv/include/hyperv.h>
58 #include <dev/hyperv/utilities/hv_utilreg.h>
59 #include <dev/hyperv/utilities/vmbus_icreg.h>
60 #include <dev/hyperv/utilities/vmbus_icvar.h>
62 #include "hv_snapshot.h"
67 #define VSS_MSGVER VMBUS_IC_VERSION(VSS_MAJOR, VSS_MINOR)
69 #define VSS_FWVER_MAJOR 3
70 #define VSS_FWVER VMBUS_IC_VERSION(VSS_FWVER_MAJOR, 0)
72 #define TIMEOUT_LIMIT (15) // seconds
80 * Following operations are only supported with IC version >= 5.0
82 VSS_OP_FREEZE, /* Freeze the file systems in the VM */
83 VSS_OP_THAW, /* Unfreeze the file systems */
85 VSS_OP_COUNT /* Number of operations, must be last */
89 * Header for all VSS messages.
92 struct vmbus_icmsg_hdr ic_hdr;
99 * Flag values for the hv_vss_check_feature. Here supports only
102 #define VSS_HBU_NO_AUTO_RECOVERY 0x00000005
104 struct hv_vss_check_feature {
108 struct hv_vss_check_dm_info {
114 struct hv_vss_hdr vss_hdr;
117 struct hv_vss_check_feature vss_cf;
118 struct hv_vss_check_dm_info dm_info;
123 struct hv_vss_opt_msg opt_msg; /* used to communicate with daemon */
124 struct hv_vss_msg msg; /* used to communicate with host */
127 /* hv_vss debug control */
128 static int hv_vss_log = 0;
130 #define hv_vss_log_error(...) do { \
131 if (hv_vss_log > 0) \
132 log(LOG_ERR, "hv_vss: " __VA_ARGS__); \
135 #define hv_vss_log_info(...) do { \
136 if (hv_vss_log > 1) \
137 log(LOG_INFO, "hv_vss: " __VA_ARGS__); \
140 static const struct vmbus_ic_desc vmbus_vss_descs[] = {
142 .ic_guid = { .hv_guid = {
143 0x29, 0x2e, 0xfa, 0x35, 0x23, 0xea, 0x36, 0x42,
144 0x96, 0xae, 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40} },
145 .ic_desc = "Hyper-V VSS"
150 static const char * vss_opt_name[] = {"None", "VSSCheck", "Freeze", "Thaw"};
152 /* character device prototypes */
153 static d_open_t hv_vss_dev_open;
154 static d_close_t hv_vss_dev_close;
155 static d_poll_t hv_vss_dev_daemon_poll;
156 static d_ioctl_t hv_vss_dev_daemon_ioctl;
158 static d_open_t hv_appvss_dev_open;
159 static d_close_t hv_appvss_dev_close;
160 static d_poll_t hv_appvss_dev_poll;
161 static d_ioctl_t hv_appvss_dev_ioctl;
163 /* hv_vss character device structure */
164 static struct cdevsw hv_vss_cdevsw =
166 .d_version = D_VERSION,
167 .d_open = hv_vss_dev_open,
168 .d_close = hv_vss_dev_close,
169 .d_poll = hv_vss_dev_daemon_poll,
170 .d_ioctl = hv_vss_dev_daemon_ioctl,
171 .d_name = FS_VSS_DEV_NAME,
174 static struct cdevsw hv_appvss_cdevsw =
176 .d_version = D_VERSION,
177 .d_open = hv_appvss_dev_open,
178 .d_close = hv_appvss_dev_close,
179 .d_poll = hv_appvss_dev_poll,
180 .d_ioctl = hv_appvss_dev_ioctl,
181 .d_name = APP_VSS_DEV_NAME,
186 * Global state to track cdev
188 struct hv_vss_dev_sc {
190 * msg was transferred from host to notify queue, and
191 * ack queue. Finally, it was recyled to free list.
193 STAILQ_HEAD(, hv_vss_req_internal) to_notify_queue;
194 STAILQ_HEAD(, hv_vss_req_internal) to_ack_queue;
195 struct hv_vss_sc *sc;
196 struct proc *proc_task;
197 struct selinfo hv_vss_selinfo;
200 * Global state to track and synchronize the transaction requests from the host.
201 * The VSS allows user to register their function to do freeze/thaw for application.
202 * VSS kernel will notify both vss daemon and user application if it is registered.
203 * The implementation state transition is illustrated by:
204 * https://clovertrail.github.io/assets/vssdot.png
206 typedef struct hv_vss_sc {
207 struct vmbus_ic_softc util_sc;
213 * mutex is used to protect access of list/queue,
214 * callout in request is also used this mutex.
216 struct mtx pending_mutex;
218 * req_free_list contains all free items
220 LIST_HEAD(, hv_vss_req_internal) req_free_list;
222 /* Indicates if daemon registered with driver */
223 boolean_t register_done;
225 boolean_t app_register_done;
227 /* cdev for file system freeze/thaw */
228 struct cdev *hv_vss_dev;
229 /* cdev for application freeze/thaw */
230 struct cdev *hv_appvss_dev;
233 struct hv_vss_dev_sc app_sc;
235 struct hv_vss_dev_sc daemon_sc;
238 typedef struct hv_vss_req_internal {
239 LIST_ENTRY(hv_vss_req_internal) link;
240 STAILQ_ENTRY(hv_vss_req_internal) slink;
241 struct hv_vss_req vss_req;
243 /* Rcv buffer for communicating with the host*/
245 /* Length of host message */
246 uint32_t host_msg_len;
247 /* Host message id */
248 uint64_t host_msg_id;
252 struct callout callout;
253 } hv_vss_req_internal;
255 #define SEARCH_REMOVE_REQ_LOCKED(reqp, queue, link, tmp, id) \
257 STAILQ_FOREACH_SAFE(reqp, queue, link, tmp) { \
258 if (reqp->vss_req.opt_msg.msgid == id) { \
259 STAILQ_REMOVE(queue, \
260 reqp, hv_vss_req_internal, link); \
267 hv_vss_is_daemon_killed_after_launch(hv_vss_sc *sc)
269 return (!sc->register_done && sc->daemon_sc.proc_task);
273 * Callback routine that gets called whenever there is a message from host
276 hv_vss_callback(struct vmbus_channel *chan __unused, void *context)
278 hv_vss_sc *sc = (hv_vss_sc*)context;
279 if (hv_vss_is_daemon_killed_after_launch(sc))
280 hv_vss_log_info("%s: daemon was killed!\n", __func__);
281 if (sc->register_done || sc->daemon_sc.proc_task) {
282 hv_vss_log_info("%s: Queuing work item\n", __func__);
283 if (hv_vss_is_daemon_killed_after_launch(sc))
284 hv_vss_log_info("%s: daemon was killed!\n", __func__);
285 taskqueue_enqueue(taskqueue_thread, &sc->task);
287 hv_vss_log_info("%s: daemon has never been registered\n", __func__);
289 hv_vss_log_info("%s: received msg from host\n", __func__);
292 * Send the response back to the host.
295 hv_vss_respond_host(uint8_t *rcv_buf, struct vmbus_channel *ch,
296 uint32_t recvlen, uint64_t requestid, uint32_t error)
298 struct vmbus_icmsg_hdr *hv_icmsg_hdrp;
300 hv_icmsg_hdrp = (struct vmbus_icmsg_hdr *)rcv_buf;
302 hv_icmsg_hdrp->ic_status = error;
303 hv_icmsg_hdrp->ic_flags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE;
305 error = vmbus_chan_send(ch, VMBUS_CHANPKT_TYPE_INBAND, 0,
306 rcv_buf, recvlen, requestid);
308 hv_vss_log_info("%s: hv_vss_respond_host: sendpacket error:%d\n",
313 hv_vss_notify_host_result_locked(struct hv_vss_req_internal *reqp, uint32_t status)
315 struct hv_vss_msg* msg = (struct hv_vss_msg *)reqp->rcv_buf;
316 hv_vss_sc *sc = reqp->sc;
317 if (reqp->vss_req.opt_msg.opt == HV_VSS_CHECK) {
318 msg->body.vss_cf.flags = VSS_HBU_NO_AUTO_RECOVERY;
320 hv_vss_log_info("%s, %s response %s to host\n", __func__,
321 vss_opt_name[reqp->vss_req.opt_msg.opt],
322 status == HV_S_OK ? "Success" : "Fail");
323 hv_vss_respond_host(reqp->rcv_buf, vmbus_get_channel(reqp->sc->dev),
324 reqp->host_msg_len, reqp->host_msg_id, status);
325 /* recycle the request */
326 LIST_INSERT_HEAD(&sc->req_free_list, reqp, link);
330 hv_vss_notify_host_result(struct hv_vss_req_internal *reqp, uint32_t status)
332 mtx_lock(&reqp->sc->pending_mutex);
333 hv_vss_notify_host_result_locked(reqp, status);
334 mtx_unlock(&reqp->sc->pending_mutex);
338 hv_vss_cp_vssreq_to_user(struct hv_vss_req_internal *reqp,
339 struct hv_vss_opt_msg *userdata)
341 struct hv_vss_req *hv_vss_dev_buf;
342 hv_vss_dev_buf = &reqp->vss_req;
343 hv_vss_dev_buf->opt_msg.opt = HV_VSS_NONE;
344 switch (reqp->vss_req.msg.hdr.vss_hdr.operation) {
346 hv_vss_dev_buf->opt_msg.opt = HV_VSS_FREEZE;
349 hv_vss_dev_buf->opt_msg.opt = HV_VSS_THAW;
351 case VSS_OP_HOT_BACKUP:
352 hv_vss_dev_buf->opt_msg.opt = HV_VSS_CHECK;
355 *userdata = hv_vss_dev_buf->opt_msg;
356 hv_vss_log_info("%s, read data from user for "
357 "%s (%ju) \n", __func__, vss_opt_name[userdata->opt],
358 (uintmax_t)userdata->msgid);
362 * Remove the request id from app notifiy or ack queue,
363 * and recyle the request by inserting it to free list.
365 * When app was notified but not yet sending ack, the request
366 * should locate in either notify queue or ack queue.
368 static struct hv_vss_req_internal*
369 hv_vss_drain_req_queue_locked(hv_vss_sc *sc, uint64_t req_id)
371 struct hv_vss_req_internal *reqp, *tmp;
372 SEARCH_REMOVE_REQ_LOCKED(reqp, &sc->daemon_sc.to_notify_queue,
375 SEARCH_REMOVE_REQ_LOCKED(reqp, &sc->daemon_sc.to_ack_queue,
378 SEARCH_REMOVE_REQ_LOCKED(reqp, &sc->app_sc.to_notify_queue,
381 SEARCH_REMOVE_REQ_LOCKED(reqp, &sc->app_sc.to_ack_queue, slink,
386 * Actions for daemon who has been notified.
389 hv_vss_notified(struct hv_vss_dev_sc *dev_sc, struct hv_vss_opt_msg *userdata)
391 struct hv_vss_req_internal *reqp;
392 mtx_lock(&dev_sc->sc->pending_mutex);
393 if (!STAILQ_EMPTY(&dev_sc->to_notify_queue)) {
394 reqp = STAILQ_FIRST(&dev_sc->to_notify_queue);
395 hv_vss_cp_vssreq_to_user(reqp, userdata);
396 STAILQ_REMOVE_HEAD(&dev_sc->to_notify_queue, slink);
397 /* insert the msg to queue for write */
398 STAILQ_INSERT_TAIL(&dev_sc->to_ack_queue, reqp, slink);
399 userdata->status = VSS_SUCCESS;
401 /* Timeout occur, thus request was removed from queue. */
402 hv_vss_log_info("%s: notify queue is empty!\n", __func__);
403 userdata->status = VSS_FAIL;
405 mtx_unlock(&dev_sc->sc->pending_mutex);
409 hv_vss_notify(struct hv_vss_dev_sc *dev_sc, struct hv_vss_req_internal *reqp)
411 uint32_t opt = reqp->vss_req.opt_msg.opt;
412 mtx_lock(&dev_sc->sc->pending_mutex);
413 STAILQ_INSERT_TAIL(&dev_sc->to_notify_queue, reqp, slink);
414 hv_vss_log_info("%s: issuing query %s (%ju) to %s\n", __func__,
415 vss_opt_name[opt], (uintmax_t)reqp->vss_req.opt_msg.msgid,
416 &dev_sc->sc->app_sc == dev_sc ? "app" : "daemon");
417 mtx_unlock(&dev_sc->sc->pending_mutex);
418 selwakeup(&dev_sc->hv_vss_selinfo);
422 * Actions for daemon who has acknowledged.
425 hv_vss_daemon_acked(struct hv_vss_dev_sc *dev_sc, struct hv_vss_opt_msg *userdata)
427 struct hv_vss_req_internal *reqp, *tmp;
433 req_id = userdata->msgid;
434 status = userdata->status;
435 /* make sure the reserved fields are all zeros. */
436 memset(&userdata->reserved, 0, sizeof(struct hv_vss_opt_msg) -
437 __offsetof(struct hv_vss_opt_msg, reserved));
438 mtx_lock(&dev_sc->sc->pending_mutex);
439 SEARCH_REMOVE_REQ_LOCKED(reqp, &dev_sc->to_ack_queue, slink, tmp, req_id);
440 mtx_unlock(&dev_sc->sc->pending_mutex);
442 hv_vss_log_info("%s Timeout: fail to find daemon ack request\n",
444 userdata->status = VSS_FAIL;
447 KASSERT(opt == reqp->vss_req.opt_msg.opt, ("Mismatched VSS operation!"));
448 hv_vss_log_info("%s, get response %d from daemon for %s (%ju) \n", __func__,
449 status, vss_opt_name[opt], (uintmax_t)req_id);
453 callout_drain(&reqp->callout);
454 hv_vss_notify_host_result(reqp,
455 status == VSS_SUCCESS ? HV_S_OK : HV_E_FAIL);
458 if (dev_sc->sc->app_register_done) {
459 if (status == VSS_SUCCESS) {
460 hv_vss_notify(&dev_sc->sc->app_sc, reqp);
463 callout_drain(&reqp->callout);
464 hv_vss_notify_host_result(reqp, HV_E_FAIL);
467 callout_drain(&reqp->callout);
468 hv_vss_notify_host_result(reqp,
469 status == VSS_SUCCESS ? HV_S_OK : HV_E_FAIL);
476 * Actions for app who has acknowledged.
479 hv_vss_app_acked(struct hv_vss_dev_sc *dev_sc, struct hv_vss_opt_msg *userdata)
481 struct hv_vss_req_internal *reqp, *tmp;
487 req_id = userdata->msgid;
488 status = userdata->status;
489 /* make sure the reserved fields are all zeros. */
490 memset(&userdata->reserved, 0, sizeof(struct hv_vss_opt_msg) -
491 __offsetof(struct hv_vss_opt_msg, reserved));
492 mtx_lock(&dev_sc->sc->pending_mutex);
493 SEARCH_REMOVE_REQ_LOCKED(reqp, &dev_sc->to_ack_queue, slink, tmp, req_id);
494 mtx_unlock(&dev_sc->sc->pending_mutex);
496 hv_vss_log_info("%s Timeout: fail to find app ack request\n",
498 userdata->status = VSS_FAIL;
501 KASSERT(opt == reqp->vss_req.opt_msg.opt, ("Mismatched VSS operation!"));
502 hv_vss_log_info("%s, get response %d from app for %s (%ju) \n",
503 __func__, status, vss_opt_name[opt], (uintmax_t)req_id);
504 if (dev_sc->sc->register_done) {
508 if (status == VSS_SUCCESS) {
509 hv_vss_notify(&dev_sc->sc->daemon_sc, reqp);
512 callout_drain(&reqp->callout);
513 hv_vss_notify_host_result(reqp, HV_E_FAIL);
517 callout_drain(&reqp->callout);
518 hv_vss_notify_host_result(reqp,
519 status == VSS_SUCCESS ? HV_S_OK : HV_E_FAIL);
523 hv_vss_log_info("%s, Fatal: vss daemon was killed\n", __func__);
528 hv_vss_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
530 struct proc *td_proc;
531 td_proc = td->td_proc;
533 struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1;
534 hv_vss_log_info("%s: %s opens device \"%s\" successfully.\n",
535 __func__, td_proc->p_comm, FS_VSS_DEV_NAME);
537 if (dev_sc->sc->register_done)
540 dev_sc->sc->register_done = true;
541 hv_vss_callback(vmbus_get_channel(dev_sc->sc->dev), dev_sc->sc);
543 dev_sc->proc_task = curproc;
548 hv_vss_dev_close(struct cdev *dev, int fflag __unused, int devtype __unused,
551 struct proc *td_proc;
552 td_proc = td->td_proc;
554 struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1;
556 hv_vss_log_info("%s: %s closes device \"%s\"\n",
557 __func__, td_proc->p_comm, FS_VSS_DEV_NAME);
558 dev_sc->sc->register_done = false;
563 hv_vss_dev_daemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
566 struct proc *td_proc;
567 struct hv_vss_dev_sc *sc;
569 td_proc = td->td_proc;
570 sc = (struct hv_vss_dev_sc*)dev->si_drv1;
572 hv_vss_log_info("%s: %s invoked vss ioctl\n", __func__, td_proc->p_comm);
574 struct hv_vss_opt_msg* userdata = (struct hv_vss_opt_msg*)data;
577 hv_vss_notified(sc, userdata);
580 hv_vss_daemon_acked(sc, userdata);
587 * hv_vss_daemon poll invokes this function to check if data is available
588 * for daemon to read.
591 hv_vss_dev_daemon_poll(struct cdev *dev, int events, struct thread *td)
594 struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1;
596 mtx_lock(&dev_sc->sc->pending_mutex);
598 * if there is data ready, inform daemon's poll
600 if (!STAILQ_EMPTY(&dev_sc->to_notify_queue))
603 selrecord(td, &dev_sc->hv_vss_selinfo);
604 hv_vss_log_info("%s return 0x%x\n", __func__, revent);
605 mtx_unlock(&dev_sc->sc->pending_mutex);
610 hv_appvss_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
612 struct proc *td_proc;
613 td_proc = td->td_proc;
615 struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1;
616 hv_vss_log_info("%s: %s opens device \"%s\" successfully.\n",
617 __func__, td_proc->p_comm, APP_VSS_DEV_NAME);
619 if (dev_sc->sc->app_register_done)
622 dev_sc->sc->app_register_done = true;
623 dev_sc->proc_task = curproc;
628 hv_appvss_dev_close(struct cdev *dev, int fflag __unused, int devtype __unused,
631 struct proc *td_proc;
632 td_proc = td->td_proc;
634 struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1;
636 hv_vss_log_info("%s: %s closes device \"%s\".\n",
637 __func__, td_proc->p_comm, APP_VSS_DEV_NAME);
638 dev_sc->sc->app_register_done = false;
643 hv_appvss_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
646 struct proc *td_proc;
647 struct hv_vss_dev_sc *dev_sc;
649 td_proc = td->td_proc;
650 dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1;
652 hv_vss_log_info("%s: %s invoked vss ioctl\n", __func__, td_proc->p_comm);
654 struct hv_vss_opt_msg* userdata = (struct hv_vss_opt_msg*)data;
657 hv_vss_notified(dev_sc, userdata);
660 hv_vss_app_acked(dev_sc, userdata);
667 * hv_vss_daemon poll invokes this function to check if data is available
668 * for daemon to read.
671 hv_appvss_dev_poll(struct cdev *dev, int events, struct thread *td)
674 struct hv_vss_dev_sc *dev_sc = (struct hv_vss_dev_sc*)dev->si_drv1;
676 mtx_lock(&dev_sc->sc->pending_mutex);
678 * if there is data ready, inform daemon's poll
680 if (!STAILQ_EMPTY(&dev_sc->to_notify_queue))
683 selrecord(td, &dev_sc->hv_vss_selinfo);
684 hv_vss_log_info("%s return 0x%x\n", __func__, revent);
685 mtx_unlock(&dev_sc->sc->pending_mutex);
690 hv_vss_timeout(void *arg)
692 hv_vss_req_internal *reqp = arg;
693 hv_vss_req_internal *request;
694 hv_vss_sc* sc = reqp->sc;
695 uint64_t req_id = reqp->vss_req.opt_msg.msgid;
696 /* This thread is locked */
697 KASSERT(mtx_owned(&sc->pending_mutex), ("mutex lock is not owned!"));
698 request = hv_vss_drain_req_queue_locked(sc, req_id);
699 KASSERT(request != NULL, ("timeout but fail to find request"));
700 hv_vss_notify_host_result_locked(reqp, HV_E_FAIL);
704 * This routine is called whenever a message is received from the host
707 hv_vss_init_req(hv_vss_req_internal *reqp,
708 uint32_t recvlen, uint64_t requestid, uint8_t *vss_buf, hv_vss_sc *sc)
710 struct timespec vm_ts;
711 struct hv_vss_msg* msg = (struct hv_vss_msg *)vss_buf;
713 memset(reqp, 0, __offsetof(hv_vss_req_internal, callout));
714 reqp->host_msg_len = recvlen;
715 reqp->host_msg_id = requestid;
716 reqp->rcv_buf = vss_buf;
718 memcpy(&reqp->vss_req.msg,
719 (struct hv_vss_msg *)vss_buf, sizeof(struct hv_vss_msg));
720 /* set the opt for users */
721 switch (msg->hdr.vss_hdr.operation) {
723 reqp->vss_req.opt_msg.opt = HV_VSS_FREEZE;
726 reqp->vss_req.opt_msg.opt = HV_VSS_THAW;
728 case VSS_OP_HOT_BACKUP:
729 reqp->vss_req.opt_msg.opt = HV_VSS_CHECK;
732 /* Use a timestamp as msg request ID */
734 reqp->vss_req.opt_msg.msgid = (vm_ts.tv_sec * NANOSEC) + vm_ts.tv_nsec;
737 static hv_vss_req_internal*
738 hv_vss_get_new_req_locked(hv_vss_sc *sc)
740 hv_vss_req_internal *reqp;
741 if (!STAILQ_EMPTY(&sc->daemon_sc.to_notify_queue) ||
742 !STAILQ_EMPTY(&sc->daemon_sc.to_ack_queue) ||
743 !STAILQ_EMPTY(&sc->app_sc.to_notify_queue) ||
744 !STAILQ_EMPTY(&sc->app_sc.to_ack_queue)) {
746 * There is request coming from host before
747 * finishing previous requests
749 hv_vss_log_info("%s: Warning: there is new request "
750 "coming before finishing previous requests\n", __func__);
753 if (LIST_EMPTY(&sc->req_free_list)) {
754 /* TODO Error: no buffer */
755 hv_vss_log_info("Error: No buffer\n");
758 reqp = LIST_FIRST(&sc->req_free_list);
759 LIST_REMOVE(reqp, link);
764 hv_vss_start_notify(hv_vss_req_internal *reqp, uint32_t opt)
766 hv_vss_sc *sc = reqp->sc;
768 * Freeze/Check notification sequence: kernel -> app -> daemon(fs)
769 * Thaw notification sequence: kernel -> daemon(fs) -> app
771 * We should wake up the daemon, in case it's doing poll().
772 * The response should be received after 5s, otherwise, trigger timeout.
776 case VSS_OP_HOT_BACKUP:
777 if (sc->app_register_done)
778 hv_vss_notify(&sc->app_sc, reqp);
780 hv_vss_notify(&sc->daemon_sc, reqp);
781 callout_reset(&reqp->callout, TIMEOUT_LIMIT * hz,
782 hv_vss_timeout, reqp);
785 hv_vss_notify(&sc->daemon_sc, reqp);
786 callout_reset(&reqp->callout, TIMEOUT_LIMIT * hz,
787 hv_vss_timeout, reqp);
793 * Function to read the vss request buffer from host
794 * and interact with daemon
797 hv_vss_process_request(void *context, int pending __unused)
800 struct vmbus_channel *channel;
801 uint32_t recvlen = 0;
803 struct vmbus_icmsg_hdr *icmsghdrp;
806 hv_vss_req_internal *reqp;
808 hv_vss_log_info("%s: entering hv_vss_process_request\n", __func__);
810 sc = (hv_vss_sc*)context;
811 vss_buf = sc->util_sc.ic_buf;
812 channel = vmbus_get_channel(sc->dev);
814 recvlen = sc->util_sc.ic_buflen;
815 ret = vmbus_chan_recv(channel, vss_buf, &recvlen, &requestid);
816 KASSERT(ret != ENOBUFS, ("hvvss recvbuf is not large enough"));
817 /* XXX check recvlen to make sure that it contains enough data */
819 while ((ret == 0) && (recvlen > 0)) {
820 icmsghdrp = (struct vmbus_icmsg_hdr *)vss_buf;
822 if (icmsghdrp->ic_type == HV_ICMSGTYPE_NEGOTIATE) {
823 ret = vmbus_ic_negomsg(&sc->util_sc, vss_buf,
824 &recvlen, VSS_FWVER, VSS_MSGVER);
825 hv_vss_respond_host(vss_buf, vmbus_get_channel(sc->dev),
826 recvlen, requestid, ret);
827 hv_vss_log_info("%s: version negotiated\n", __func__);
828 } else if (!hv_vss_is_daemon_killed_after_launch(sc)) {
829 struct hv_vss_msg* msg = (struct hv_vss_msg *)vss_buf;
830 switch(msg->hdr.vss_hdr.operation) {
833 case VSS_OP_HOT_BACKUP:
834 mtx_lock(&sc->pending_mutex);
835 reqp = hv_vss_get_new_req_locked(sc);
836 mtx_unlock(&sc->pending_mutex);
838 /* ignore this request from host */
841 hv_vss_init_req(reqp, recvlen, requestid, vss_buf, sc);
842 hv_vss_log_info("%s: receive %s (%ju) from host\n",
844 vss_opt_name[reqp->vss_req.opt_msg.opt],
845 (uintmax_t)reqp->vss_req.opt_msg.msgid);
846 hv_vss_start_notify(reqp, msg->hdr.vss_hdr.operation);
848 case VSS_OP_GET_DM_INFO:
849 hv_vss_log_info("%s: receive GET_DM_INFO from host\n",
851 msg->body.dm_info.flags = 0;
852 hv_vss_respond_host(vss_buf, vmbus_get_channel(sc->dev),
853 recvlen, requestid, HV_S_OK);
856 device_printf(sc->dev, "Unknown opt from host: %d\n",
857 msg->hdr.vss_hdr.operation);
861 /* daemon was killed for some reason after it was launched */
862 struct hv_vss_msg* msg = (struct hv_vss_msg *)vss_buf;
863 switch(msg->hdr.vss_hdr.operation) {
865 hv_vss_log_info("%s: response fail for FREEZE\n",
869 hv_vss_log_info("%s: response fail for THAW\n",
872 case VSS_OP_HOT_BACKUP:
873 hv_vss_log_info("%s: response fail for HOT_BACKUP\n",
875 msg->body.vss_cf.flags = VSS_HBU_NO_AUTO_RECOVERY;
877 case VSS_OP_GET_DM_INFO:
878 hv_vss_log_info("%s: response fail for GET_DM_INFO\n",
880 msg->body.dm_info.flags = 0;
883 device_printf(sc->dev, "Unknown opt from host: %d\n",
884 msg->hdr.vss_hdr.operation);
887 hv_vss_respond_host(vss_buf, vmbus_get_channel(sc->dev),
888 recvlen, requestid, HV_E_FAIL);
891 * Try reading next buffer
893 recvlen = sc->util_sc.ic_buflen;
894 ret = vmbus_chan_recv(channel, vss_buf, &recvlen, &requestid);
895 KASSERT(ret != ENOBUFS, ("hvvss recvbuf is not large enough"));
896 /* XXX check recvlen to make sure that it contains enough data */
898 hv_vss_log_info("%s: read: context %p, ret =%d, recvlen=%d\n",
899 __func__, context, ret, recvlen);
904 hv_vss_probe(device_t dev)
906 return (vmbus_ic_probe(dev, vmbus_vss_descs));
910 hv_vss_init_send_receive_queue(device_t dev)
912 hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev);
914 const int max_list = 4; /* It is big enough for the list */
915 struct hv_vss_req_internal* reqp;
917 LIST_INIT(&sc->req_free_list);
918 STAILQ_INIT(&sc->daemon_sc.to_notify_queue);
919 STAILQ_INIT(&sc->daemon_sc.to_ack_queue);
920 STAILQ_INIT(&sc->app_sc.to_notify_queue);
921 STAILQ_INIT(&sc->app_sc.to_ack_queue);
923 for (i = 0; i < max_list; i++) {
924 reqp = malloc(sizeof(struct hv_vss_req_internal),
925 M_DEVBUF, M_WAITOK|M_ZERO);
926 LIST_INSERT_HEAD(&sc->req_free_list, reqp, link);
927 callout_init_mtx(&reqp->callout, &sc->pending_mutex, 0);
933 hv_vss_destroy_send_receive_queue(device_t dev)
935 hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev);
936 hv_vss_req_internal* reqp;
938 while (!LIST_EMPTY(&sc->req_free_list)) {
939 reqp = LIST_FIRST(&sc->req_free_list);
940 LIST_REMOVE(reqp, link);
941 free(reqp, M_DEVBUF);
944 while (!STAILQ_EMPTY(&sc->daemon_sc.to_notify_queue)) {
945 reqp = STAILQ_FIRST(&sc->daemon_sc.to_notify_queue);
946 STAILQ_REMOVE_HEAD(&sc->daemon_sc.to_notify_queue, slink);
947 free(reqp, M_DEVBUF);
950 while (!STAILQ_EMPTY(&sc->daemon_sc.to_ack_queue)) {
951 reqp = STAILQ_FIRST(&sc->daemon_sc.to_ack_queue);
952 STAILQ_REMOVE_HEAD(&sc->daemon_sc.to_ack_queue, slink);
953 free(reqp, M_DEVBUF);
956 while (!STAILQ_EMPTY(&sc->app_sc.to_notify_queue)) {
957 reqp = STAILQ_FIRST(&sc->app_sc.to_notify_queue);
958 STAILQ_REMOVE_HEAD(&sc->app_sc.to_notify_queue, slink);
959 free(reqp, M_DEVBUF);
962 while (!STAILQ_EMPTY(&sc->app_sc.to_ack_queue)) {
963 reqp = STAILQ_FIRST(&sc->app_sc.to_ack_queue);
964 STAILQ_REMOVE_HEAD(&sc->app_sc.to_ack_queue, slink);
965 free(reqp, M_DEVBUF);
971 hv_vss_attach(device_t dev)
974 struct sysctl_oid_list *child;
975 struct sysctl_ctx_list *ctx;
977 hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev);
980 mtx_init(&sc->pending_mutex, "hv_vss pending mutex", NULL, MTX_DEF);
982 ctx = device_get_sysctl_ctx(dev);
983 child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
985 SYSCTL_ADD_INT(ctx, child, OID_AUTO, "hv_vss_log",
986 CTLFLAG_RWTUN, &hv_vss_log, 0, "Hyperv VSS service log level");
988 TASK_INIT(&sc->task, 0, hv_vss_process_request, sc);
989 hv_vss_init_send_receive_queue(dev);
990 /* create character device for file system freeze/thaw */
991 error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
1001 hv_vss_log_info("Fail to create '%s': %d\n", FS_VSS_DEV_NAME, error);
1004 sc->hv_vss_dev->si_drv1 = &sc->daemon_sc;
1005 sc->daemon_sc.sc = sc;
1006 /* create character device for application freeze/thaw */
1007 error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
1017 hv_vss_log_info("Fail to create '%s': %d\n", APP_VSS_DEV_NAME, error);
1020 sc->hv_appvss_dev->si_drv1 = &sc->app_sc;
1023 return (vmbus_ic_attach(dev, hv_vss_callback));
1027 hv_vss_detach(device_t dev)
1029 hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev);
1030 mtx_destroy(&sc->pending_mutex);
1031 if (sc->daemon_sc.proc_task != NULL) {
1032 PROC_LOCK(sc->daemon_sc.proc_task);
1033 kern_psignal(sc->daemon_sc.proc_task, SIGKILL);
1034 PROC_UNLOCK(sc->daemon_sc.proc_task);
1036 if (sc->app_sc.proc_task != NULL) {
1037 PROC_LOCK(sc->app_sc.proc_task);
1038 kern_psignal(sc->app_sc.proc_task, SIGKILL);
1039 PROC_UNLOCK(sc->app_sc.proc_task);
1041 hv_vss_destroy_send_receive_queue(dev);
1042 destroy_dev(sc->hv_vss_dev);
1043 destroy_dev(sc->hv_appvss_dev);
1044 return (vmbus_ic_detach(dev));
1047 static device_method_t vss_methods[] = {
1048 /* Device interface */
1049 DEVMETHOD(device_probe, hv_vss_probe),
1050 DEVMETHOD(device_attach, hv_vss_attach),
1051 DEVMETHOD(device_detach, hv_vss_detach),
1055 static driver_t vss_driver = { "hvvss", vss_methods, sizeof(hv_vss_sc)};
1057 static devclass_t vss_devclass;
1059 DRIVER_MODULE(hv_vss, vmbus, vss_driver, vss_devclass, NULL, NULL);
1060 MODULE_VERSION(hv_vss, 1);
1061 MODULE_DEPEND(hv_vss, vmbus, 1, 1, 1);