linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] various hyperv fixes
@ 2015-10-05 15:27 Olaf Hering
  2015-10-05 15:27 ` [PATCH 1/5] Drivers: hv: utils: run polling callback always in interrupt context Olaf Hering
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Olaf Hering @ 2015-10-05 15:27 UTC (permalink / raw)
  To: kys, haiyangz, gregkh; +Cc: linux-kernel, devel, Olaf Hering

Various hyperv changes, based on v4.3-rc4 linux.git

Olaf



Olaf Hering (5):
  Drivers: hv: utils: run polling callback always in interrupt context
  tools: hv: report ENOSPC errors in hv_fcopy_daemon
  tools: hv: remove repeated HV_FCOPY string
  Drivers: hv: util: catch allocation errors
  Drivers: hv: utils: use memdup_user in hvt_op_write

 drivers/hv/hv_fcopy.c           | 37 +++++++++++++------------------------
 drivers/hv/hv_kvp.c             | 28 ++++++++++------------------
 drivers/hv/hv_snapshot.c        | 29 +++++++++++------------------
 drivers/hv/hv_utils_transport.c | 18 ++++++++++--------
 drivers/hv/hyperv_vmbus.h       |  6 +-----
 include/uapi/linux/hyperv.h     |  1 +
 tools/hv/hv_fcopy_daemon.c      | 24 +++++++++++++++++++-----
 7 files changed, 65 insertions(+), 78 deletions(-)


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/5] Drivers: hv: utils: run polling callback always in interrupt context
  2015-10-05 15:27 [PATCH 0/5] various hyperv fixes Olaf Hering
@ 2015-10-05 15:27 ` Olaf Hering
  2015-10-05 15:27 ` [PATCH 2/5] tools: hv: report ENOSPC errors in hv_fcopy_daemon Olaf Hering
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Olaf Hering @ 2015-10-05 15:27 UTC (permalink / raw)
  To: kys, haiyangz, gregkh; +Cc: linux-kernel, devel, Olaf Hering

Currently hv_fcopy_onchannelcallback is called from interrupts and also
via the ->write function of hv_utils. Since the used global variables to
maintain state are not thread safe the state can get out of sync.
This affects the variable state as well as the channel inbound buffer.

As suggested by KY djust hv_poll_channel to always run the given
callback on the cpu which the channel is bound to. This avoids the need
for locking because all the util services are single threaded.

Remove the context variable, they will always be the same as
recv_channel. Its value will be set during the first interrupt after
negociation.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
 drivers/hv/hv_fcopy.c     | 37 +++++++++++++------------------------
 drivers/hv/hv_kvp.c       | 28 ++++++++++------------------
 drivers/hv/hv_snapshot.c  | 29 +++++++++++------------------
 drivers/hv/hyperv_vmbus.h |  6 +-----
 4 files changed, 35 insertions(+), 65 deletions(-)

diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index db4b887..da7b6f7 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -51,7 +51,6 @@ static struct {
 	struct hv_fcopy_hdr  *fcopy_msg; /* current message */
 	struct vmbus_channel *recv_channel; /* chn we got the request */
 	u64 recv_req_id; /* request ID. */
-	void *fcopy_context; /* for the channel callback */
 } fcopy_transaction;
 
 static void fcopy_respond_to_host(int error);
@@ -67,6 +66,13 @@ static struct hvutil_transport *hvt;
  */
 static int dm_reg_value;
 
+static void fcopy_poll_wrapper(void *channel)
+{
+	/* Transaction is finished, reset the state here to avoid races. */
+	fcopy_transaction.state = HVUTIL_READY;
+	hv_fcopy_onchannelcallback(channel);
+}
+
 static void fcopy_timeout_func(struct work_struct *dummy)
 {
 	/*
@@ -74,13 +80,7 @@ static void fcopy_timeout_func(struct work_struct *dummy)
 	 * process the pending transaction.
 	 */
 	fcopy_respond_to_host(HV_E_FAIL);
-
-	/* Transaction is finished, reset the state. */
-	if (fcopy_transaction.state > HVUTIL_READY)
-		fcopy_transaction.state = HVUTIL_READY;
-
-	hv_poll_channel(fcopy_transaction.fcopy_context,
-			hv_fcopy_onchannelcallback);
+	hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
 }
 
 static int fcopy_handle_handshake(u32 version)
@@ -108,9 +108,9 @@ static int fcopy_handle_handshake(u32 version)
 		return -EINVAL;
 	}
 	pr_debug("FCP: userspace daemon ver. %d registered\n", version);
+	/* Forward state for hv_fcopy_onchannelcallback */
 	fcopy_transaction.state = HVUTIL_READY;
-	hv_poll_channel(fcopy_transaction.fcopy_context,
-			hv_fcopy_onchannelcallback);
+	hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
 	return 0;
 }
 
@@ -227,15 +227,8 @@ void hv_fcopy_onchannelcallback(void *context)
 	int util_fw_version;
 	int fcopy_srv_version;
 
-	if (fcopy_transaction.state > HVUTIL_READY) {
-		/*
-		 * We will defer processing this callback once
-		 * the current transaction is complete.
-		 */
-		fcopy_transaction.fcopy_context = context;
+	if (fcopy_transaction.state > HVUTIL_READY)
 		return;
-	}
-	fcopy_transaction.fcopy_context = NULL;
 
 	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
 			 &requestid);
@@ -294,9 +287,6 @@ static int fcopy_on_msg(void *msg, int len)
 	if (fcopy_transaction.state == HVUTIL_DEVICE_INIT)
 		return fcopy_handle_handshake(*val);
 
-	if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ)
-		return -EINVAL;
-
 	/*
 	 * Complete the transaction by forwarding the result
 	 * to the host. But first, cancel the timeout.
@@ -304,9 +294,8 @@ static int fcopy_on_msg(void *msg, int len)
 	if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
 		fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
 		fcopy_respond_to_host(*val);
-		fcopy_transaction.state = HVUTIL_READY;
-		hv_poll_channel(fcopy_transaction.fcopy_context,
-				hv_fcopy_onchannelcallback);
+		hv_poll_channel(fcopy_transaction.recv_channel,
+				fcopy_poll_wrapper);
 	}
 
 	return 0;
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 74c38a9..d9777be 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -66,7 +66,6 @@ static struct {
 	struct hv_kvp_msg  *kvp_msg; /* current message */
 	struct vmbus_channel *recv_channel; /* chn we got the request */
 	u64 recv_req_id; /* request ID. */
-	void *kvp_context; /* for the channel callback */
 } kvp_transaction;
 
 /*
@@ -94,6 +93,13 @@ static struct hvutil_transport *hvt;
  */
 #define HV_DRV_VERSION           "3.1"
 
+static void kvp_poll_wrapper(void *channel)
+{
+	/* Transaction is finished, reset the state here to avoid races. */
+	kvp_transaction.state = HVUTIL_READY;
+	hv_kvp_onchannelcallback(channel);
+}
+
 static void
 kvp_register(int reg_value)
 {
@@ -121,12 +127,7 @@ static void kvp_timeout_func(struct work_struct *dummy)
 	 */
 	kvp_respond_to_host(NULL, HV_E_FAIL);
 
-	/* Transaction is finished, reset the state. */
-	if (kvp_transaction.state > HVUTIL_READY)
-		kvp_transaction.state = HVUTIL_READY;
-
-	hv_poll_channel(kvp_transaction.kvp_context,
-			hv_kvp_onchannelcallback);
+	hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
 }
 
 static int kvp_handle_handshake(struct hv_kvp_msg *msg)
@@ -218,9 +219,7 @@ static int kvp_on_msg(void *msg, int len)
 	 */
 	if (cancel_delayed_work_sync(&kvp_timeout_work)) {
 		kvp_respond_to_host(message, error);
-		kvp_transaction.state = HVUTIL_READY;
-		hv_poll_channel(kvp_transaction.kvp_context,
-				hv_kvp_onchannelcallback);
+		hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
 	}
 
 	return 0;
@@ -596,15 +595,8 @@ void hv_kvp_onchannelcallback(void *context)
 	int util_fw_version;
 	int kvp_srv_version;
 
-	if (kvp_transaction.state > HVUTIL_READY) {
-		/*
-		 * We will defer processing this callback once
-		 * the current transaction is complete.
-		 */
-		kvp_transaction.kvp_context = context;
+	if (kvp_transaction.state > HVUTIL_READY)
 		return;
-	}
-	kvp_transaction.kvp_context = NULL;
 
 	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen,
 			 &requestid);
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 815405f..a548ae4 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -53,7 +53,6 @@ static struct {
 	struct vmbus_channel *recv_channel; /* chn we got the request */
 	u64 recv_req_id; /* request ID. */
 	struct hv_vss_msg  *msg; /* current message */
-	void *vss_context; /* for the channel callback */
 } vss_transaction;
 
 
@@ -74,6 +73,13 @@ static void vss_timeout_func(struct work_struct *dummy);
 static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func);
 static DECLARE_WORK(vss_send_op_work, vss_send_op);
 
+static void vss_poll_wrapper(void *channel)
+{
+	/* Transaction is finished, reset the state here to avoid races. */
+	vss_transaction.state = HVUTIL_READY;
+	hv_vss_onchannelcallback(channel);
+}
+
 /*
  * Callback when data is received from user mode.
  */
@@ -86,12 +92,7 @@ static void vss_timeout_func(struct work_struct *dummy)
 	pr_warn("VSS: timeout waiting for daemon to reply\n");
 	vss_respond_to_host(HV_E_FAIL);
 
-	/* Transaction is finished, reset the state. */
-	if (vss_transaction.state > HVUTIL_READY)
-		vss_transaction.state = HVUTIL_READY;
-
-	hv_poll_channel(vss_transaction.vss_context,
-			hv_vss_onchannelcallback);
+	hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
 }
 
 static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
@@ -138,9 +139,8 @@ static int vss_on_msg(void *msg, int len)
 		if (cancel_delayed_work_sync(&vss_timeout_work)) {
 			vss_respond_to_host(vss_msg->error);
 			/* Transaction is finished, reset the state. */
-			vss_transaction.state = HVUTIL_READY;
-			hv_poll_channel(vss_transaction.vss_context,
-					hv_vss_onchannelcallback);
+			hv_poll_channel(vss_transaction.recv_channel,
+					vss_poll_wrapper);
 		}
 	} else {
 		/* This is a spurious call! */
@@ -238,15 +238,8 @@ void hv_vss_onchannelcallback(void *context)
 	struct icmsg_hdr *icmsghdrp;
 	struct icmsg_negotiate *negop = NULL;
 
-	if (vss_transaction.state > HVUTIL_READY) {
-		/*
-		 * We will defer processing this callback once
-		 * the current transaction is complete.
-		 */
-		vss_transaction.vss_context = context;
+	if (vss_transaction.state > HVUTIL_READY)
 		return;
-	}
-	vss_transaction.vss_context = NULL;
 
 	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
 			 &requestid);
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 3d70e36..c7fac81 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -764,11 +764,7 @@ static inline void hv_poll_channel(struct vmbus_channel *channel,
 	if (!channel)
 		return;
 
-	if (channel->target_cpu != smp_processor_id())
-		smp_call_function_single(channel->target_cpu,
-					 cb, channel, true);
-	else
-		cb(channel);
+	smp_call_function_single(channel->target_cpu, cb, channel, true);
 }
 
 enum hvutil_device_state {

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] tools: hv: report ENOSPC errors in hv_fcopy_daemon
  2015-10-05 15:27 [PATCH 0/5] various hyperv fixes Olaf Hering
  2015-10-05 15:27 ` [PATCH 1/5] Drivers: hv: utils: run polling callback always in interrupt context Olaf Hering
