0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <sys/types.h>
0011 #include <sys/poll.h>
0012 #include <sys/ioctl.h>
0013 #include <sys/stat.h>
0014 #include <sys/sysmacros.h>
0015 #include <fcntl.h>
0016 #include <stdio.h>
0017 #include <mntent.h>
0018 #include <stdlib.h>
0019 #include <unistd.h>
0020 #include <string.h>
0021 #include <ctype.h>
0022 #include <errno.h>
0023 #include <linux/fs.h>
0024 #include <linux/major.h>
0025 #include <linux/hyperv.h>
0026 #include <syslog.h>
0027 #include <getopt.h>
0028 #include <stdbool.h>
0029 #include <dirent.h>
0030
0031 static bool fs_frozen;
0032
0033
0034 static int vss_do_freeze(char *dir, unsigned int cmd)
0035 {
0036 int ret, fd = open(dir, O_RDONLY);
0037
0038 if (fd < 0)
0039 return 1;
0040
0041 ret = ioctl(fd, cmd, 0);
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 if (ret) {
0053 if ((cmd == FIFREEZE && errno == EBUSY) ||
0054 (cmd == FITHAW && errno == EINVAL)) {
0055 close(fd);
0056 return 0;
0057 }
0058 }
0059
0060 close(fd);
0061 return !!ret;
0062 }
0063
0064 static bool is_dev_loop(const char *blkname)
0065 {
0066 char *buffer;
0067 DIR *dir;
0068 struct dirent *entry;
0069 bool ret = false;
0070
0071 buffer = malloc(PATH_MAX);
0072 if (!buffer) {
0073 syslog(LOG_ERR, "Can't allocate memory!");
0074 exit(1);
0075 }
0076
0077 snprintf(buffer, PATH_MAX, "%s/loop", blkname);
0078 if (!access(buffer, R_OK | X_OK)) {
0079 ret = true;
0080 goto free_buffer;
0081 } else if (errno != ENOENT) {
0082 syslog(LOG_ERR, "Can't access: %s; error:%d %s!",
0083 buffer, errno, strerror(errno));
0084 }
0085
0086 snprintf(buffer, PATH_MAX, "%s/slaves", blkname);
0087 dir = opendir(buffer);
0088 if (!dir) {
0089 if (errno != ENOENT)
0090 syslog(LOG_ERR, "Can't opendir: %s; error:%d %s!",
0091 buffer, errno, strerror(errno));
0092 goto free_buffer;
0093 }
0094
0095 while ((entry = readdir(dir)) != NULL) {
0096 if (strcmp(entry->d_name, ".") == 0 ||
0097 strcmp(entry->d_name, "..") == 0)
0098 continue;
0099
0100 snprintf(buffer, PATH_MAX, "%s/slaves/%s", blkname,
0101 entry->d_name);
0102 if (is_dev_loop(buffer)) {
0103 ret = true;
0104 break;
0105 }
0106 }
0107 closedir(dir);
0108 free_buffer:
0109 free(buffer);
0110 return ret;
0111 }
0112
0113 static int vss_operate(int operation)
0114 {
0115 char match[] = "/dev/";
0116 FILE *mounts;
0117 struct mntent *ent;
0118 struct stat sb;
0119 char errdir[1024] = {0};
0120 char blkdir[23];
0121 unsigned int cmd;
0122 int error = 0, root_seen = 0, save_errno = 0;
0123
0124 switch (operation) {
0125 case VSS_OP_FREEZE:
0126 cmd = FIFREEZE;
0127 break;
0128 case VSS_OP_THAW:
0129 cmd = FITHAW;
0130 break;
0131 default:
0132 return -1;
0133 }
0134
0135 mounts = setmntent("/proc/mounts", "r");
0136 if (mounts == NULL)
0137 return -1;
0138
0139 while ((ent = getmntent(mounts))) {
0140 if (strncmp(ent->mnt_fsname, match, strlen(match)))
0141 continue;
0142 if (stat(ent->mnt_fsname, &sb)) {
0143 syslog(LOG_ERR, "Can't stat: %s; error:%d %s!",
0144 ent->mnt_fsname, errno, strerror(errno));
0145 } else {
0146 sprintf(blkdir, "/sys/dev/block/%d:%d",
0147 major(sb.st_rdev), minor(sb.st_rdev));
0148 if (is_dev_loop(blkdir))
0149 continue;
0150 }
0151 if (hasmntopt(ent, MNTOPT_RO) != NULL)
0152 continue;
0153 if (strcmp(ent->mnt_type, "vfat") == 0)
0154 continue;
0155 if (strcmp(ent->mnt_dir, "/") == 0) {
0156 root_seen = 1;
0157 continue;
0158 }
0159 error |= vss_do_freeze(ent->mnt_dir, cmd);
0160 if (operation == VSS_OP_FREEZE) {
0161 if (error)
0162 goto err;
0163 fs_frozen = true;
0164 }
0165 }
0166
0167 endmntent(mounts);
0168
0169 if (root_seen) {
0170 error |= vss_do_freeze("/", cmd);
0171 if (operation == VSS_OP_FREEZE) {
0172 if (error)
0173 goto err;
0174 fs_frozen = true;
0175 }
0176 }
0177
0178 if (operation == VSS_OP_THAW && !error)
0179 fs_frozen = false;
0180
0181 goto out;
0182 err:
0183 save_errno = errno;
0184 if (ent) {
0185 strncpy(errdir, ent->mnt_dir, sizeof(errdir)-1);
0186 endmntent(mounts);
0187 }
0188 vss_operate(VSS_OP_THAW);
0189 fs_frozen = false;
0190
0191 if (ent)
0192 syslog(LOG_ERR, "FREEZE of %s failed; error:%d %s",
0193 errdir, save_errno, strerror(save_errno));
0194 else
0195 syslog(LOG_ERR, "FREEZE of / failed; error:%d %s", save_errno,
0196 strerror(save_errno));
0197 out:
0198 return error;
0199 }
0200
0201 void print_usage(char *argv[])
0202 {
0203 fprintf(stderr, "Usage: %s [options]\n"
0204 "Options are:\n"
0205 " -n, --no-daemon stay in foreground, don't daemonize\n"
0206 " -h, --help print this help\n", argv[0]);
0207 }
0208
0209 int main(int argc, char *argv[])
0210 {
0211 int vss_fd = -1, len;
0212 int error;
0213 struct pollfd pfd;
0214 int op;
0215 struct hv_vss_msg vss_msg[1];
0216 int daemonize = 1, long_index = 0, opt;
0217 int in_handshake;
0218 __u32 kernel_modver;
0219
0220 static struct option long_options[] = {
0221 {"help", no_argument, 0, 'h' },
0222 {"no-daemon", no_argument, 0, 'n' },
0223 {0, 0, 0, 0 }
0224 };
0225
0226 while ((opt = getopt_long(argc, argv, "hn", long_options,
0227 &long_index)) != -1) {
0228 switch (opt) {
0229 case 'n':
0230 daemonize = 0;
0231 break;
0232 case 'h':
0233 print_usage(argv);
0234 exit(0);
0235 default:
0236 print_usage(argv);
0237 exit(EXIT_FAILURE);
0238 }
0239 }
0240
0241 if (daemonize && daemon(1, 0))
0242 return 1;
0243
0244 openlog("Hyper-V VSS", 0, LOG_USER);
0245 syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
0246
0247 reopen_vss_fd:
0248 if (vss_fd != -1)
0249 close(vss_fd);
0250 if (fs_frozen) {
0251 if (vss_operate(VSS_OP_THAW) || fs_frozen) {
0252 syslog(LOG_ERR, "failed to thaw file system: err=%d",
0253 errno);
0254 exit(EXIT_FAILURE);
0255 }
0256 }
0257
0258 in_handshake = 1;
0259 vss_fd = open("/dev/vmbus/hv_vss", O_RDWR);
0260 if (vss_fd < 0) {
0261 syslog(LOG_ERR, "open /dev/vmbus/hv_vss failed; error: %d %s",
0262 errno, strerror(errno));
0263 exit(EXIT_FAILURE);
0264 }
0265
0266
0267
0268 vss_msg->vss_hdr.operation = VSS_OP_REGISTER1;
0269
0270 len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
0271 if (len < 0) {
0272 syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
0273 errno, strerror(errno));
0274 close(vss_fd);
0275 exit(EXIT_FAILURE);
0276 }
0277
0278 pfd.fd = vss_fd;
0279
0280 while (1) {
0281 pfd.events = POLLIN;
0282 pfd.revents = 0;
0283
0284 if (poll(&pfd, 1, -1) < 0) {
0285 syslog(LOG_ERR, "poll failed; error:%d %s", errno, strerror(errno));
0286 if (errno == EINVAL) {
0287 close(vss_fd);
0288 exit(EXIT_FAILURE);
0289 }
0290 else
0291 continue;
0292 }
0293
0294 len = read(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
0295
0296 if (in_handshake) {
0297 if (len != sizeof(kernel_modver)) {
0298 syslog(LOG_ERR, "invalid version negotiation");
0299 exit(EXIT_FAILURE);
0300 }
0301 kernel_modver = *(__u32 *)vss_msg;
0302 in_handshake = 0;
0303 syslog(LOG_INFO, "VSS: kernel module version: %d",
0304 kernel_modver);
0305 continue;
0306 }
0307
0308 if (len != sizeof(struct hv_vss_msg)) {
0309 syslog(LOG_ERR, "read failed; error:%d %s",
0310 errno, strerror(errno));
0311 goto reopen_vss_fd;
0312 }
0313
0314 op = vss_msg->vss_hdr.operation;
0315 error = HV_S_OK;
0316
0317 switch (op) {
0318 case VSS_OP_FREEZE:
0319 case VSS_OP_THAW:
0320 error = vss_operate(op);
0321 syslog(LOG_INFO, "VSS: op=%s: %s\n",
0322 op == VSS_OP_FREEZE ? "FREEZE" : "THAW",
0323 error ? "failed" : "succeeded");
0324
0325 if (error) {
0326 error = HV_E_FAIL;
0327 syslog(LOG_ERR, "op=%d failed!", op);
0328 syslog(LOG_ERR, "report it with these files:");
0329 syslog(LOG_ERR, "/etc/fstab and /proc/mounts");
0330 }
0331 break;
0332 case VSS_OP_HOT_BACKUP:
0333 syslog(LOG_INFO, "VSS: op=CHECK HOT BACKUP\n");
0334 break;
0335 default:
0336 syslog(LOG_ERR, "Illegal op:%d\n", op);
0337 }
0338
0339
0340
0341
0342
0343
0344 vss_msg->error = error;
0345 len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
0346 if (len != sizeof(struct hv_vss_msg)) {
0347 syslog(LOG_ERR, "write failed; error: %d %s", errno,
0348 strerror(errno));
0349 goto reopen_vss_fd;
0350 }
0351 }
0352
0353 close(vss_fd);
0354 exit(0);
0355 }