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