^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * An implementation of the host initiated guest snapshot for Hyper-V.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2013, Microsoft, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author : K. Y. Srinivasan <kys@microsoft.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <sys/poll.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <sys/ioctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <sys/sysmacros.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <mntent.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/major.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/hyperv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <syslog.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <getopt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <stdbool.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <dirent.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static bool fs_frozen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /* Don't use syslog() in the function since that can cause write to disk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static int vss_do_freeze(char *dir, unsigned int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) int ret, fd = open(dir, O_RDONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (fd < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) ret = ioctl(fd, cmd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * If a partition is mounted more than once, only the first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * FREEZE/THAW can succeed and the later ones will get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * EBUSY/EINVAL respectively: there could be 2 cases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * 1) a user may mount the same partition to different directories
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * by mistake or on purpose;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * 2) The subvolume of btrfs appears to have the same partition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * mounted more than once.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if ((cmd == FIFREEZE && errno == EBUSY) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) (cmd == FITHAW && errno == EINVAL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return !!ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static bool is_dev_loop(const char *blkname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) char *buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) DIR *dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct dirent *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) bool ret = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) buffer = malloc(PATH_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (!buffer) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) syslog(LOG_ERR, "Can't allocate memory!");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) exit(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) snprintf(buffer, PATH_MAX, "%s/loop", blkname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (!access(buffer, R_OK | X_OK)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ret = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) goto free_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) } else if (errno != ENOENT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) syslog(LOG_ERR, "Can't access: %s; error:%d %s!",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) buffer, errno, strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) snprintf(buffer, PATH_MAX, "%s/slaves", blkname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) dir = opendir(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (!dir) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (errno != ENOENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) syslog(LOG_ERR, "Can't opendir: %s; error:%d %s!",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) buffer, errno, strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) goto free_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) while ((entry = readdir(dir)) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (strcmp(entry->d_name, ".") == 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) strcmp(entry->d_name, "..") == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) snprintf(buffer, PATH_MAX, "%s/slaves/%s", blkname,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) entry->d_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (is_dev_loop(buffer)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) ret = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) closedir(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) free_buffer:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) free(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static int vss_operate(int operation)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) char match[] = "/dev/";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) FILE *mounts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct mntent *ent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct stat sb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) char errdir[1024] = {0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) char blkdir[23]; /* /sys/dev/block/XXX:XXX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) unsigned int cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) int error = 0, root_seen = 0, save_errno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) switch (operation) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) case VSS_OP_FREEZE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) cmd = FIFREEZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) case VSS_OP_THAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) cmd = FITHAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) mounts = setmntent("/proc/mounts", "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (mounts == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) while ((ent = getmntent(mounts))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (strncmp(ent->mnt_fsname, match, strlen(match)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (stat(ent->mnt_fsname, &sb)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) syslog(LOG_ERR, "Can't stat: %s; error:%d %s!",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ent->mnt_fsname, errno, strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) sprintf(blkdir, "/sys/dev/block/%d:%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) major(sb.st_rdev), minor(sb.st_rdev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (is_dev_loop(blkdir))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (hasmntopt(ent, MNTOPT_RO) != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (strcmp(ent->mnt_type, "vfat") == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (strcmp(ent->mnt_dir, "/") == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) root_seen = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) error |= vss_do_freeze(ent->mnt_dir, cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (operation == VSS_OP_FREEZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) fs_frozen = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) endmntent(mounts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (root_seen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) error |= vss_do_freeze("/", cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (operation == VSS_OP_FREEZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) fs_frozen = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (operation == VSS_OP_THAW && !error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) fs_frozen = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) save_errno = errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (ent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) strncpy(errdir, ent->mnt_dir, sizeof(errdir)-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) endmntent(mounts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) vss_operate(VSS_OP_THAW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) fs_frozen = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) /* Call syslog after we thaw all filesystems */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (ent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) syslog(LOG_ERR, "FREEZE of %s failed; error:%d %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) errdir, save_errno, strerror(save_errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) syslog(LOG_ERR, "FREEZE of / failed; error:%d %s", save_errno,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) strerror(save_errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) void print_usage(char *argv[])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) fprintf(stderr, "Usage: %s [options]\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) "Options are:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) " -n, --no-daemon stay in foreground, don't daemonize\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) " -h, --help print this help\n", argv[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) int main(int argc, char *argv[])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) int vss_fd = -1, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) struct pollfd pfd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) int op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct hv_vss_msg vss_msg[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) int daemonize = 1, long_index = 0, opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) int in_handshake;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) __u32 kernel_modver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static struct option long_options[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {"help", no_argument, 0, 'h' },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {"no-daemon", no_argument, 0, 'n' },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {0, 0, 0, 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) while ((opt = getopt_long(argc, argv, "hn", long_options,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) &long_index)) != -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) switch (opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) case 'n':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) daemonize = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) case 'h':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) print_usage(argv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) exit(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) print_usage(argv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (daemonize && daemon(1, 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) openlog("Hyper-V VSS", 0, LOG_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) reopen_vss_fd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (vss_fd != -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) close(vss_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (fs_frozen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (vss_operate(VSS_OP_THAW) || fs_frozen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) syslog(LOG_ERR, "failed to thaw file system: err=%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) errno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) in_handshake = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) vss_fd = open("/dev/vmbus/hv_vss", O_RDWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (vss_fd < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) syslog(LOG_ERR, "open /dev/vmbus/hv_vss failed; error: %d %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) errno, strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) * Register ourselves with the kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) vss_msg->vss_hdr.operation = VSS_OP_REGISTER1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (len < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) errno, strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) close(vss_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) pfd.fd = vss_fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) pfd.events = POLLIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) pfd.revents = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (poll(&pfd, 1, -1) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) syslog(LOG_ERR, "poll failed; error:%d %s", errno, strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (errno == EINVAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) close(vss_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) len = read(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (in_handshake) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (len != sizeof(kernel_modver)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) syslog(LOG_ERR, "invalid version negotiation");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) kernel_modver = *(__u32 *)vss_msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) in_handshake = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) syslog(LOG_INFO, "VSS: kernel module version: %d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) kernel_modver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (len != sizeof(struct hv_vss_msg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) syslog(LOG_ERR, "read failed; error:%d %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) errno, strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) goto reopen_vss_fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) op = vss_msg->vss_hdr.operation;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) error = HV_S_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) switch (op) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) case VSS_OP_FREEZE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) case VSS_OP_THAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) error = vss_operate(op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) syslog(LOG_INFO, "VSS: op=%s: %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) op == VSS_OP_FREEZE ? "FREEZE" : "THAW",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) error ? "failed" : "succeeded");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) error = HV_E_FAIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) syslog(LOG_ERR, "op=%d failed!", op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) syslog(LOG_ERR, "report it with these files:");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) syslog(LOG_ERR, "/etc/fstab and /proc/mounts");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) case VSS_OP_HOT_BACKUP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) syslog(LOG_INFO, "VSS: op=CHECK HOT BACKUP\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) syslog(LOG_ERR, "Illegal op:%d\n", op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * The write() may return an error due to the faked VSS_OP_THAW
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * message upon hibernation. Ignore the error by resetting the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * dev file, i.e. closing and re-opening it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) vss_msg->error = error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (len != sizeof(struct hv_vss_msg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) syslog(LOG_ERR, "write failed; error: %d %s", errno,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) goto reopen_vss_fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) close(vss_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) exit(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }