.. | .. |
---|
| 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 | |
---|