hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/tools/hv/hv_vss_daemon.c
....@@ -1,20 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * An implementation of the host initiated guest snapshot for Hyper-V.
34 *
4
- *
55 * Copyright (C) 2013, Microsoft, Inc.
66 * 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
- *
187 */
198
209
....@@ -39,6 +28,8 @@
3928 #include <stdbool.h>
4029 #include <dirent.h>
4130
31
+static bool fs_frozen;
32
+
4233 /* Don't use syslog() in the function since that can cause write to disk */
4334 static int vss_do_freeze(char *dir, unsigned int cmd)
4435 {
....@@ -53,7 +44,7 @@
5344 * If a partition is mounted more than once, only the first
5445 * FREEZE/THAW can succeed and the later ones will get
5546 * 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
5748 * by mistake or on purpose;
5849 * 2) The subvolume of btrfs appears to have the same partition
5950 * mounted more than once.
....@@ -166,17 +157,26 @@
166157 continue;
167158 }
168159 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
+ }
171165 }
172166
173167 endmntent(mounts);
174168
175169 if (root_seen) {
176170 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
+ }
179176 }
177
+
178
+ if (operation == VSS_OP_THAW && !error)
179
+ fs_frozen = false;
180180
181181 goto out;
182182 err:
....@@ -186,6 +186,7 @@
186186 endmntent(mounts);
187187 }
188188 vss_operate(VSS_OP_THAW);
189
+ fs_frozen = false;
189190 /* Call syslog after we thaw all filesystems */
190191 if (ent)
191192 syslog(LOG_ERR, "FREEZE of %s failed; error:%d %s",
....@@ -207,13 +208,13 @@
207208
208209 int main(int argc, char *argv[])
209210 {
210
- int vss_fd, len;
211
+ int vss_fd = -1, len;
211212 int error;
212213 struct pollfd pfd;
213214 int op;
214215 struct hv_vss_msg vss_msg[1];
215216 int daemonize = 1, long_index = 0, opt;
216
- int in_handshake = 1;
217
+ int in_handshake;
217218 __u32 kernel_modver;
218219
219220 static struct option long_options[] = {
....@@ -243,6 +244,18 @@
243244 openlog("Hyper-V VSS", 0, LOG_USER);
244245 syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
245246
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;
246259 vss_fd = open("/dev/vmbus/hv_vss", O_RDWR);
247260 if (vss_fd < 0) {
248261 syslog(LOG_ERR, "open /dev/vmbus/hv_vss failed; error: %d %s",
....@@ -295,8 +308,7 @@
295308 if (len != sizeof(struct hv_vss_msg)) {
296309 syslog(LOG_ERR, "read failed; error:%d %s",
297310 errno, strerror(errno));
298
- close(vss_fd);
299
- return EXIT_FAILURE;
311
+ goto reopen_vss_fd;
300312 }
301313
302314 op = vss_msg->vss_hdr.operation;
....@@ -323,14 +335,18 @@
323335 default:
324336 syslog(LOG_ERR, "Illegal op:%d\n", op);
325337 }
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
+ */
326344 vss_msg->error = error;
327345 len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
328346 if (len != sizeof(struct hv_vss_msg)) {
329347 syslog(LOG_ERR, "write failed; error: %d %s", errno,
330348 strerror(errno));
331
-
332
- if (op == VSS_OP_FREEZE)
333
- vss_operate(VSS_OP_THAW);
349
+ goto reopen_vss_fd;
334350 }
335351 }
336352