xref: /freebsd/contrib/hyperv/tools/hv_vss_daemon.c (revision 168fce73b59d6023cab45d063a452551a1f2103e)
1*168fce73SSepherosa Ziehau #include <string.h>
2*168fce73SSepherosa Ziehau #include <stdio.h>
3*168fce73SSepherosa Ziehau #include <sys/ioctl.h>
4*168fce73SSepherosa Ziehau #include <sys/param.h>
5*168fce73SSepherosa Ziehau #include <sys/ucred.h>
6*168fce73SSepherosa Ziehau #include <sys/mount.h>
7*168fce73SSepherosa Ziehau #include <sys/types.h>
8*168fce73SSepherosa Ziehau 
9*168fce73SSepherosa Ziehau #include <unistd.h>
10*168fce73SSepherosa Ziehau #include <stdlib.h>
11*168fce73SSepherosa Ziehau #include <poll.h>
12*168fce73SSepherosa Ziehau #include <stdint.h>
13*168fce73SSepherosa Ziehau #include <syslog.h>
14*168fce73SSepherosa Ziehau #include <errno.h>
15*168fce73SSepherosa Ziehau #include <err.h>
16*168fce73SSepherosa Ziehau #include <fcntl.h>
17*168fce73SSepherosa Ziehau #include <ufs/ffs/fs.h>
18*168fce73SSepherosa Ziehau #include <paths.h>
19*168fce73SSepherosa Ziehau #include <sysexits.h>
20*168fce73SSepherosa Ziehau 
21*168fce73SSepherosa Ziehau #include "hv_snapshot.h"
22*168fce73SSepherosa Ziehau 
23*168fce73SSepherosa Ziehau #define UNDEF_FREEZE_THAW       (0)
24*168fce73SSepherosa Ziehau #define FREEZE                  (1)
25*168fce73SSepherosa Ziehau #define THAW                    (2)
26*168fce73SSepherosa Ziehau 
27*168fce73SSepherosa Ziehau #define	VSS_LOG(priority, format, args...) do	{				\
28*168fce73SSepherosa Ziehau 		if (is_debugging == 1) {					\
29*168fce73SSepherosa Ziehau 			if (is_daemon == 1)					\
30*168fce73SSepherosa Ziehau 				syslog(priority, format, ## args);		\
31*168fce73SSepherosa Ziehau 			else							\
32*168fce73SSepherosa Ziehau 				printf(format, ## args);			\
33*168fce73SSepherosa Ziehau 		} else {							\
34*168fce73SSepherosa Ziehau 			if (priority < LOG_DEBUG) {				\
35*168fce73SSepherosa Ziehau 				if (is_daemon == 1)				\
36*168fce73SSepherosa Ziehau 					syslog(priority, format, ## args);	\
37*168fce73SSepherosa Ziehau 				else						\
38*168fce73SSepherosa Ziehau 					printf(format, ## args);		\
39*168fce73SSepherosa Ziehau 			}							\
40*168fce73SSepherosa Ziehau 		}								\
41*168fce73SSepherosa Ziehau 	} while(0)
42*168fce73SSepherosa Ziehau 
43*168fce73SSepherosa Ziehau static int is_daemon = 1;
44*168fce73SSepherosa Ziehau static int is_debugging = 0;
45*168fce73SSepherosa Ziehau static int g_ufs_suspend_handle = -1;
46*168fce73SSepherosa Ziehau 
47*168fce73SSepherosa Ziehau static const char *dev = "/dev";
48*168fce73SSepherosa Ziehau 
49*168fce73SSepherosa Ziehau static int
50*168fce73SSepherosa Ziehau check(void)
51*168fce73SSepherosa Ziehau {
52*168fce73SSepherosa Ziehau 	struct statfs *mntbuf, *statfsp;
53*168fce73SSepherosa Ziehau 	int mntsize;
54*168fce73SSepherosa Ziehau 	int i;
55*168fce73SSepherosa Ziehau 
56*168fce73SSepherosa Ziehau 	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
57*168fce73SSepherosa Ziehau 	if (mntsize == 0) {
58*168fce73SSepherosa Ziehau 		VSS_LOG(LOG_ERR, "There is no mount information\n");
59*168fce73SSepherosa Ziehau 		return (EINVAL);
60*168fce73SSepherosa Ziehau 	}
61*168fce73SSepherosa Ziehau 	for (i = mntsize - 1; i >= 0; --i)
62*168fce73SSepherosa Ziehau 	{
63*168fce73SSepherosa Ziehau 		statfsp = &mntbuf[i];
64*168fce73SSepherosa Ziehau 
65*168fce73SSepherosa Ziehau 		if (strncmp(statfsp->f_mntonname, dev, strlen(dev)) == 0) {
66*168fce73SSepherosa Ziehau 			continue; /* skip to freeze '/dev' */
67*168fce73SSepherosa Ziehau 		} else if (statfsp->f_flags & MNT_RDONLY) {
68*168fce73SSepherosa Ziehau 			continue; /* skip to freeze RDONLY partition */
69*168fce73SSepherosa Ziehau 		} else if (strncmp(statfsp->f_fstypename, "ufs", 3) != 0) {
70*168fce73SSepherosa Ziehau 			return (EPERM); /* only UFS can be freezed */
71*168fce73SSepherosa Ziehau 		}
72*168fce73SSepherosa Ziehau 	}
73*168fce73SSepherosa Ziehau 
74*168fce73SSepherosa Ziehau 	return (0);
75*168fce73SSepherosa Ziehau }
76*168fce73SSepherosa Ziehau 
77*168fce73SSepherosa Ziehau static int
78*168fce73SSepherosa Ziehau freeze(void)
79*168fce73SSepherosa Ziehau {
80*168fce73SSepherosa Ziehau 	struct statfs *mntbuf, *statfsp;
81*168fce73SSepherosa Ziehau 	int mntsize;
82*168fce73SSepherosa Ziehau 	int error = 0;
83*168fce73SSepherosa Ziehau 	int i;
84*168fce73SSepherosa Ziehau 
85*168fce73SSepherosa Ziehau 	g_ufs_suspend_handle = open(_PATH_UFSSUSPEND, O_RDWR);
86*168fce73SSepherosa Ziehau 	if (g_ufs_suspend_handle == -1) {
87*168fce73SSepherosa Ziehau 		VSS_LOG(LOG_ERR, "unable to open %s", _PATH_UFSSUSPEND);
88*168fce73SSepherosa Ziehau 		return (errno);
89*168fce73SSepherosa Ziehau 	}
90*168fce73SSepherosa Ziehau 
91*168fce73SSepherosa Ziehau 	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
92*168fce73SSepherosa Ziehau 	if (mntsize == 0) {
93*168fce73SSepherosa Ziehau 		VSS_LOG(LOG_ERR, "There is no mount information\n");
94*168fce73SSepherosa Ziehau 		return (EINVAL);
95*168fce73SSepherosa Ziehau 	}
96*168fce73SSepherosa Ziehau 	for (i = mntsize - 1; i >= 0; --i)
97*168fce73SSepherosa Ziehau 	{
98*168fce73SSepherosa Ziehau 		statfsp = &mntbuf[i];
99*168fce73SSepherosa Ziehau 
100*168fce73SSepherosa Ziehau 		if (strncmp(statfsp->f_mntonname, dev, strlen(dev)) == 0) {
101*168fce73SSepherosa Ziehau 			continue; /* skip to freeze '/dev' */
102*168fce73SSepherosa Ziehau 		} else if (statfsp->f_flags & MNT_RDONLY) {
103*168fce73SSepherosa Ziehau 			continue; /* skip to freeze RDONLY partition */
104*168fce73SSepherosa Ziehau 		} else if (strncmp(statfsp->f_fstypename, "ufs", 3) != 0) {
105*168fce73SSepherosa Ziehau 			continue; /* only UFS can be freezed */
106*168fce73SSepherosa Ziehau 		}
107*168fce73SSepherosa Ziehau 		error = ioctl(g_ufs_suspend_handle, UFSSUSPEND, &statfsp->f_fsid);
108*168fce73SSepherosa Ziehau 		if (error != 0) {
109*168fce73SSepherosa Ziehau 			VSS_LOG(LOG_ERR, "error: %d\n", errno);
110*168fce73SSepherosa Ziehau 			error = errno;
111*168fce73SSepherosa Ziehau 		} else {
112*168fce73SSepherosa Ziehau 			VSS_LOG(LOG_INFO, "Successfully suspend fs: %s\n",
113*168fce73SSepherosa Ziehau 			    statfsp->f_mntonname);
114*168fce73SSepherosa Ziehau 		}
115*168fce73SSepherosa Ziehau 	}
116*168fce73SSepherosa Ziehau 
117*168fce73SSepherosa Ziehau 	return (error);
118*168fce73SSepherosa Ziehau }
119*168fce73SSepherosa Ziehau 
120*168fce73SSepherosa Ziehau /**
121*168fce73SSepherosa Ziehau  * close the opened handle will thaw the FS.
122*168fce73SSepherosa Ziehau  */
123*168fce73SSepherosa Ziehau static int
124*168fce73SSepherosa Ziehau thaw(void)
125*168fce73SSepherosa Ziehau {
126*168fce73SSepherosa Ziehau 	int error = 0;
127*168fce73SSepherosa Ziehau 	if (g_ufs_suspend_handle != -1) {
128*168fce73SSepherosa Ziehau 		error = close(g_ufs_suspend_handle);
129*168fce73SSepherosa Ziehau 		if (!error) {
130*168fce73SSepherosa Ziehau 			g_ufs_suspend_handle = -1;
131*168fce73SSepherosa Ziehau 			VSS_LOG(LOG_INFO, "Successfully thaw the fs\n");
132*168fce73SSepherosa Ziehau 		} else {
133*168fce73SSepherosa Ziehau 			error = errno;
134*168fce73SSepherosa Ziehau 			VSS_LOG(LOG_ERR, "Fail to thaw the fs: "
135*168fce73SSepherosa Ziehau 			    "%d %s\n", errno, strerror(errno));
136*168fce73SSepherosa Ziehau 		}
137*168fce73SSepherosa Ziehau 	} else {
138*168fce73SSepherosa Ziehau 		VSS_LOG(LOG_INFO, "The fs has already been thawed\n");
139*168fce73SSepherosa Ziehau 	}
140*168fce73SSepherosa Ziehau 
141*168fce73SSepherosa Ziehau 	return (error);
142*168fce73SSepherosa Ziehau }
143*168fce73SSepherosa Ziehau 
144*168fce73SSepherosa Ziehau static void
145*168fce73SSepherosa Ziehau usage(const char* cmd)
146*168fce73SSepherosa Ziehau {
147*168fce73SSepherosa Ziehau 	fprintf(stderr, "%s: daemon for UFS file system freeze/thaw\n"
148*168fce73SSepherosa Ziehau 	    " -d : enable debug log printing. Default is disabled.\n"
149*168fce73SSepherosa Ziehau 	    " -n : run as a regular process instead of a daemon. Default is a daemon.\n"
150*168fce73SSepherosa Ziehau 	    " -h : print usage.\n", cmd);
151*168fce73SSepherosa Ziehau 	exit(1);
152*168fce73SSepherosa Ziehau }
153*168fce73SSepherosa Ziehau 
154*168fce73SSepherosa Ziehau int
155*168fce73SSepherosa Ziehau main(int argc, char* argv[])
156*168fce73SSepherosa Ziehau {
157*168fce73SSepherosa Ziehau 	struct hv_vss_opt_msg  userdata;
158*168fce73SSepherosa Ziehau 
159*168fce73SSepherosa Ziehau 	struct pollfd hv_vss_poll_fd[1];
160*168fce73SSepherosa Ziehau 	uint32_t op;
161*168fce73SSepherosa Ziehau 	int ch, r, len, error;
162*168fce73SSepherosa Ziehau 	int hv_vss_dev_fd;
163*168fce73SSepherosa Ziehau 
164*168fce73SSepherosa Ziehau 	int freeze_thaw = UNDEF_FREEZE_THAW;
165*168fce73SSepherosa Ziehau 	while ((ch = getopt(argc, argv, "dnh")) != -1) {
166*168fce73SSepherosa Ziehau 		switch (ch) {
167*168fce73SSepherosa Ziehau 		case 'n':
168*168fce73SSepherosa Ziehau 			/* Run as regular process for debugging purpose. */
169*168fce73SSepherosa Ziehau 			is_daemon = 0;
170*168fce73SSepherosa Ziehau 			break;
171*168fce73SSepherosa Ziehau 		case 'd':
172*168fce73SSepherosa Ziehau 			/* Generate debugging output */
173*168fce73SSepherosa Ziehau 			is_debugging = 1;
174*168fce73SSepherosa Ziehau 			break;
175*168fce73SSepherosa Ziehau 		case 'h':
176*168fce73SSepherosa Ziehau 		default:
177*168fce73SSepherosa Ziehau 			usage(argv[0]);
178*168fce73SSepherosa Ziehau 			break;
179*168fce73SSepherosa Ziehau 		}
180*168fce73SSepherosa Ziehau 	}
181*168fce73SSepherosa Ziehau 
182*168fce73SSepherosa Ziehau 	openlog("HV_VSS", 0, LOG_USER);
183*168fce73SSepherosa Ziehau 
184*168fce73SSepherosa Ziehau 	/* Become daemon first. */
185*168fce73SSepherosa Ziehau 	if (is_daemon == 1)
186*168fce73SSepherosa Ziehau 		daemon(1, 0);
187*168fce73SSepherosa Ziehau 	else
188*168fce73SSepherosa Ziehau 		VSS_LOG(LOG_DEBUG, "Run as regular process.\n");
189*168fce73SSepherosa Ziehau 
190*168fce73SSepherosa Ziehau 	VSS_LOG(LOG_INFO, "HV_VSS starting; pid is: %d\n", getpid());
191*168fce73SSepherosa Ziehau 
192*168fce73SSepherosa Ziehau 	memset(&userdata, 0, sizeof(struct hv_vss_opt_msg));
193*168fce73SSepherosa Ziehau 	/* register the daemon */
194*168fce73SSepherosa Ziehau 	hv_vss_dev_fd = open(VSS_DEV(FS_VSS_DEV_NAME), O_RDWR);
195*168fce73SSepherosa Ziehau 
196*168fce73SSepherosa Ziehau 	if (hv_vss_dev_fd < 0) {
197*168fce73SSepherosa Ziehau 		VSS_LOG(LOG_ERR, "Fail to open %s, error: %d %s\n",
198*168fce73SSepherosa Ziehau 		    VSS_DEV(FS_VSS_DEV_NAME), errno, strerror(errno));
199*168fce73SSepherosa Ziehau 		exit(EXIT_FAILURE);
200*168fce73SSepherosa Ziehau 	}
201*168fce73SSepherosa Ziehau 	hv_vss_poll_fd[0].fd = hv_vss_dev_fd;
202*168fce73SSepherosa Ziehau 	hv_vss_poll_fd[0].events = POLLIN | POLLRDNORM;
203*168fce73SSepherosa Ziehau 
204*168fce73SSepherosa Ziehau 	while (1) {
205*168fce73SSepherosa Ziehau 		r = poll(hv_vss_poll_fd, 1, INFTIM);
206*168fce73SSepherosa Ziehau 
207*168fce73SSepherosa Ziehau 		VSS_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n",
208*168fce73SSepherosa Ziehau 		    r, hv_vss_poll_fd[0].revents);
209*168fce73SSepherosa Ziehau 
210*168fce73SSepherosa Ziehau 		if (r == 0 || (r < 0 && errno == EAGAIN) ||
211*168fce73SSepherosa Ziehau 		    (r < 0 && errno == EINTR)) {
212*168fce73SSepherosa Ziehau 			/* Nothing to read */
213*168fce73SSepherosa Ziehau 			continue;
214*168fce73SSepherosa Ziehau 		}
215*168fce73SSepherosa Ziehau 
216*168fce73SSepherosa Ziehau 		if (r < 0) {
217*168fce73SSepherosa Ziehau 			/*
218*168fce73SSepherosa Ziehau 			 * For poll return failure other than EAGAIN,
219*168fce73SSepherosa Ziehau 			 * we want to exit.
220*168fce73SSepherosa Ziehau 			 */
221*168fce73SSepherosa Ziehau 			VSS_LOG(LOG_ERR, "Poll failed.\n");
222*168fce73SSepherosa Ziehau 			perror("poll");
223*168fce73SSepherosa Ziehau 			exit(EIO);
224*168fce73SSepherosa Ziehau 		}
225*168fce73SSepherosa Ziehau 
226*168fce73SSepherosa Ziehau 		/* Read from character device */
227*168fce73SSepherosa Ziehau 		error = ioctl(hv_vss_dev_fd, IOCHVVSSREAD, &userdata);
228*168fce73SSepherosa Ziehau 		if (error < 0) {
229*168fce73SSepherosa Ziehau 			VSS_LOG(LOG_ERR, "Read failed.\n");
230*168fce73SSepherosa Ziehau 			perror("pread");
231*168fce73SSepherosa Ziehau 			exit(EIO);
232*168fce73SSepherosa Ziehau 		}
233*168fce73SSepherosa Ziehau 
234*168fce73SSepherosa Ziehau 		if (userdata.status != 0) {
235*168fce73SSepherosa Ziehau 			VSS_LOG(LOG_ERR, "data read error\n");
236*168fce73SSepherosa Ziehau 			continue;
237*168fce73SSepherosa Ziehau 		}
238*168fce73SSepherosa Ziehau 
239*168fce73SSepherosa Ziehau 		/*
240*168fce73SSepherosa Ziehau 		 * We will use the KVP header information to pass back
241*168fce73SSepherosa Ziehau 		 * the error from this daemon. So, first save the op
242*168fce73SSepherosa Ziehau 		 * and pool info to local variables.
243*168fce73SSepherosa Ziehau 		 */
244*168fce73SSepherosa Ziehau 
245*168fce73SSepherosa Ziehau 		op = userdata.opt;
246*168fce73SSepherosa Ziehau 
247*168fce73SSepherosa Ziehau 		switch (op) {
248*168fce73SSepherosa Ziehau 		case HV_VSS_CHECK:
249*168fce73SSepherosa Ziehau 			error = check();
250*168fce73SSepherosa Ziehau 			break;
251*168fce73SSepherosa Ziehau 		case HV_VSS_FREEZE:
252*168fce73SSepherosa Ziehau 			error = freeze();
253*168fce73SSepherosa Ziehau 			break;
254*168fce73SSepherosa Ziehau 		case HV_VSS_THAW:
255*168fce73SSepherosa Ziehau 			error = thaw();
256*168fce73SSepherosa Ziehau 			break;
257*168fce73SSepherosa Ziehau 		default:
258*168fce73SSepherosa Ziehau 			VSS_LOG(LOG_ERR, "Illegal operation: %d\n", op);
259*168fce73SSepherosa Ziehau 			error = VSS_FAIL;
260*168fce73SSepherosa Ziehau 		}
261*168fce73SSepherosa Ziehau 		if (error)
262*168fce73SSepherosa Ziehau 			userdata.status = VSS_FAIL;
263*168fce73SSepherosa Ziehau 		else
264*168fce73SSepherosa Ziehau 			userdata.status = VSS_SUCCESS;
265*168fce73SSepherosa Ziehau 		error = ioctl(hv_vss_dev_fd, IOCHVVSSWRITE, &userdata);
266*168fce73SSepherosa Ziehau 		if (error != 0) {
267*168fce73SSepherosa Ziehau 			VSS_LOG(LOG_ERR, "Fail to write to device\n");
268*168fce73SSepherosa Ziehau 			exit(EXIT_FAILURE);
269*168fce73SSepherosa Ziehau 		} else {
270*168fce73SSepherosa Ziehau 			VSS_LOG(LOG_INFO, "Send response %d for %s to kernel\n",
271*168fce73SSepherosa Ziehau 			    userdata.status, op == HV_VSS_FREEZE ? "Freeze" :
272*168fce73SSepherosa Ziehau 			    (op == HV_VSS_THAW ? "Thaw" : "Check"));
273*168fce73SSepherosa Ziehau 		}
274*168fce73SSepherosa Ziehau 	}
275*168fce73SSepherosa Ziehau }
276