@ 2015-10-05 15:27 ` Olaf Hering
  2015-10-05 15:27 ` [PATCH 3/5] tools: hv: remove repeated HV_FCOPY string Olaf Hering
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Olaf Hering @ 2015-10-05 15:27 UTC (permalink / raw)
  To: kys, haiyangz, gregkh; +Cc: linux-kernel, devel, Olaf Hering

Currently some "Unspecified error 0x80004005" is reported on the Windows
side if something fails. Handle the ENOSPC case and return
ERROR_DISK_FULL, which allows at least Copy-VMFile to report a meaning
full error.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
 include/uapi/linux/hyperv.h |  1 +
 tools/hv/hv_fcopy_daemon.c  | 20 +++++++++++++++++---
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h
index e4c0a35..e347b24 100644
--- a/include/uapi/linux/hyperv.h
+++ b/include/uapi/linux/hyperv.h
@@ -313,6 +313,7 @@ enum hv_kvp_exchg_pool {
 #define HV_INVALIDARG			0x80070057
 #define HV_GUID_NOTFOUND		0x80041002
 #define HV_ERROR_ALREADY_EXISTS		0x80070050
+#define HV_ERROR_DISK_FULL		0x80070070
 
 #define ADDR_FAMILY_NONE	0x00
 #define ADDR_FAMILY_IPV4	0x01
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
index 5480e4e..f1d7426 100644
--- a/tools/hv/hv_fcopy_daemon.c
+++ b/tools/hv/hv_fcopy_daemon.c
@@ -37,12 +37,14 @@
 
 static int target_fd;
 static char target_fname[W_MAX_PATH];
+static unsigned long long filesize;
 
 static int hv_start_fcopy(struct hv_start_fcopy *smsg)
 {
 	int error = HV_E_FAIL;
 	char *q, *p;
 
+	filesize = 0;
 	p = (char *)smsg->path_name;
 	snprintf(target_fname, sizeof(target_fname), "%s/%s",
 		 (char *)smsg->path_name, (char *)smsg->file_name);
@@ -98,14 +100,26 @@ done:
 static int hv_copy_data(struct hv_do_fcopy *cpmsg)
 {
 	ssize_t bytes_written;
+	int ret = 0;
 
 	bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
 				cpmsg->offset);
 
-	if (bytes_written != cpmsg->size)
-		return HV_E_FAIL;
+	filesize += cpmsg->size;
+	if (bytes_written != cpmsg->size) {
+		switch (errno) {
+		case ENOSPC:
+			ret = HV_ERROR_DISK_FULL;
+			break;
+		default:
+			ret = HV_E_FAIL;
+			break;
+		}
+		syslog(LOG_ERR, "pwrite failed to write %llu bytes: %ld (%s)",
+		       filesize, (long)bytes_written, strerror(errno));
+	}
 
-	return 0;
+	return ret;
 }
 
 static int hv_copy_finished(void)

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] tools: hv: remove repeated HV_FCOPY string
  2015-10-05 15:27 [PATCH 0/5] various hyperv fixes Olaf Hering
  2015-10-05 15:27 ` [PATCH 1/5] Drivers: hv: utils: run polling callback always in interrupt context Olaf Hering
  2015-10-05 15:27 ` [PATCH 2/5] tools: hv: report ENOSPC errors in hv_fcopy_daemon Olaf Hering
