All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stefano Stabellini <sstabellini@kernel.org>
To: xen-devel@lists.xen.org
Cc: linux-kernel@vger.kernel.org, sstabellini@kernel.org,
	jgross@suse.com, boris.ostrovsky@oracle.com,
	Stefano Stabellini <stefano@aporeto.com>
Subject: [PATCH v3 10/13] xen/pvcalls: implement recvmsg
Date: Mon, 31 Jul 2017 15:57:32 -0700	[thread overview]
Message-ID: <1501541855-7354-10-git-send-email-sstabellini@kernel.org> (raw)
In-Reply-To: <1501541855-7354-1-git-send-email-sstabellini@kernel.org>

Implement recvmsg by copying data from the "in" ring. If not enough data
is available and the recvmsg call is blocking, then wait on the
inflight_conn_req waitqueue. Take the active socket in_mutex so that
only one function can access the ring at any given time.

If no data is available on the ring, rather than returning immediately
or sleep-waiting, spin for up to 5000 cycles. This small optimization
turns out to improve performance and latency significantly.

Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
 drivers/xen/pvcalls-front.c | 102 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/xen/pvcalls-front.h |   4 ++
 2 files changed, 106 insertions(+)

diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index 369acde..635a83a 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -105,6 +105,20 @@ static int pvcalls_front_write_todo(struct sock_mapping *map)
 	return size - pvcalls_queued(prod, cons, size);
 }
 
+static bool pvcalls_front_read_todo(struct sock_mapping *map)
+{
+	struct pvcalls_data_intf *intf = map->active.ring;
+	RING_IDX cons, prod;
+	int32_t error;
+
+	cons = intf->in_cons;
+	prod = intf->in_prod;
+	error = intf->in_error;
+	return (error != 0 ||
+		pvcalls_queued(prod, cons,
+			       XEN_FLEX_RING_SIZE(intf->ring_order)) != 0);
+}
+
 static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
 {
 	struct xenbus_device *dev = dev_id;
@@ -434,6 +448,94 @@ int pvcalls_front_sendmsg(struct socket *sock, struct msghdr *msg,
 	return tot_sent;
 }
 
+static int __read_ring(struct pvcalls_data_intf *intf,
+		       struct pvcalls_data *data,
+		       struct iov_iter *msg_iter,
+		       size_t len, int flags)
+{
+	RING_IDX cons, prod, size, masked_prod, masked_cons;
+	RING_IDX array_size = XEN_FLEX_RING_SIZE(intf->ring_order);
+	int32_t error;
+
+	cons = intf->in_cons;
+	prod = intf->in_prod;
+	error = intf->in_error;
+	/* get pointers before reading from the ring */
+	virt_rmb();
+	if (error < 0)
+		return error;
+
+	size = pvcalls_queued(prod, cons, array_size);
+	masked_prod = pvcalls_mask(prod, array_size);
+	masked_cons = pvcalls_mask(cons, array_size);
+
+	if (size == 0)
+		return 0;
+
+	if (len > size)
+		len = size;
+
+	if (masked_prod > masked_cons) {
+		copy_to_iter(data->in + masked_cons, len, msg_iter);
+	} else {
+		if (len > (array_size - masked_cons)) {
+			copy_to_iter(data->in + masked_cons,
+				     array_size - masked_cons, msg_iter);
+			copy_to_iter(data->in,
+				     len - (array_size - masked_cons),
+				     msg_iter);
+		} else {
+			copy_to_iter(data->in + masked_cons, len, msg_iter);
+		}
+	}
+	/* read data from the ring before increasing the index */
+	virt_mb();
+	if (!(flags & MSG_PEEK))
+		intf->in_cons += len;
+
+	return len;
+}
+
+int pvcalls_front_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+		     int flags)
+{
+	struct pvcalls_bedata *bedata;
+	int ret = -EAGAIN;
+	struct sock_mapping *map;
+
+	if (!pvcalls_front_dev)
+		return -ENOTCONN;
+	bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
+
+	map = (struct sock_mapping *) READ_ONCE(sock->sk->sk_send_head);
+	if (!map)
+		return -ENOTSOCK;
+
+	if (flags & (MSG_CMSG_CLOEXEC|MSG_ERRQUEUE|MSG_OOB|MSG_TRUNC))
+		return -EOPNOTSUPP;
+
+	mutex_lock(&map->active.in_mutex);
+	if (len > XEN_FLEX_RING_SIZE(map->active.ring->ring_order))
+		len = XEN_FLEX_RING_SIZE(map->active.ring->ring_order);
+
+	while (!(flags & MSG_DONTWAIT) && !pvcalls_front_read_todo(map)) {
+		wait_event_interruptible(map->active.inflight_conn_req,
+					 pvcalls_front_read_todo(map));
+	}
+	ret = __read_ring(map->active.ring, &map->active.data,
+			  &msg->msg_iter, len, flags);
+
+	if (ret > 0)
+		notify_remote_via_irq(map->active.irq);
+	if (ret == 0)
+		ret = -EAGAIN;
+	if (ret == -ENOTCONN)
+		ret = 0;
+
+	mutex_unlock(&map->active.in_mutex);
+	return ret;
+}
+
 int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
 {
 	struct pvcalls_bedata *bedata;
diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h
index d937c24..de24041 100644
--- a/drivers/xen/pvcalls-front.h
+++ b/drivers/xen/pvcalls-front.h
@@ -16,5 +16,9 @@ int pvcalls_front_accept(struct socket *sock,
 int pvcalls_front_sendmsg(struct socket *sock,
 			  struct msghdr *msg,
 			  size_t len);
+int pvcalls_front_recvmsg(struct socket *sock,
+			  struct msghdr *msg,
+			  size_t len,
+			  int flags);
 
 #endif
-- 
1.9.1

WARNING: multiple messages have this Message-ID (diff)
From: Stefano Stabellini <sstabellini@kernel.org>
To: xen-devel@lists.xen.org
Cc: jgross@suse.com, Stefano Stabellini <stefano@aporeto.com>,
	boris.ostrovsky@oracle.com, sstabellini@kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH v3 10/13] xen/pvcalls: implement recvmsg
Date: Mon, 31 Jul 2017 15:57:32 -0700	[thread overview]
Message-ID: <1501541855-7354-10-git-send-email-sstabellini@kernel.org> (raw)
In-Reply-To: <1501541855-7354-1-git-send-email-sstabellini@kernel.org>

Implement recvmsg by copying data from the "in" ring. If not enough data
is available and the recvmsg call is blocking, then wait on the
inflight_conn_req waitqueue. Take the active socket in_mutex so that
only one function can access the ring at any given time.

If no data is available on the ring, rather than returning immediately
or sleep-waiting, spin for up to 5000 cycles. This small optimization
turns out to improve performance and latency significantly.

Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
 drivers/xen/pvcalls-front.c | 102 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/xen/pvcalls-front.h |   4 ++
 2 files changed, 106 insertions(+)

diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index 369acde..635a83a 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -105,6 +105,20 @@ static int pvcalls_front_write_todo(struct sock_mapping *map)
 	return size - pvcalls_queued(prod, cons, size);
 }
 
