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