@ 2015-10-05 15:27 ` Olaf Hering
  2015-10-05 15:27 ` [PATCH 4/5] Drivers: hv: util: catch allocation errors Olaf Hering
  2015-10-05 15:27 ` [PATCH 5/5] Drivers: hv: utils: use memdup_user in hvt_op_write Olaf Hering
  4 siblings, 0 replies; 6+ messages in thread
From: Olaf Hering @ 2015-10-05 15:27 UTC (permalink / raw)
  To: kys, haiyangz, gregkh; +Cc: linux-kernel, devel, Olaf Hering

HV_FCOPY is already used as identifier in syslog.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
 tools/hv/hv_fcopy_daemon.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
index f1d7426..fdc9ca4 100644
--- a/tools/hv/hv_fcopy_daemon.c
+++ b/tools/hv/hv_fcopy_daemon.c
@@ -179,7 +179,7 @@ int main(int argc, char *argv[])
 	}
 
 	openlog("HV_FCOPY", 0, LOG_USER);
-	syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid());
+	syslog(LOG_INFO, "starting; pid is:%d", getpid());
 
 	fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
 
@@ -215,7 +215,7 @@ int main(int argc, char *argv[])
 			}
 			kernel_modver = *(__u32 *)buffer;
 			in_handshake = 0;
-			syslog(LOG_INFO, "HV_FCOPY: kernel module version: %d",
+			syslog(LOG_INFO, "kernel module version: %d",
 			       kernel_modver);
 			continue;
 		}

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] Drivers: hv: util: catch allocation errors
  2015-10-05 15:27 [PATCH 0/5] various hyperv fixes Olaf Hering
                   ` (2 preceding siblings ...)
  2015-10-05 15:27 ` [PATCH 3/5] tools: hv: remove repeated HV_FCOPY string Olaf Hering
@ 2015-10-05 15:27 ` Olaf Hering
  2015-10-05 15:27 ` [PATCH 5/5] Drivers: hv: utils: use memdup_user in hvt_op_write Olaf Hering
  4 siblings, 0 replies; 6+ messages in thread
From: Olaf Hering @ 2015-10-05 15:27 UTC (permalink / raw)
  To: kys, haiyangz, gregkh; +Cc: linux-kernel, devel, Olaf Hering

Catch allocation errors in hvutil_transport_send.

Fixes: 14b50f80c32d ('Drivers: hv: util: introduce hv_utils_transport abstraction')

Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
 drivers/hv/hv_utils_transport.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c
index 6a9d80a..1505ee6 100644
--- a/drivers/hv/hv_utils_transport.c
+++ b/drivers/hv/hv_utils_transport.c
@@ -204,9 +204,12 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
 		goto out_unlock;
 	}
 	hvt->outmsg = kzalloc(len, GFP_KERNEL);
-	memcpy(hvt->outmsg, msg, len);
-	hvt->outmsg_len = len;
-	wake_up_interruptible(&hvt->outmsg_q);
+	if (hvt->outmsg) {
+		memcpy(hvt->outmsg, msg, len);
+		hvt->outmsg_len = len;
+		wake_up_interruptible(&hvt->outmsg_q);
+	} else
+		ret = -ENOMEM;
 out_unlock:
 	mutex_unlock(&hvt->outmsg_lock);
 	return ret;

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] Drivers: hv: utils: use memdup_user in hvt_op_write
  2015-10-05 15:27 [PATCH 0/5] various hyperv fixes Olaf Hering
                   ` (3 preceding siblings ...)
  2015-10-05 15:27 ` [PATCH 4/5] Drivers: hv: util: catch allocation errors Olaf Hering
@ 2015-10-05 15:27 ` Olaf Hering
  4 siblings, 0 replies; 6+ messages in thread
