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
next prev 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: linkBe 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.