| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * An implementation of the host initiated guest snapshot for Hyper-V. |
|---|
| 3 | 4 | * |
|---|
| 4 | | - * |
|---|
| 5 | 5 | * Copyright (C) 2013, Microsoft, Inc. |
|---|
| 6 | 6 | * Author : K. Y. Srinivasan <kys@microsoft.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 9 | | - * under the terms of the GNU General Public License version 2 as published |
|---|
| 10 | | - * by the Free Software Foundation. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 13 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | | - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or |
|---|
| 15 | | - * NON INFRINGEMENT. See the GNU General Public License for more |
|---|
| 16 | | - * details. |
|---|
| 17 | | - * |
|---|
| 18 | 7 | */ |
|---|
| 19 | 8 | |
|---|
| 20 | 9 | |
|---|
| .. | .. |
|---|
| 39 | 28 | #include <stdbool.h> |
|---|
| 40 | 29 | #include <dirent.h> |
|---|
| 41 | 30 | |
|---|
| 31 | +static bool fs_frozen; |
|---|
| 32 | + |
|---|
| 42 | 33 | /* Don't use syslog() in the function since that can cause write to disk */ |
|---|
| 43 | 34 | static int vss_do_freeze(char *dir, unsigned int cmd) |
|---|
| 44 | 35 | { |
|---|
| .. | .. |
|---|
| 53 | 44 | * If a partition is mounted more than once, only the first |
|---|
| 54 | 45 | * FREEZE/THAW can succeed and the later ones will get |
|---|
| 55 | 46 | * EBUSY/EINVAL respectively: there could be 2 cases: |
|---|
| 56 | | - * 1) a user may mount the same partition to differnt directories |
|---|
| 47 | + * 1) a user may mount the same partition to different directories |
|---|
| 57 | 48 | * by mistake or on purpose; |
|---|
| 58 | 49 | * 2) The subvolume of btrfs appears to have the same partition |
|---|
| 59 | 50 | * mounted more than once. |
|---|
| .. | .. |
|---|
| 166 | 157 | continue; |
|---|
| 167 | 158 | } |
|---|
| 168 | 159 | error |= vss_do_freeze(ent->mnt_dir, cmd); |
|---|
| 169 | | - if (error && operation == VSS_OP_FREEZE) |
|---|
| 170 | | - goto err; |
|---|
| 160 | + if (operation == VSS_OP_FREEZE) { |
|---|
| 161 | + if (error) |
|---|
| 162 | + goto err; |
|---|
| 163 | + fs_frozen = true; |
|---|
| 164 | + } |
|---|
| 171 | 165 | } |
|---|
| 172 | 166 | |
|---|
| 173 | 167 | endmntent(mounts); |
|---|
| 174 | 168 | |
|---|
| 175 | 169 | if (root_seen) { |
|---|
| 176 | 170 | error |= vss_do_freeze("/", cmd); |
|---|
| 177 | | - if (error && operation == VSS_OP_FREEZE) |
|---|
| 178 | | - goto err; |
|---|
| 171 | + if (operation == VSS_OP_FREEZE) { |
|---|
| 172 | + if (error) |
|---|
| 173 | + goto err; |
|---|
| 174 | + fs_frozen = true; |
|---|
| 175 | + } |
|---|
| 179 | 176 | } |
|---|
| 177 | + |
|---|
| 178 | + if (operation == VSS_OP_THAW && !error) |
|---|
| 179 | + fs_frozen = false; |
|---|
| 180 | 180 | |
|---|
| 181 | 181 | goto out; |
|---|
| 182 | 182 | err: |
|---|
| .. | .. |
|---|
| 186 | 186 | endmntent(mounts); |
|---|
| 187 | 187 | } |
|---|
| 188 | 188 | vss_operate(VSS_OP_THAW); |
|---|
| 189 | + fs_frozen = false; |
|---|
| 189 | 190 | /* Call syslog after we thaw all filesystems */ |
|---|
| 190 | 191 | if (ent) |
|---|
| 191 | 192 | syslog(LOG_ERR, "FREEZE of %s failed; error:%d %s", |
|---|
| .. | .. |
|---|
| 207 | 208 | |
|---|
| 208 | 209 | int main(int argc, char *argv[]) |
|---|
| 209 | 210 | { |
|---|
| 210 | | - int vss_fd, len; |
|---|
| 211 | + int vss_fd = -1, len; |
|---|
| 211 | 212 | int error; |
|---|
| 212 | 213 | struct pollfd pfd; |
|---|
| 213 | 214 | int op; |
|---|
| 214 | 215 | struct hv_vss_msg vss_msg[1]; |
|---|
| 215 | 216 | int daemonize = 1, long_index = 0, opt; |
|---|
| 216 | | - int in_handshake = 1; |
|---|
| 217 | + int in_handshake; |
|---|
| 217 | 218 | __u32 kernel_modver; |
|---|
| 218 | 219 | |
|---|
| 219 | 220 | static struct option long_options[] = { |
|---|
| .. | .. |
|---|
| 243 | 244 | openlog("Hyper-V VSS", 0, LOG_USER); |
|---|
| 244 | 245 | syslog(LOG_INFO, "VSS starting; pid is:%d", getpid()); |
|---|
| 245 | 246 | |
|---|
| 247 | +reopen_vss_fd: |
|---|
| 248 | + if (vss_fd != -1) |
|---|
| 249 | + close(vss_fd); |
|---|
| 250 | + if (fs_frozen) { |
|---|
| 251 | + if (vss_operate(VSS_OP_THAW) || fs_frozen) { |
|---|
| 252 | + syslog(LOG_ERR, "failed to thaw file system: err=%d", |
|---|
| 253 | + errno); |
|---|
| 254 | + exit(EXIT_FAILURE); |
|---|
| 255 | + } |
|---|
| 256 | + } |
|---|
| 257 | + |
|---|
| 258 | + in_handshake = 1; |
|---|
| 246 | 259 | vss_fd = open("/dev/vmbus/hv_vss", O_RDWR); |
|---|
| 247 | 260 | if (vss_fd < 0) { |
|---|
| 248 | 261 | syslog(LOG_ERR, "open /dev/vmbus/hv_vss failed; error: %d %s", |
|---|
| .. | .. |
|---|
| 295 | 308 | if (len != sizeof(struct hv_vss_msg)) { |
|---|
| 296 | 309 | syslog(LOG_ERR, "read failed; error:%d %s", |
|---|
| 297 | 310 | errno, strerror(errno)); |
|---|
| 298 | | - close(vss_fd); |
|---|
| 299 | | - return EXIT_FAILURE; |
|---|
| 311 | + goto reopen_vss_fd; |
|---|
| 300 | 312 | } |
|---|
| 301 | 313 | |
|---|
| 302 | 314 | op = vss_msg->vss_hdr.operation; |
|---|
| .. | .. |
|---|
| 323 | 335 | default: |
|---|
| 324 | 336 | syslog(LOG_ERR, "Illegal op:%d\n", op); |
|---|
| 325 | 337 | } |
|---|
| 338 | + |
|---|
| 339 | + /* |
|---|
| 340 | + * The write() may return an error due to the faked VSS_OP_THAW |
|---|
| 341 | + * message upon hibernation. Ignore the error by resetting the |
|---|
| 342 | + * dev file, i.e. closing and re-opening it. |
|---|
| 343 | + */ |
|---|
| 326 | 344 | vss_msg->error = error; |
|---|
| 327 | 345 | len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg)); |
|---|
| 328 | 346 | if (len != sizeof(struct hv_vss_msg)) { |
|---|
| 329 | 347 | syslog(LOG_ERR, "write failed; error: %d %s", errno, |
|---|
| 330 | 348 | strerror(errno)); |
|---|
| 331 | | - |
|---|
| 332 | | - if (op == VSS_OP_FREEZE) |
|---|
| 333 | | - vss_operate(VSS_OP_THAW); |
|---|
| 349 | + goto reopen_vss_fd; |
|---|
| 334 | 350 | } |
|---|
| 335 | 351 | } |
|---|
| 336 | 352 | |
|---|