From: Olaf Hering @ 2015-10-05 15:27 UTC (permalink / raw)
  To: kys, haiyangz, gregkh; +Cc: linux-kernel, devel, Olaf Hering

Use memdup_user to handle OOM.

Fixes: 14b50f80c32d ('Drivers: hv: util: introduce hv_utils_transport abstraction')

Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
 drivers/hv/hv_utils_transport.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c
index 1505ee6..24b2766 100644
--- a/drivers/hv/hv_utils_transport.c
+++ b/drivers/hv/hv_utils_transport.c
@@ -80,11 +80,10 @@ static ssize_t hvt_op_write(struct file *file, const char __user *buf,
 
 	hvt = container_of(file->f_op, struct hvutil_transport, fops);
 
-	inmsg = kzalloc(count, GFP_KERNEL);
-	if (copy_from_user(inmsg, buf, count)) {
-		kfree(inmsg);
-		return -EFAULT;
-	}
+	inmsg = memdup_user(buf, count);
+	if (IS_ERR(inmsg))
+		return PTR_ERR(inmsg);
+
 	if (hvt->on_msg(inmsg, count))
 		return -EFAULT;
 	kfree(inmsg);

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-10-05 15:28 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-05 15:27 [PATCH 0/5] various hyperv fixes Olaf Hering
2015-10-05 15:27 ` [PATCH 1/5] Drivers: hv: utils: run polling callback always in interrupt context Olaf Hering
2015-10-05 15:27 ` [PATCH 2/5] tools: hv: report ENOSPC errors in hv_fcopy_daemon Olaf Hering
2015-10-05 15:27 ` [PATCH 3/5] tools: hv: remove repeated HV_FCOPY string Olaf Hering
2015-10-05 15:27 ` [PATCH 4/5] Drivers: hv: util: catch allocation errors Olaf Hering
2015-10-05 15:27 ` [PATCH 5/5] Drivers: hv: utils: use memdup_user in hvt_op_write Olaf Hering

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).