1168fce73SSepherosa Ziehau #include <string.h> 2168fce73SSepherosa Ziehau #include <stdio.h> 3168fce73SSepherosa Ziehau #include <sys/ioctl.h> 4168fce73SSepherosa Ziehau #include <sys/param.h> 5168fce73SSepherosa Ziehau #include <sys/ucred.h> 6168fce73SSepherosa Ziehau #include <sys/mount.h> 7168fce73SSepherosa Ziehau #include <sys/types.h> 8168fce73SSepherosa Ziehau 9168fce73SSepherosa Ziehau #include <unistd.h> 10168fce73SSepherosa Ziehau #include <stdlib.h> 11168fce73SSepherosa Ziehau #include <poll.h> 12168fce73SSepherosa Ziehau #include <stdint.h> 13168fce73SSepherosa Ziehau #include <syslog.h> 14168fce73SSepherosa Ziehau #include <errno.h> 15168fce73SSepherosa Ziehau #include <err.h> 16168fce73SSepherosa Ziehau #include <fcntl.h> 17168fce73SSepherosa Ziehau #include <ufs/ffs/fs.h> 18168fce73SSepherosa Ziehau #include <paths.h> 19168fce73SSepherosa Ziehau #include <sysexits.h> 20168fce73SSepherosa Ziehau 21168fce73SSepherosa Ziehau #include "hv_snapshot.h" 22168fce73SSepherosa Ziehau 23168fce73SSepherosa Ziehau #define UNDEF_FREEZE_THAW (0) 24168fce73SSepherosa Ziehau #define FREEZE (1) 25168fce73SSepherosa Ziehau #define THAW (2) 26168fce73SSepherosa Ziehau 27168fce73SSepherosa Ziehau #define VSS_LOG(priority, format, args...) do { \ 28168fce73SSepherosa Ziehau if (is_debugging == 1) { \ 29168fce73SSepherosa Ziehau if (is_daemon == 1) \ 30168fce73SSepherosa Ziehau syslog(priority, format, ## args); \ 31168fce73SSepherosa Ziehau else \ 32168fce73SSepherosa Ziehau printf(format, ## args); \ 33168fce73SSepherosa Ziehau } else { \ 34168fce73SSepherosa Ziehau if (priority < LOG_DEBUG) { \ 35168fce73SSepherosa Ziehau if (is_daemon == 1) \ 36168fce73SSepherosa Ziehau syslog(priority, format, ## args); \ 37168fce73SSepherosa Ziehau else \ 38168fce73SSepherosa Ziehau printf(format, ## args); \ 39168fce73SSepherosa Ziehau } \ 40168fce73SSepherosa Ziehau } \ 41168fce73SSepherosa Ziehau } while(0) 42168fce73SSepherosa Ziehau 43168fce73SSepherosa Ziehau static int is_daemon = 1; 44168fce73SSepherosa Ziehau static int is_debugging = 0; 45168fce73SSepherosa Ziehau static int g_ufs_suspend_handle = -1; 46168fce73SSepherosa Ziehau 47168fce73SSepherosa Ziehau static const char *dev = "/dev"; 48168fce73SSepherosa Ziehau 49168fce73SSepherosa Ziehau static int 50168fce73SSepherosa Ziehau check(void) 51168fce73SSepherosa Ziehau { 52168fce73SSepherosa Ziehau struct statfs *mntbuf, *statfsp; 53168fce73SSepherosa Ziehau int mntsize; 54168fce73SSepherosa Ziehau int i; 55168fce73SSepherosa Ziehau 56168fce73SSepherosa Ziehau mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 57168fce73SSepherosa Ziehau if (mntsize == 0) { 58168fce73SSepherosa Ziehau VSS_LOG(LOG_ERR, "There is no mount information\n"); 59168fce73SSepherosa Ziehau return (EINVAL); 60168fce73SSepherosa Ziehau } 61168fce73SSepherosa Ziehau for (i = mntsize - 1; i >= 0; --i) 62168fce73SSepherosa Ziehau { 63168fce73SSepherosa Ziehau statfsp = &mntbuf[i]; 64168fce73SSepherosa Ziehau 65168fce73SSepherosa Ziehau if (strncmp(statfsp->f_mntonname, dev, strlen(dev)) == 0) { 66168fce73SSepherosa Ziehau continue; /* skip to freeze '/dev' */ 67168fce73SSepherosa Ziehau } else if (statfsp->f_flags & MNT_RDONLY) { 68168fce73SSepherosa Ziehau continue; /* skip to freeze RDONLY partition */ 69168fce73SSepherosa Ziehau } else if (strncmp(statfsp->f_fstypename, "ufs", 3) != 0) { 70168fce73SSepherosa Ziehau return (EPERM); /* only UFS can be freezed */ 71168fce73SSepherosa Ziehau } 72168fce73SSepherosa Ziehau } 73168fce73SSepherosa Ziehau 74168fce73SSepherosa Ziehau return (0); 75168fce73SSepherosa Ziehau } 76168fce73SSepherosa Ziehau 77168fce73SSepherosa Ziehau static int 78168fce73SSepherosa Ziehau freeze(void) 79168fce73SSepherosa Ziehau { 80168fce73SSepherosa Ziehau struct statfs *mntbuf, *statfsp; 81168fce73SSepherosa Ziehau int mntsize; 82168fce73SSepherosa Ziehau int error = 0; 83168fce73SSepherosa Ziehau int i; 84168fce73SSepherosa Ziehau 85168fce73SSepherosa Ziehau g_ufs_suspend_handle = open(_PATH_UFSSUSPEND, O_RDWR); 86168fce73SSepherosa Ziehau if (g_ufs_suspend_handle == -1) { 87168fce73SSepherosa Ziehau VSS_LOG(LOG_ERR, "unable to open %s", _PATH_UFSSUSPEND); 88168fce73SSepherosa Ziehau return (errno); 89168fce73SSepherosa Ziehau } 90168fce73SSepherosa Ziehau 91168fce73SSepherosa Ziehau mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 92168fce73SSepherosa Ziehau if (mntsize == 0) { 93168fce73SSepherosa Ziehau VSS_LOG(LOG_ERR, "There is no mount information\n"); 94168fce73SSepherosa Ziehau return (EINVAL); 95168fce73SSepherosa Ziehau } 96168fce73SSepherosa Ziehau for (i = mntsize - 1; i >= 0; --i) 97168fce73SSepherosa Ziehau { 98168fce73SSepherosa Ziehau statfsp = &mntbuf[i]; 99168fce73SSepherosa Ziehau 100168fce73SSepherosa Ziehau if (strncmp(statfsp->f_mntonname, dev, strlen(dev)) == 0) { 101168fce73SSepherosa Ziehau continue; /* skip to freeze '/dev' */ 102168fce73SSepherosa Ziehau } else if (statfsp->f_flags & MNT_RDONLY) { 103168fce73SSepherosa Ziehau continue; /* skip to freeze RDONLY partition */ 104168fce73SSepherosa Ziehau } else if (strncmp(statfsp->f_fstypename, "ufs", 3) != 0) { 105168fce73SSepherosa Ziehau continue; /* only UFS can be freezed */ 106168fce73SSepherosa Ziehau } 107168fce73SSepherosa Ziehau error = ioctl(g_ufs_suspend_handle, UFSSUSPEND, &statfsp->f_fsid); 108168fce73SSepherosa Ziehau if (error != 0) { 109168fce73SSepherosa Ziehau VSS_LOG(LOG_ERR, "error: %d\n", errno); 110168fce73SSepherosa Ziehau error = errno; 111168fce73SSepherosa Ziehau } else { 112168fce73SSepherosa Ziehau VSS_LOG(LOG_INFO, "Successfully suspend fs: %s\n", 113168fce73SSepherosa Ziehau statfsp->f_mntonname); 114168fce73SSepherosa Ziehau } 115168fce73SSepherosa Ziehau } 116168fce73SSepherosa Ziehau 117168fce73SSepherosa Ziehau return (error); 118168fce73SSepherosa Ziehau } 119168fce73SSepherosa Ziehau 120168fce73SSepherosa Ziehau /** 121168fce73SSepherosa Ziehau * close the opened handle will thaw the FS. 122168fce73SSepherosa Ziehau */ 123168fce73SSepherosa Ziehau static int 124168fce73SSepherosa Ziehau thaw(void) 125168fce73SSepherosa Ziehau { 126168fce73SSepherosa Ziehau int error = 0; 127168fce73SSepherosa Ziehau if (g_ufs_suspend_handle != -1) { 128168fce73SSepherosa Ziehau error = close(g_ufs_suspend_handle); 129168fce73SSepherosa Ziehau if (!error) { 130168fce73SSepherosa Ziehau g_ufs_suspend_handle = -1; 131168fce73SSepherosa Ziehau VSS_LOG(LOG_INFO, "Successfully thaw the fs\n"); 132168fce73SSepherosa Ziehau } else { 133168fce73SSepherosa Ziehau error = errno; 134168fce73SSepherosa Ziehau VSS_LOG(LOG_ERR, "Fail to thaw the fs: " 135168fce73SSepherosa Ziehau "%d %s\n", errno, strerror(errno)); 136168fce73SSepherosa Ziehau } 137168fce73SSepherosa Ziehau } else { 138168fce73SSepherosa Ziehau VSS_LOG(LOG_INFO, "The fs has already been thawed\n"); 139168fce73SSepherosa Ziehau } 140168fce73SSepherosa Ziehau 141168fce73SSepherosa Ziehau return (error); 142168fce73SSepherosa Ziehau } 143168fce73SSepherosa Ziehau 144168fce73SSepherosa Ziehau static void 145168fce73SSepherosa Ziehau usage(const char* cmd) 146168fce73SSepherosa Ziehau { 147168fce73SSepherosa Ziehau fprintf(stderr, "%s: daemon for UFS file system freeze/thaw\n" 148168fce73SSepherosa Ziehau " -d : enable debug log printing. Default is disabled.\n" 149168fce73SSepherosa Ziehau " -n : run as a regular process instead of a daemon. Default is a daemon.\n" 150168fce73SSepherosa Ziehau " -h : print usage.\n", cmd); 151168fce73SSepherosa Ziehau exit(1); 152168fce73SSepherosa Ziehau } 153168fce73SSepherosa Ziehau 154168fce73SSepherosa Ziehau int 155168fce73SSepherosa Ziehau main(int argc, char* argv[]) 156168fce73SSepherosa Ziehau { 157168fce73SSepherosa Ziehau struct hv_vss_opt_msg userdata; 158168fce73SSepherosa Ziehau 159168fce73SSepherosa Ziehau struct pollfd hv_vss_poll_fd[1]; 160168fce73SSepherosa Ziehau uint32_t op; 161*bedddda0SSepherosa Ziehau int ch, r, error; 162168fce73SSepherosa Ziehau int hv_vss_dev_fd; 163168fce73SSepherosa Ziehau 164168fce73SSepherosa Ziehau while ((ch = getopt(argc, argv, "dnh")) != -1) { 165168fce73SSepherosa Ziehau switch (ch) { 166168fce73SSepherosa Ziehau case 'n': 167168fce73SSepherosa Ziehau /* Run as regular process for debugging purpose. */ 168168fce73SSepherosa Ziehau is_daemon = 0; 169168fce73SSepherosa Ziehau break; 170168fce73SSepherosa Ziehau case 'd': 171168fce73SSepherosa Ziehau /* Generate debugging output */ 172168fce73SSepherosa Ziehau is_debugging = 1; 173168fce73SSepherosa Ziehau break; 174168fce73SSepherosa Ziehau case 'h': 175168fce73SSepherosa Ziehau default: 176168fce73SSepherosa Ziehau usage(argv[0]); 177168fce73SSepherosa Ziehau break; 178168fce73SSepherosa Ziehau } 179168fce73SSepherosa Ziehau } 180168fce73SSepherosa Ziehau 181168fce73SSepherosa Ziehau openlog("HV_VSS", 0, LOG_USER); 182168fce73SSepherosa Ziehau 183168fce73SSepherosa Ziehau /* Become daemon first. */ 184168fce73SSepherosa Ziehau if (is_daemon == 1) 185168fce73SSepherosa Ziehau daemon(1, 0); 186168fce73SSepherosa Ziehau else 187168fce73SSepherosa Ziehau VSS_LOG(LOG_DEBUG, "Run as regular process.\n"); 188168fce73SSepherosa Ziehau 189168fce73SSepherosa Ziehau VSS_LOG(LOG_INFO, "HV_VSS starting; pid is: %d\n", getpid()); 190168fce73SSepherosa Ziehau 191168fce73SSepherosa Ziehau memset(&userdata, 0, sizeof(struct hv_vss_opt_msg)); 192168fce73SSepherosa Ziehau /* register the daemon */ 193168fce73SSepherosa Ziehau hv_vss_dev_fd = open(VSS_DEV(FS_VSS_DEV_NAME), O_RDWR); 194168fce73SSepherosa Ziehau 195168fce73SSepherosa Ziehau if (hv_vss_dev_fd < 0) { 196168fce73SSepherosa Ziehau VSS_LOG(LOG_ERR, "Fail to open %s, error: %d %s\n", 197168fce73SSepherosa Ziehau VSS_DEV(FS_VSS_DEV_NAME), errno, strerror(errno)); 198168fce73SSepherosa Ziehau exit(EXIT_FAILURE); 199168fce73SSepherosa Ziehau } 200168fce73SSepherosa Ziehau hv_vss_poll_fd[0].fd = hv_vss_dev_fd; 201168fce73SSepherosa Ziehau hv_vss_poll_fd[0].events = POLLIN | POLLRDNORM; 202168fce73SSepherosa Ziehau 203168fce73SSepherosa Ziehau while (1) { 204168fce73SSepherosa Ziehau r = poll(hv_vss_poll_fd, 1, INFTIM); 205168fce73SSepherosa Ziehau 206168fce73SSepherosa Ziehau VSS_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n", 207168fce73SSepherosa Ziehau r, hv_vss_poll_fd[0].revents); 208168fce73SSepherosa Ziehau 209168fce73SSepherosa Ziehau if (r == 0 || (r < 0 && errno == EAGAIN) || 210168fce73SSepherosa Ziehau (r < 0 && errno == EINTR)) { 211168fce73SSepherosa Ziehau /* Nothing to read */ 212168fce73SSepherosa Ziehau continue; 213168fce73SSepherosa Ziehau } 214168fce73SSepherosa Ziehau 215168fce73SSepherosa Ziehau if (r < 0) { 216168fce73SSepherosa Ziehau /* 217168fce73SSepherosa Ziehau * For poll return failure other than EAGAIN, 218168fce73SSepherosa Ziehau * we want to exit. 219168fce73SSepherosa Ziehau */ 220168fce73SSepherosa Ziehau VSS_LOG(LOG_ERR, "Poll failed.\n"); 221168fce73SSepherosa Ziehau perror("poll"); 222168fce73SSepherosa Ziehau exit(EIO); 223168fce73SSepherosa Ziehau } 224168fce73SSepherosa Ziehau 225168fce73SSepherosa Ziehau /* Read from character device */ 226168fce73SSepherosa Ziehau error = ioctl(hv_vss_dev_fd, IOCHVVSSREAD, &userdata); 227168fce73SSepherosa Ziehau if (error < 0) { 228168fce73SSepherosa Ziehau VSS_LOG(LOG_ERR, "Read failed.\n"); 229168fce73SSepherosa Ziehau perror("pread"); 230168fce73SSepherosa Ziehau exit(EIO); 231168fce73SSepherosa Ziehau } 232168fce73SSepherosa Ziehau 233168fce73SSepherosa Ziehau if (userdata.status != 0) { 234168fce73SSepherosa Ziehau VSS_LOG(LOG_ERR, "data read error\n"); 235168fce73SSepherosa Ziehau continue; 236168fce73SSepherosa Ziehau } 237168fce73SSepherosa Ziehau 238168fce73SSepherosa Ziehau /* 239168fce73SSepherosa Ziehau * We will use the KVP header information to pass back 240168fce73SSepherosa Ziehau * the error from this daemon. So, first save the op 241168fce73SSepherosa Ziehau * and pool info to local variables. 242168fce73SSepherosa Ziehau */ 243168fce73SSepherosa Ziehau 244168fce73SSepherosa Ziehau op = userdata.opt; 245168fce73SSepherosa Ziehau 246168fce73SSepherosa Ziehau switch (op) { 247168fce73SSepherosa Ziehau case HV_VSS_CHECK: 248168fce73SSepherosa Ziehau error = check(); 249168fce73SSepherosa Ziehau break; 250168fce73SSepherosa Ziehau case HV_VSS_FREEZE: 251168fce73SSepherosa Ziehau error = freeze(); 252168fce73SSepherosa Ziehau break; 253168fce73SSepherosa Ziehau case HV_VSS_THAW: 254168fce73SSepherosa Ziehau error = thaw(); 255168fce73SSepherosa Ziehau break; 256168fce73SSepherosa Ziehau default: 257168fce73SSepherosa Ziehau VSS_LOG(LOG_ERR, "Illegal operation: %d\n", op); 258168fce73SSepherosa Ziehau error = VSS_FAIL; 259168fce73SSepherosa Ziehau } 260168fce73SSepherosa Ziehau if (error) 261168fce73SSepherosa Ziehau userdata.status = VSS_FAIL; 262168fce73SSepherosa Ziehau else 263168fce73SSepherosa Ziehau userdata.status = VSS_SUCCESS; 264168fce73SSepherosa Ziehau error = ioctl(hv_vss_dev_fd, IOCHVVSSWRITE, &userdata); 265168fce73SSepherosa Ziehau if (error != 0) { 266168fce73SSepherosa Ziehau VSS_LOG(LOG_ERR, "Fail to write to device\n"); 267168fce73SSepherosa Ziehau exit(EXIT_FAILURE); 268168fce73SSepherosa Ziehau } else { 269168fce73SSepherosa Ziehau VSS_LOG(LOG_INFO, "Send response %d for %s to kernel\n", 270168fce73SSepherosa Ziehau userdata.status, op == HV_VSS_FREEZE ? "Freeze" : 271168fce73SSepherosa Ziehau (op == HV_VSS_THAW ? "Thaw" : "Check")); 272168fce73SSepherosa Ziehau } 273168fce73SSepherosa Ziehau } 274168fce73SSepherosa Ziehau } 275