xref: /freebsd/sys/dev/hyperv/utilities/hv_snapshot.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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