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