+static bool pvcalls_front_read_todo(struct sock_mapping *map)
+{
+	struct pvcalls_data_intf *intf = map->active.ring;
+	RING_IDX cons, prod;
+	int32_t error;
+
+	cons = intf->in_cons;
+	prod = intf->in_prod;
+	error = intf->in_error;
+	return (error != 0 ||
+		pvcalls_queued(prod, cons,
+			       XEN_FLEX_RING_SIZE(intf->ring_order)) != 0);
+}
+
 static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
 {
 	struct xenbus_device *dev = dev_id;
@@ -434,6 +448,94 @@ int pvcalls_front_sendmsg(struct socket *sock, struct msghdr *msg,
 	return tot_sent;
 }
 
+static int __read_ring(struct pvcalls_data_intf *intf,
+		       struct pvcalls_data *data,
+		       struct iov_iter *msg_iter,
+		       size_t len, int flags)
+{
+	RING_IDX cons, prod, size, masked_prod, masked_cons;
+	RING_IDX array_size = XEN_FLEX_RING_SIZE(intf->ring_order);
+	int32_t error;
+
+	cons = intf->in_cons;
+	prod = intf->in_prod;
+	error = intf->in_error;
+	/* get pointers before reading from the ring */
+	virt_rmb();
+	if (error < 0)
+		return error;
+
+	size = pvcalls_queued(prod, cons, array_size);
+	masked_prod = pvcalls_mask(prod, array_size);
+	masked_cons = pvcalls_mask(cons, array_size);
+
+	if (size == 0)
+		return 0;
+
+	if (len > size)
+		len = size;
+
+	if (masked_prod > masked_cons) {
+		copy_to_iter(data->in + masked_cons, len, msg_iter);
+	} else {
+		if (len > (array_size - masked_cons)) {
+			copy_to_iter(data->in + masked_cons,
+				     array_size - masked_cons, msg_iter);
+			copy_to_iter(data->in,
+				     len - (array_size - masked_cons),
+				     msg_iter);
+		} else {
+			copy_to_iter(data->in + masked_cons, len, msg_iter);
+		}
+	}
+	/* read data from the ring before increasing the index */
+	virt_mb();
+	if (!(flags & MSG_PEEK))
+		intf->in_cons += len;
+
+	return len;
+}
+
+int pvcalls_front_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+		     int flags)
+{
+	struct pvcalls_bedata *bedata;
+	int ret = -EAGAIN;
+	struct sock_mapping *map;
+
+	if (!pvcalls_front_dev)
+		return -ENOTCONN;
+	bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
+
+	map = (struct sock_mapping *) READ_ONCE(sock->sk->sk_send_head);
+	if (!map)
+		return -ENOTSOCK;
+
+	if (flags & (MSG_CMSG_CLOEXEC|MSG_ERRQUEUE|MSG_OOB|MSG_TRUNC))
+		return -EOPNOTSUPP;
+
+	mutex_lock(&map->active.in_mutex);
+	if (len > XEN_FLEX_RING_SIZE(map->active.ring->ring_order))
+		len = XEN_FLEX_RING_SIZE(map->active.ring->ring_order);
+
+	while (!(flags & MSG_DONTWAIT) && !pvcalls_front_read_todo(map)) {
+		wait_event_interruptible(map->active.inflight_conn_req,
+					 pvcalls_front_read_todo(map));
+	}
+	ret = __read_ring(map->active.ring, &map->active.data,
+			  &msg->msg_iter, len, flags);
+
+	if (ret > 0)
+		notify_remote_via_irq(map->active.irq);
+	if (ret == 0)
+		ret = -EAGAIN;
+	if (ret == -ENOTCONN)
+		ret = 0;
+
+	mutex_unlock(&map->active.in_mutex);
+	return ret;
+}
+
 int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
 {
 	struct pvcalls_bedata *bedata;
diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h
index d937c24..de24041 100644
--- a/drivers/xen/pvcalls-front.h
+++ b/drivers/xen/pvcalls-front.h
@@ -16,5 +16,9 @@ int pvcalls_front_accept(struct socket *sock,
 int pvcalls_front_sendmsg(struct socket *sock,
 			  struct msghdr *msg,
 			  size_t len);
+int pvcalls_front_recvmsg(struct socket *sock,
+			  struct msghdr *msg,
+			  size_t len,
+			  int flags);
 
 #endif
-- 
1.9.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

  parent reply	other threads:[~2017-07-31 23:03 UTC|newest]

Thread overview: 89+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-31 22:57 [PATCH v3 00/13] introduce the Xen PV Calls frontend Stefano Stabellini
2017-07-31 22:57 ` [PATCH v3 01/13] xen/pvcalls: introduce the pvcalls xenbus frontend Stefano Stabellini
2017-07-31 22:57   ` Stefano Stabellini
2017-07-31 22:57   ` [PATCH v3 02/13] xen/pvcalls: implement frontend disconnect Stefano Stabellini
2017-08-11 22:43     ` Boris Ostrovsky
2017-08-11 22:43       ` Boris Ostrovsky
2017-09-09  0:07       ` Stefano Stabellini
2017-09-09  0:07       ` Stefano Stabellini
2017-07-31 22:57   ` Stefano Stabellini
2017-07-31 22:57   ` [PATCH v3 03/13] xen/pvcalls: connect to the backend Stefano Stabellini
2017-07-31 22:57     ` Stefano Stabellini
2017-08-11 22:55     ` Boris Ostrovsky
2017-08-11 22:55     ` Boris Ostrovsky
2017-09-09  0:14       ` Stefano Stabellini
2017-09-09  0:14       ` Stefano Stabellini
2017-07-31 22:57   ` [PATCH v3 04/13] xen/pvcalls: implement socket command and handle events Stefano Stabellini
2017-07-31 22:57     ` Stefano Stabellini
2017-08-13  0:42     ` Boris Ostrovsky
2017-09-08 23:20       ` Stefano Stabellini
2017-09-08 23:20       ` Stefano Stabellini
2017-08-13  0:42     ` Boris Ostrovsky
2017-07-31 22:57   ` [PATCH v3 05/13] xen/pvcalls: implement connect command Stefano Stabellini
2017-07-31 22:57     ` Stefano Stabellini
2017-08-13  1:12     ` Boris Ostrovsky
2017-09-08 21:23       ` Stefano Stabellini
2017-09-08 21:23       ` Stefano Stabellini
2017-08-13  1:12     ` Boris Ostrovsky
2017-07-31 22:57   ` [PATCH v3 06/13] xen/pvcalls: implement bind command Stefano Stabellini
2017-07-31 22:57   ` Stefano Stabellini
2017-08-13  1:22     ` Boris Ostrovsky
2017-09-08 21:46       ` Stefano Stabellini
2017-09-08 21:46       ` Stefano Stabellini
2017-08-13  1:22     ` Boris Ostrovsky
2017-07-31 22:57   ` [PATCH v3 07/13] xen/pvcalls: implement listen command Stefano Stabellini
2017-08-13  1:28     ` Boris Ostrovsky
2017-08-13  1:28     ` Boris Ostrovsky
2017-07-31 22:57   ` Stefano Stabellini
2017-07-31 22:57   ` [PATCH v3 08/13] xen/pvcalls: implement accept command Stefano Stabellini
2017-07-31 22:57     ` Stefano Stabellini
2017-08-15  2:00     ` Boris Ostrovsky
2017-08-15  2:00     ` Boris Ostrovsky
2017-08-15  2:04       ` Boris Ostrovsky
2017-08-15  2:04       ` Boris Ostrovsky
2017-09-08 21:58         ` Stefano Stabellini
2017-09-08 21:58         ` Stefano Stabellini
2017-09-08 22:16       ` Stefano Stabellini
2017-09-08 22:16       ` Stefano Stabellini
2017-07-31 22:57   ` [PATCH v3 09/13] xen/pvcalls: implement sendmsg Stefano Stabellini
2017-07-31 22:57     ` Stefano Stabellini
2017-08-15  2:31     ` Boris Ostrovsky
2017-08-15  2:31       ` Boris Ostrovsky
2017-09-08 23:48       ` Stefano Stabellini
2017-09-08 23:48       ` Stefano Stabellini
2017-07-31 22:57   ` Stefano Stabellini [this message]
2017-07-31 22:57     ` [PATCH v3 10/13] xen/pvcalls: implement recvmsg Stefano Stabellini
2017-08-15  2:39     ` Boris Ostrovsky
2017-08-15  2:39       ` Boris Ostrovsky
2017-09-08 23:11       ` Stefano Stabellini
2017-09-08 23:11       ` Stefano Stabellini
2017-07-31 22:57   ` [PATCH v3 11/13] xen/pvcalls: implement poll command Stefano Stabellini
2017-07-31 22:57   ` Stefano Stabellini
2017-08-15 20:30     ` Boris Ostrovsky
2017-08-15 20:30     ` Boris Ostrovsky
2017-09-08 23:03       ` Stefano Stabellini
2017-09-12 14:14         ` Boris Ostrovsky
2017-09-12 22:17           ` Stefano Stabellini
2017-09-12 22:17           ` Stefano Stabellini
2017-09-12 23:04             ` Boris Ostrovsky
2017-09-12 23:13               ` Stefano Stabellini
2017-09-12 23:18                 ` Stefano Stabellini
2017-09-12 23:18                   ` Stefano Stabellini
2017-09-12 23:13               ` Stefano Stabellini
2017-09-12 23:04             ` Boris Ostrovsky
2017-09-12 14:14         ` Boris Ostrovsky
2017-09-08 23:03       ` Stefano Stabellini
2017-07-31 22:57   ` [PATCH v3 12/13] xen/pvcalls: implement release command Stefano Stabellini
2017-08-15 20:44     ` Boris Ostrovsky
2017-08-15 20:44     ` Boris Ostrovsky
2017-09-08 23:09       ` Stefano Stabellini
2017-09-08 23:09       ` Stefano Stabellini
2017-07-31 22:57   ` Stefano Stabellini
2017-07-31 22:57   ` [PATCH v3 13/13] xen: introduce a Kconfig option to enable the pvcalls frontend Stefano Stabellini
2017-07-31 22:57     ` Stefano Stabellini
2017-08-11 22:36   ` [PATCH v3 01/13] xen/pvcalls: introduce the pvcalls xenbus frontend Boris Ostrovsky
2017-08-11 22:36   ` Boris Ostrovsky
2017-08-10 15:07 ` [PATCH v3 00/13] introduce the Xen PV Calls frontend Boris Ostrovsky
2017-08-10 15:07 ` Boris Ostrovsky
2017-08-10 18:15   ` Stefano Stabellini
2017-08-10 18:15   ` Stefano Stabellini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1501541855-7354-10-git-send-email-sstabellini@kernel.org \
    --to=sstabellini@kernel.org \
    --cc=boris.ostrovsky@oracle.com \
    --cc=jgross@suse.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stefano@aporeto.com \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.