hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/hv/hv_fcopy.c
....@@ -1,20 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * An implementation of file copy service.
34 *
45 * Copyright (C) 2014, Microsoft, Inc.
56 *
67 * Author : K. Y. Srinivasan <ksrinivasan@novell.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
- *
188 */
199
2010 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
....@@ -23,6 +13,7 @@
2313 #include <linux/workqueue.h>
2414 #include <linux/hyperv.h>
2515 #include <linux/sched.h>
16
+#include <asm/hyperv-tlfs.h>
2617
2718 #include "hyperv_vmbus.h"
2819 #include "hv_utils_transport.h"
....@@ -80,7 +71,7 @@
8071 {
8172 /* Transaction is finished, reset the state here to avoid races. */
8273 fcopy_transaction.state = HVUTIL_READY;
83
- hv_fcopy_onchannelcallback(channel);
74
+ tasklet_schedule(&((struct vmbus_channel *)channel)->callback_event);
8475 }
8576
8677 static void fcopy_timeout_func(struct work_struct *dummy)
....@@ -244,7 +235,7 @@
244235 if (fcopy_transaction.state > HVUTIL_READY)
245236 return;
246237
247
- vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
238
+ vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen,
248239 &requestid);
249240 if (recvlen <= 0)
250241 return;
....@@ -355,9 +346,61 @@
355346 return 0;
356347 }
357348
349
+static void hv_fcopy_cancel_work(void)
350
+{
351
+ cancel_delayed_work_sync(&fcopy_timeout_work);
352
+ cancel_work_sync(&fcopy_send_work);
353
+}
354
+
355
+int hv_fcopy_pre_suspend(void)
356
+{
357
+ struct vmbus_channel *channel = fcopy_transaction.recv_channel;
358
+ struct hv_fcopy_hdr *fcopy_msg;
359
+
360
+ /*
361
+ * Fake a CANCEL_FCOPY message for the user space daemon in case the
362
+ * daemon is in the middle of copying some file. It doesn't matter if
363
+ * there is already a message pending to be delivered to the user
364
+ * space since we force fcopy_transaction.state to be HVUTIL_READY, so
365
+ * the user space daemon's write() will fail with EINVAL (see
366
+ * fcopy_on_msg()), and the daemon will reset the device by closing
367
+ * and re-opening it.
368
+ */
369
+ fcopy_msg = kzalloc(sizeof(*fcopy_msg), GFP_KERNEL);
370
+ if (!fcopy_msg)
371
+ return -ENOMEM;
372
+
373
+ tasklet_disable(&channel->callback_event);
374
+
375
+ fcopy_msg->operation = CANCEL_FCOPY;
376
+
377
+ hv_fcopy_cancel_work();
378
+
379
+ /* We don't care about the return value. */
380
+ hvutil_transport_send(hvt, fcopy_msg, sizeof(*fcopy_msg), NULL);
381
+
382
+ kfree(fcopy_msg);
383
+
384
+ fcopy_transaction.state = HVUTIL_READY;
385
+
386
+ /* tasklet_enable() will be called in hv_fcopy_pre_resume(). */
387
+ return 0;
388
+}
389
+
390
+int hv_fcopy_pre_resume(void)
391
+{
392
+ struct vmbus_channel *channel = fcopy_transaction.recv_channel;
393
+
394
+ tasklet_enable(&channel->callback_event);
395
+
396
+ return 0;
397
+}
398
+
358399 void hv_fcopy_deinit(void)
359400 {
360401 fcopy_transaction.state = HVUTIL_DEVICE_DYING;
361
- cancel_delayed_work_sync(&fcopy_timeout_work);
402
+
403
+ hv_fcopy_cancel_work();
404
+
362405 hvutil_transport_destroy(hvt);
363406 }