hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/tools/hv/hv_fcopy_daemon.c
....@@ -1,19 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * An implementation of host to guest copy functionality for Linux.
34 *
45 * Copyright (C) 2014, Microsoft, Inc.
56 *
67 * 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.
178 */
189
1910
....@@ -89,6 +80,8 @@
8980
9081 error = 0;
9182 done:
83
+ if (error)
84
+ target_fname[0] = '\0';
9285 return error;
9386 }
9487
....@@ -117,15 +110,29 @@
117110 return ret;
118111 }
119112
113
+/*
114
+ * Reset target_fname to "" in the two below functions for hibernation: if
115
+ * the fcopy operation is aborted by hibernation, the daemon should remove the
116
+ * partially-copied file; to achieve this, the hv_utils driver always fakes a
117
+ * CANCEL_FCOPY message upon suspend, and later when the VM resumes back,
118
+ * the daemon calls hv_copy_cancel() to remove the file; if a file is copied
119
+ * successfully before suspend, hv_copy_finished() must reset target_fname to
120
+ * avoid that the file can be incorrectly removed upon resume, since the faked
121
+ * CANCEL_FCOPY message is spurious in this case.
122
+ */
120123 static int hv_copy_finished(void)
121124 {
122125 close(target_fd);
126
+ target_fname[0] = '\0';
123127 return 0;
124128 }
125129 static int hv_copy_cancel(void)
126130 {
127131 close(target_fd);
128
- unlink(target_fname);
132
+ if (strlen(target_fname) > 0) {
133
+ unlink(target_fname);
134
+ target_fname[0] = '\0';
135
+ }
129136 return 0;
130137
131138 }
....@@ -140,7 +147,7 @@
140147
141148 int main(int argc, char *argv[])
142149 {
143
- int fcopy_fd;
150
+ int fcopy_fd = -1;
144151 int error;
145152 int daemonize = 1, long_index = 0, opt;
146153 int version = FCOPY_CURRENT_VERSION;
....@@ -150,7 +157,7 @@
150157 struct hv_do_fcopy copy;
151158 __u32 kernel_modver;
152159 } buffer = { };
153
- int in_handshake = 1;
160
+ int in_handshake;
154161
155162 static struct option long_options[] = {
156163 {"help", no_argument, 0, 'h' },
....@@ -179,6 +186,12 @@
179186 openlog("HV_FCOPY", 0, LOG_USER);
180187 syslog(LOG_INFO, "starting; pid is:%d", getpid());
181188
189
+reopen_fcopy_fd:
190
+ if (fcopy_fd != -1)
191
+ close(fcopy_fd);
192
+ /* Remove any possible partially-copied file on error */
193
+ hv_copy_cancel();
194
+ in_handshake = 1;
182195 fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
183196
184197 if (fcopy_fd < 0) {
....@@ -205,7 +218,7 @@
205218 len = pread(fcopy_fd, &buffer, sizeof(buffer), 0);
206219 if (len < 0) {
207220 syslog(LOG_ERR, "pread failed: %s", strerror(errno));
208
- exit(EXIT_FAILURE);
221
+ goto reopen_fcopy_fd;
209222 }
210223
211224 if (in_handshake) {
....@@ -240,9 +253,14 @@
240253
241254 }
242255
256
+ /*
257
+ * pwrite() may return an error due to the faked CANCEL_FCOPY
258
+ * message upon hibernation. Ignore the error by resetting the
259
+ * dev file, i.e. closing and re-opening it.
260
+ */
243261 if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) {
244262 syslog(LOG_ERR, "pwrite failed: %s", strerror(errno));
245
- exit(EXIT_FAILURE);
263
+ goto reopen_fcopy_fd;
246264 }
247265 }
248266 }