Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1694071 > unrolled thread
| Started by | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| First post | 2017-07-22 02:20 +0200 |
| Last post | 2017-07-25 00:40 +0200 |
| Articles | 18 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v1 00/13] introduce the Xen PV Calls frontend Stefano Stabellini <sstabellini@kernel.org> - 2017-07-22 02:20 +0200
[PATCH v1 12/13] xen/pvcalls: implement frontend disconnect Stefano Stabellini <sstabellini@kernel.org> - 2017-07-22 02:20 +0200
Re: [PATCH v1 12/13] xen/pvcalls: implement frontend disconnect Juergen Gross <jgross@suse.com> - 2017-07-24 22:20 +0200
[PATCH v1 11/13] xen/pvcalls: implement release command Stefano Stabellini <sstabellini@kernel.org> - 2017-07-22 02:20 +0200
Re: [PATCH v1 11/13] xen/pvcalls: implement release command Juergen Gross <jgross@suse.com> - 2017-07-24 22:20 +0200
Re: [PATCH v1 11/13] xen/pvcalls: implement release command Stefano Stabellini <sstabellini@kernel.org> - 2017-07-25 23:10 +0200
[PATCH v1 01/13] xen/pvcalls: introduce the pvcalls xenbus frontend Stefano Stabellini <sstabellini@kernel.org> - 2017-07-22 02:20 +0200
[PATCH v1 09/13] xen/pvcalls: implement recvmsg Stefano Stabellini <sstabellini@kernel.org> - 2017-07-22 02:20 +0200
Re: [PATCH v1 09/13] xen/pvcalls: implement recvmsg Juergen Gross <jgross@suse.com> - 2017-07-24 22:00 +0200
Re: [PATCH v1 09/13] xen/pvcalls: implement recvmsg Stefano Stabellini <sstabellini@kernel.org> - 2017-07-25 00:40 +0200
[PATCH v1 07/13] xen/pvcalls: implement accept command Stefano Stabellini <sstabellini@kernel.org> - 2017-07-22 02:20 +0200
Re: [PATCH v1 07/13] xen/pvcalls: implement accept command Juergen Gross <jgross@suse.com> - 2017-07-24 21:50 +0200
Re: [PATCH v1 07/13] xen/pvcalls: implement accept command Stefano Stabellini <sstabellini@kernel.org> - 2017-07-25 01:00 +0200
[PATCH v1 08/13] xen/pvcalls: implement sendmsg Stefano Stabellini <sstabellini@kernel.org> - 2017-07-22 02:20 +0200
Re: [PATCH v1 08/13] xen/pvcalls: implement sendmsg Juergen Gross <jgross@suse.com> - 2017-07-24 22:00 +0200
Re: [PATCH v1 08/13] xen/pvcalls: implement sendmsg Stefano Stabellini <sstabellini@kernel.org> - 2017-07-25 00:40 +0200
Re: [PATCH v1 01/13] xen/pvcalls: introduce the pvcalls xenbus frontend Juergen Gross <jgross@suse.com> - 2017-07-24 21:10 +0200
Re: [PATCH v1 01/13] xen/pvcalls: introduce the pvcalls xenbus frontend Stefano Stabellini <sstabellini@kernel.org> - 2017-07-25 00:40 +0200
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-22 02:20 +0200 |
| Subject | [PATCH v1 00/13] introduce the Xen PV Calls frontend |
| Message-ID | <u5Qjf-3b8-3@gated-at.bofh.it> |
Hi all,
this series introduces the frontend for the newly introduced PV Calls
procotol.
PV Calls is a paravirtualized protocol that allows the implementation of
a set of POSIX functions in a different domain. The PV Calls frontend
sends POSIX function calls to the backend, which implements them and
returns a value to the frontend and acts on the function call.
For more information about PV Calls, please read:
https://xenbits.xen.org/docs/unstable/misc/pvcalls.html
This patch series only implements the frontend driver. It doesn't
attempt to redirect POSIX calls to it. The functions exported in
pvcalls-front.h are meant to be used for that. A separate patch series
will be sent to use them and hook them into the system.
Stefano Stabellini (13):
xen/pvcalls: introduce the pvcalls xenbus frontend
xen/pvcalls: connect to the backend
xen/pvcalls: implement socket command and handle events
xen/pvcalls: implement connect command
xen/pvcalls: implement bind command
xen/pvcalls: implement listen command
xen/pvcalls: implement accept command
xen/pvcalls: implement sendmsg
xen/pvcalls: implement recvmsg
xen/pvcalls: implement poll command
xen/pvcalls: implement release command
xen/pvcalls: implement frontend disconnect
xen: introduce a Kconfig option to enable the pvcalls frontend
drivers/xen/Kconfig | 9 +
drivers/xen/Makefile | 1 +
drivers/xen/pvcalls-front.c | 1097 +++++++++++++++++++++++++++++++++++++++++++
drivers/xen/pvcalls-front.h | 28 ++
4 files changed, 1135 insertions(+)
create mode 100644 drivers/xen/pvcalls-front.c
create mode 100644 drivers/xen/pvcalls-front.h
[toc] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-22 02:20 +0200 |
| Subject | [PATCH v1 12/13] xen/pvcalls: implement frontend disconnect |
| Message-ID | <u5Qjg-3b8-25@gated-at.bofh.it> |
| In reply to | #1694071 |
Implement pvcalls frontend removal function. Go through the list of
active and passive sockets and free them all, one at a time.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-front.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index bd3dfac..fcc15fb 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -898,6 +898,34 @@ int pvcalls_front_release(struct socket *sock)
static int pvcalls_front_remove(struct xenbus_device *dev)
{
+ struct pvcalls_bedata *bedata;
+ struct sock_mapping *map = NULL, *n;
+
+ bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
+
+ list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) {
+ mutex_lock(&map->active.in_mutex);
+ mutex_lock(&map->active.out_mutex);
+ pvcalls_front_free_map(bedata, map);
+ mutex_unlock(&map->active.out_mutex);
+ mutex_unlock(&map->active.in_mutex);
+ kfree(map);
+ }
+ list_for_each_entry_safe(map, n, &bedata->socketpass_mappings, list) {
+ spin_lock(&bedata->pvcallss_lock);
+ list_del_init(&map->list);
+ spin_unlock(&bedata->pvcallss_lock);
+ kfree(map);
+ }
+ if (bedata->irq > 0)
+ unbind_from_irqhandler(bedata->irq, dev);
+ if (bedata->ref >= 0)
+ gnttab_end_foreign_access(bedata->ref, 0, 0);
+ kfree(bedata->ring.sring);
+ kfree(bedata);
+ dev_set_drvdata(&dev->dev, NULL);
+ xenbus_switch_state(dev, XenbusStateClosed);
+ pvcalls_front_dev = NULL;
return 0;
}
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Juergen Gross <jgross@suse.com> |
|---|---|
| Date | 2017-07-24 22:20 +0200 |
| Subject | Re: [PATCH v1 12/13] xen/pvcalls: implement frontend disconnect |
| Message-ID | <u6RZD-1pl-13@gated-at.bofh.it> |
| In reply to | #1694072 |
On 22/07/17 02:12, Stefano Stabellini wrote: > Implement pvcalls frontend removal function. Go through the list of > active and passive sockets and free them all, one at a time. > > Signed-off-by: Stefano Stabellini <stefano@aporeto.com> > CC: boris.ostrovsky@oracle.com > CC: jgross@suse.com Reviewed-by: Juergen Gross <jgross@suse.com> Juergen
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-22 02:20 +0200 |
| Subject | [PATCH v1 11/13] xen/pvcalls: implement release command |
| Message-ID | <u5Qjg-3b8-19@gated-at.bofh.it> |
| In reply to | #1694071 |
Send PVCALLS_RELEASE to the backend and wait for a reply. Take both
in_mutex and out_mutex to avoid concurrent accesses. Then, free the
socket.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-front.c | 86 +++++++++++++++++++++++++++++++++++++++++++++
drivers/xen/pvcalls-front.h | 1 +
2 files changed, 87 insertions(+)
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index b6cfb7d..bd3dfac 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -174,6 +174,24 @@ static irqreturn_t pvcalls_front_conn_handler(int irq, void *sock_map)
return IRQ_HANDLED;
}
+static void pvcalls_front_free_map(struct pvcalls_bedata *bedata,
+ struct sock_mapping *map)
+{
+ int i;
+
+ spin_lock(&bedata->pvcallss_lock);
+ if (!list_empty(&map->list))
+ list_del_init(&map->list);
+ spin_unlock(&bedata->pvcallss_lock);
+
+ /* what if the thread waiting still need access? */
+ for (i = 0; i < (1 << map->active.ring->ring_order); i++)
+ gnttab_end_foreign_access(map->active.ring->ref[i], 0, 0);
+ gnttab_end_foreign_access(map->active.ref, 0, 0);
+ free_page((unsigned long)map->active.ring);
+ unbind_from_irqhandler(map->active.irq, map);
+}
+
int pvcalls_front_socket(struct socket *sock)
{
struct pvcalls_bedata *bedata;
@@ -805,6 +823,74 @@ unsigned int pvcalls_front_poll(struct file *file, struct socket *sock,
return pvcalls_front_poll_passive(file, bedata, map, wait);
}
+int pvcalls_front_release(struct socket *sock)
+{
+ struct pvcalls_bedata *bedata;
+ struct sock_mapping *map;
+ int req_id, notify;
+ struct xen_pvcalls_request *req;
+
+ if (!pvcalls_front_dev)
+ return -EIO;
+ bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
+ if (!bedata)
+ return -EIO;
+
+ if (sock->sk == NULL)
+ return 0;
+
+ map = (struct sock_mapping *) READ_ONCE(sock->sk->sk_send_head);
+ if (map == NULL)
+ return 0;
+ WRITE_ONCE(sock->sk->sk_send_head, NULL);
+
+ spin_lock(&bedata->pvcallss_lock);
+ req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
+ BUG_ON(req_id >= PVCALLS_NR_REQ_PER_RING);
+ if (RING_FULL(&bedata->ring) ||
+ READ_ONCE(bedata->rsp[req_id].req_id) != PVCALLS_INVALID_ID) {
+ spin_unlock(&bedata->pvcallss_lock);
+ return -EAGAIN;
+ }
+ req = RING_GET_REQUEST(&bedata->ring, req_id);
+ req->req_id = req_id;
+ req->cmd = PVCALLS_RELEASE;
+ req->u.release.id = (uint64_t)sock;
+
+ bedata->ring.req_prod_pvt++;
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
+ spin_unlock(&bedata->pvcallss_lock);
+ if (notify)
+ notify_remote_via_irq(bedata->irq);
+
+ wait_event(bedata->inflight_req,
+ READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+
+ if (map->active_socket) {
+ /*
+ * Set in_error and wake up inflight_conn_req to force
+ * recvmsg waiters to exit.
+ */
+ map->active.ring->in_error = -EBADF;
+ wake_up_interruptible(&map->active.inflight_conn_req);
+
+ mutex_lock(&map->active.in_mutex);
+ mutex_lock(&map->active.out_mutex);
+ pvcalls_front_free_map(bedata, map);
+ mutex_unlock(&map->active.out_mutex);
+ mutex_unlock(&map->active.in_mutex);
+ kfree(map);
+ } else {
+ spin_lock(&bedata->pvcallss_lock);
+ list_del_init(&map->list);
+ kfree(map);
+ spin_unlock(&bedata->pvcallss_lock);
+ }
+ WRITE_ONCE(bedata->rsp[req_id].req_id, PVCALLS_INVALID_ID);
+
+ return 0;
+}
+
static const struct xenbus_device_id pvcalls_front_ids[] = {
{ "pvcalls" },
{ "" }
diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h
index 25e05b8..3332978 100644
--- a/drivers/xen/pvcalls-front.h
+++ b/drivers/xen/pvcalls-front.h
@@ -23,5 +23,6 @@ int pvcalls_front_recvmsg(struct socket *sock,
unsigned int pvcalls_front_poll(struct file *file,
struct socket *sock,
poll_table *wait);
+int pvcalls_front_release(struct socket *sock);
#endif
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Juergen Gross <jgross@suse.com> |
|---|---|
| Date | 2017-07-24 22:20 +0200 |
| Subject | Re: [PATCH v1 11/13] xen/pvcalls: implement release command |
| Message-ID | <u6RZE-1pl-15@gated-at.bofh.it> |
| In reply to | #1694073 |
On 22/07/17 02:12, Stefano Stabellini wrote:
> Send PVCALLS_RELEASE to the backend and wait for a reply. Take both
> in_mutex and out_mutex to avoid concurrent accesses. Then, free the
> socket.
>
> Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
> CC: boris.ostrovsky@oracle.com
> CC: jgross@suse.com
> ---
> drivers/xen/pvcalls-front.c | 86 +++++++++++++++++++++++++++++++++++++++++++++
> drivers/xen/pvcalls-front.h | 1 +
> 2 files changed, 87 insertions(+)
>
> diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> index b6cfb7d..bd3dfac 100644
> --- a/drivers/xen/pvcalls-front.c
> +++ b/drivers/xen/pvcalls-front.c
> @@ -174,6 +174,24 @@ static irqreturn_t pvcalls_front_conn_handler(int irq, void *sock_map)
> return IRQ_HANDLED;
> }
>
> +static void pvcalls_front_free_map(struct pvcalls_bedata *bedata,
> + struct sock_mapping *map)
> +{
> + int i;
> +
> + spin_lock(&bedata->pvcallss_lock);
> + if (!list_empty(&map->list))
> + list_del_init(&map->list);
> + spin_unlock(&bedata->pvcallss_lock);
> +
> + /* what if the thread waiting still need access? */
Is this handled? If not, why is it no problem?
> + for (i = 0; i < (1 << map->active.ring->ring_order); i++)
> + gnttab_end_foreign_access(map->active.ring->ref[i], 0, 0);
> + gnttab_end_foreign_access(map->active.ref, 0, 0);
> + free_page((unsigned long)map->active.ring);
> + unbind_from_irqhandler(map->active.irq, map);
> +}
> +
> int pvcalls_front_socket(struct socket *sock)
> {
> struct pvcalls_bedata *bedata;
> @@ -805,6 +823,74 @@ unsigned int pvcalls_front_poll(struct file *file, struct socket *sock,
> return pvcalls_front_poll_passive(file, bedata, map, wait);
> }
>
> +int pvcalls_front_release(struct socket *sock)
> +{
> + struct pvcalls_bedata *bedata;
> + struct sock_mapping *map;
> + int req_id, notify;
> + struct xen_pvcalls_request *req;
> +
> + if (!pvcalls_front_dev)
> + return -EIO;
> + bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
> + if (!bedata)
> + return -EIO;
> +
> + if (sock->sk == NULL)
> + return 0;
> +
> + map = (struct sock_mapping *) READ_ONCE(sock->sk->sk_send_head);
> + if (map == NULL)
> + return 0;
> + WRITE_ONCE(sock->sk->sk_send_head, NULL);
> +
> + spin_lock(&bedata->pvcallss_lock);
> + req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
> + BUG_ON(req_id >= PVCALLS_NR_REQ_PER_RING);
> + if (RING_FULL(&bedata->ring) ||
> + READ_ONCE(bedata->rsp[req_id].req_id) != PVCALLS_INVALID_ID) {
> + spin_unlock(&bedata->pvcallss_lock);
> + return -EAGAIN;
Isn't it a problem you already cleared sock->sk->sk_send_head?
Juergen
> + }
> + req = RING_GET_REQUEST(&bedata->ring, req_id);
> + req->req_id = req_id;
> + req->cmd = PVCALLS_RELEASE;
> + req->u.release.id = (uint64_t)sock;
> +
> + bedata->ring.req_prod_pvt++;
> + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
> + spin_unlock(&bedata->pvcallss_lock);
> + if (notify)
> + notify_remote_via_irq(bedata->irq);
> +
> + wait_event(bedata->inflight_req,
> + READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
> +
> + if (map->active_socket) {
> + /*
> + * Set in_error and wake up inflight_conn_req to force
> + * recvmsg waiters to exit.
> + */
> + map->active.ring->in_error = -EBADF;
> + wake_up_interruptible(&map->active.inflight_conn_req);
> +
> + mutex_lock(&map->active.in_mutex);
> + mutex_lock(&map->active.out_mutex);
> + pvcalls_front_free_map(bedata, map);
> + mutex_unlock(&map->active.out_mutex);
> + mutex_unlock(&map->active.in_mutex);
> + kfree(map);
> + } else {
> + spin_lock(&bedata->pvcallss_lock);
> + list_del_init(&map->list);
> + kfree(map);
> + spin_unlock(&bedata->pvcallss_lock);
> + }
> + WRITE_ONCE(bedata->rsp[req_id].req_id, PVCALLS_INVALID_ID);
> +
> + return 0;
> +}
> +
> static const struct xenbus_device_id pvcalls_front_ids[] = {
> { "pvcalls" },
> { "" }
> diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h
> index 25e05b8..3332978 100644
> --- a/drivers/xen/pvcalls-front.h
> +++ b/drivers/xen/pvcalls-front.h
> @@ -23,5 +23,6 @@ int pvcalls_front_recvmsg(struct socket *sock,
> unsigned int pvcalls_front_poll(struct file *file,
> struct socket *sock,
> poll_table *wait);
> +int pvcalls_front_release(struct socket *sock);
>
> #endif
>
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-25 23:10 +0200 |
| Subject | Re: [PATCH v1 11/13] xen/pvcalls: implement release command |
| Message-ID | <u7ffB-82I-63@gated-at.bofh.it> |
| In reply to | #1695068 |
On Mon, 24 Jul 2017, Juergen Gross wrote:
> On 22/07/17 02:12, Stefano Stabellini wrote:
> > Send PVCALLS_RELEASE to the backend and wait for a reply. Take both
> > in_mutex and out_mutex to avoid concurrent accesses. Then, free the
> > socket.
> >
> > Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
> > CC: boris.ostrovsky@oracle.com
> > CC: jgross@suse.com
> > ---
> > drivers/xen/pvcalls-front.c | 86 +++++++++++++++++++++++++++++++++++++++++++++
> > drivers/xen/pvcalls-front.h | 1 +
> > 2 files changed, 87 insertions(+)
> >
> > diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> > index b6cfb7d..bd3dfac 100644
> > --- a/drivers/xen/pvcalls-front.c
> > +++ b/drivers/xen/pvcalls-front.c
> > @@ -174,6 +174,24 @@ static irqreturn_t pvcalls_front_conn_handler(int irq, void *sock_map)
> > return IRQ_HANDLED;
> > }
> >
> > +static void pvcalls_front_free_map(struct pvcalls_bedata *bedata,
> > + struct sock_mapping *map)
> > +{
> > + int i;
> > +
> > + spin_lock(&bedata->pvcallss_lock);
> > + if (!list_empty(&map->list))
> > + list_del_init(&map->list);
> > + spin_unlock(&bedata->pvcallss_lock);
> > +
> > + /* what if the thread waiting still need access? */
>
> Is this handled? If not, why is it no problem?
Yes, sorry. This is a left-over from earlier versions of the code.
This scenario is handled because threads waiting will have already been
awaken by the wake_up_interruptible call in pvcalls_front_release, and
also the code is protected by both the in_mutex and out_mutex. I hadn't
introduced in_mutex and out_mutex yet when I wrote this comment, it no
longer applies.
> > + for (i = 0; i < (1 << map->active.ring->ring_order); i++)
> > + gnttab_end_foreign_access(map->active.ring->ref[i], 0, 0);
> > + gnttab_end_foreign_access(map->active.ref, 0, 0);
> > + free_page((unsigned long)map->active.ring);
> > + unbind_from_irqhandler(map->active.irq, map);
> > +}
> > +
> > int pvcalls_front_socket(struct socket *sock)
> > {
> > struct pvcalls_bedata *bedata;
> > @@ -805,6 +823,74 @@ unsigned int pvcalls_front_poll(struct file *file, struct socket *sock,
> > return pvcalls_front_poll_passive(file, bedata, map, wait);
> > }
> >
> > +int pvcalls_front_release(struct socket *sock)
> > +{
> > + struct pvcalls_bedata *bedata;
> > + struct sock_mapping *map;
> > + int req_id, notify;
> > + struct xen_pvcalls_request *req;
> > +
> > + if (!pvcalls_front_dev)
> > + return -EIO;
> > + bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
> > + if (!bedata)
> > + return -EIO;
> > +
> > + if (sock->sk == NULL)
> > + return 0;
> > +
> > + map = (struct sock_mapping *) READ_ONCE(sock->sk->sk_send_head);
> > + if (map == NULL)
> > + return 0;
> > + WRITE_ONCE(sock->sk->sk_send_head, NULL);
> > +
> > + spin_lock(&bedata->pvcallss_lock);
> > + req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
> > + BUG_ON(req_id >= PVCALLS_NR_REQ_PER_RING);
> > + if (RING_FULL(&bedata->ring) ||
> > + READ_ONCE(bedata->rsp[req_id].req_id) != PVCALLS_INVALID_ID) {
> > + spin_unlock(&bedata->pvcallss_lock);
> > + return -EAGAIN;
>
> Isn't it a problem you already cleared sock->sk->sk_send_head?
Yes, you are right. It would effectively leak the socket. I'll move the
clearing of sk_send_head after this check.
> > + }
> > + req = RING_GET_REQUEST(&bedata->ring, req_id);
> > + req->req_id = req_id;
> > + req->cmd = PVCALLS_RELEASE;
> > + req->u.release.id = (uint64_t)sock;
> > +
> > + bedata->ring.req_prod_pvt++;
> > + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
> > + spin_unlock(&bedata->pvcallss_lock);
> > + if (notify)
> > + notify_remote_via_irq(bedata->irq);
> > +
> > + wait_event(bedata->inflight_req,
> > + READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
> > +
> > + if (map->active_socket) {
> > + /*
> > + * Set in_error and wake up inflight_conn_req to force
> > + * recvmsg waiters to exit.
> > + */
> > + map->active.ring->in_error = -EBADF;
> > + wake_up_interruptible(&map->active.inflight_conn_req);
> > +
> > + mutex_lock(&map->active.in_mutex);
> > + mutex_lock(&map->active.out_mutex);
> > + pvcalls_front_free_map(bedata, map);
> > + mutex_unlock(&map->active.out_mutex);
> > + mutex_unlock(&map->active.in_mutex);
> > + kfree(map);
> > + } else {
> > + spin_lock(&bedata->pvcallss_lock);
> > + list_del_init(&map->list);
> > + kfree(map);
> > + spin_unlock(&bedata->pvcallss_lock);
> > + }
> > + WRITE_ONCE(bedata->rsp[req_id].req_id, PVCALLS_INVALID_ID);
> > +
> > + return 0;
> > +}
> > +
> > static const struct xenbus_device_id pvcalls_front_ids[] = {
> > { "pvcalls" },
> > { "" }
> > diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h
> > index 25e05b8..3332978 100644
> > --- a/drivers/xen/pvcalls-front.h
> > +++ b/drivers/xen/pvcalls-front.h
> > @@ -23,5 +23,6 @@ int pvcalls_front_recvmsg(struct socket *sock,
> > unsigned int pvcalls_front_poll(struct file *file,
> > struct socket *sock,
> > poll_table *wait);
> > +int pvcalls_front_release(struct socket *sock);
> >
> > #endif
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-22 02:20 +0200 |
| Subject | [PATCH v1 01/13] xen/pvcalls: introduce the pvcalls xenbus frontend |
| Message-ID | <u5Qjf-3b8-5@gated-at.bofh.it> |
| In reply to | #1694071 |
Introduce a xenbus frontend for the pvcalls protocol, as defined by
https://xenbits.xen.org/docs/unstable/misc/pvcalls.html.
This patch only adds the stubs, the code will be added by the following
patches.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-front.c | 68 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 drivers/xen/pvcalls-front.c
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
new file mode 100644
index 0000000..173e204
--- /dev/null
+++ b/drivers/xen/pvcalls-front.c
@@ -0,0 +1,68 @@
+/*
+ * (c) 2017 Stefano Stabellini <stefano@aporeto.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include <xen/xen.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/pvcalls.h>
+
+static const struct xenbus_device_id pvcalls_front_ids[] = {
+ { "pvcalls" },
+ { "" }
+};
+
+static int pvcalls_front_remove(struct xenbus_device *dev)
+{
+ return 0;
+}
+
+static int pvcalls_front_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ return 0;
+}
+
+static int pvcalls_front_resume(struct xenbus_device *dev)
+{
+ dev_warn(&dev->dev, "suspsend/resume unsupported\n");
+ return 0;
+}
+
+static void pvcalls_front_changed(struct xenbus_device *dev,
+ enum xenbus_state backend_state)
+{
+}
+
+static struct xenbus_driver pvcalls_front_driver = {
+ .ids = pvcalls_front_ids,
+ .probe = pvcalls_front_probe,
+ .remove = pvcalls_front_remove,
+ .resume = pvcalls_front_resume,
+ .otherend_changed = pvcalls_front_changed,
+};
+
+static int __init pvcalls_frontend_init(void)
+{
+ if (!xen_domain())
+ return -ENODEV;
+
+ pr_info("Initialising Xen pvcalls frontend driver\n");
+
+ return xenbus_register_frontend(&pvcalls_front_driver);
+}
+
+module_init(pvcalls_frontend_init);
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-22 02:20 +0200 |
| Subject | [PATCH v1 09/13] xen/pvcalls: implement recvmsg |
| Message-ID | <u5Qjh-3b8-27@gated-at.bofh.it> |
| In reply to | #1694074 |
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 not enough 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 | 106 ++++++++++++++++++++++++++++++++++++++++++++
drivers/xen/pvcalls-front.h | 4 ++
2 files changed, 110 insertions(+)
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index bf29f40..3d1041a 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -94,6 +94,20 @@ static int pvcalls_front_write_todo(struct sock_mapping *map)
return size - pvcalls_queued(prod, cons, size);
}
+static int 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;
@@ -413,6 +427,98 @@ 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;
+ int count = 0;
+
+ 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)) {
+ if (count < PVCALLS_FRON_MAX_SPIN)
+ count++;
+ else
+ 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
[toc] | [prev] | [next] | [standalone]
| From | Juergen Gross <jgross@suse.com> |
|---|---|
| Date | 2017-07-24 22:00 +0200 |
| Subject | Re: [PATCH v1 09/13] xen/pvcalls: implement recvmsg |
| Message-ID | <u6RGh-12s-5@gated-at.bofh.it> |
| In reply to | #1694075 |
On 22/07/17 02:11, Stefano Stabellini wrote:
> 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 not enough 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 | 106 ++++++++++++++++++++++++++++++++++++++++++++
> drivers/xen/pvcalls-front.h | 4 ++
> 2 files changed, 110 insertions(+)
>
> diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> index bf29f40..3d1041a 100644
> --- a/drivers/xen/pvcalls-front.c
> +++ b/drivers/xen/pvcalls-front.c
> @@ -94,6 +94,20 @@ static int pvcalls_front_write_todo(struct sock_mapping *map)
> return size - pvcalls_queued(prod, cons, size);
> }
>
> +static int pvcalls_front_read_todo(struct sock_mapping *map)
Return type bool?
Juergen
> +{
> + 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;
> @@ -413,6 +427,98 @@ 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;
> + int count = 0;
> +
> + 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)) {
> + if (count < PVCALLS_FRON_MAX_SPIN)
> + count++;
> + else
> + 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
>
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-25 00:40 +0200 |
| Subject | Re: [PATCH v1 09/13] xen/pvcalls: implement recvmsg |
| Message-ID | <u6Ub7-2PW-11@gated-at.bofh.it> |
| In reply to | #1695048 |
On Mon, 24 Jul 2017, Juergen Gross wrote:
> On 22/07/17 02:11, Stefano Stabellini wrote:
> > 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 not enough 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 | 106 ++++++++++++++++++++++++++++++++++++++++++++
> > drivers/xen/pvcalls-front.h | 4 ++
> > 2 files changed, 110 insertions(+)
> >
> > diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> > index bf29f40..3d1041a 100644
> > --- a/drivers/xen/pvcalls-front.c
> > +++ b/drivers/xen/pvcalls-front.c
> > @@ -94,6 +94,20 @@ static int pvcalls_front_write_todo(struct sock_mapping *map)
> > return size - pvcalls_queued(prod, cons, size);
> > }
> >
> > +static int pvcalls_front_read_todo(struct sock_mapping *map)
>
> Return type bool?
Yes, good idea
> > +{
> > + 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;
> > @@ -413,6 +427,98 @@ 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;
> > + int count = 0;
> > +
> > + 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)) {
> > + if (count < PVCALLS_FRON_MAX_SPIN)
> > + count++;
> > + else
> > + 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
> >
>
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-22 02:20 +0200 |
| Subject | [PATCH v1 07/13] xen/pvcalls: implement accept command |
| Message-ID | <u5Qjh-3b8-29@gated-at.bofh.it> |
| In reply to | #1694074 |
Send PVCALLS_ACCEPT to the backend. Allocate a new active socket. Make
sure that only one accept command is executed at any given time by
setting PVCALLS_FLAG_ACCEPT_INFLIGHT and waiting on the
inflight_accept_req waitqueue.
sock->sk->sk_send_head is not used for ip sockets: reuse the field to
store a pointer to the struct sock_mapping corresponding to the socket.
Convert the new struct socket pointer into an uint64_t and use it as id
for the new socket to pass to the backend.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-front.c | 79 +++++++++++++++++++++++++++++++++++++++++++++
drivers/xen/pvcalls-front.h | 3 ++
2 files changed, 82 insertions(+)
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index 80fd5fb..f3a04a2 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -410,6 +410,85 @@ int pvcalls_front_listen(struct socket *sock, int backlog)
return ret;
}
+int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+ struct pvcalls_bedata *bedata;
+ struct sock_mapping *map;
+ struct sock_mapping *map2 = NULL;
+ struct xen_pvcalls_request *req;
+ int notify, req_id, ret, evtchn;
+
+ 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 (map->passive.status != PVCALLS_STATUS_LISTEN)
+ return -EINVAL;
+
+ /*
+ * Backend only supports 1 inflight accept request, will return
+ * errors for the others
+ */
+ if (test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
+ (void *)&map->passive.flags)) {
+ if (wait_event_interruptible(map->passive.inflight_accept_req,
+ !test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
+ (void *)&map->passive.flags))
+ != 0)
+ return -EINTR;
+ }
+
+
+ newsock->sk = kzalloc(sizeof(*newsock->sk), GFP_KERNEL);
+ if (newsock->sk == NULL)
+ return -ENOMEM;
+
+ spin_lock(&bedata->pvcallss_lock);
+ req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
+ BUG_ON(req_id >= PVCALLS_NR_REQ_PER_RING);
+ if (RING_FULL(&bedata->ring) ||
+ READ_ONCE(bedata->rsp[req_id].req_id) != PVCALLS_INVALID_ID) {
+ spin_unlock(&bedata->pvcallss_lock);
+ return -EAGAIN;
+ }
+
+ map2 = create_active(&evtchn);
+
+ req = RING_GET_REQUEST(&bedata->ring, req_id);
+ req->req_id = req_id;
+ req->cmd = PVCALLS_ACCEPT;
+ req->u.accept.id = (uint64_t) sock;
+ req->u.accept.ref = map2->active.ref;
+ req->u.accept.id_new = (uint64_t) newsock;
+ req->u.accept.evtchn = evtchn;
+
+ list_add_tail(&map2->list, &bedata->socket_mappings);
+ WRITE_ONCE(newsock->sk->sk_send_head, (void *)map2);
+ map2->sock = newsock;
+
+ bedata->ring.req_prod_pvt++;
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
+ spin_unlock(&bedata->pvcallss_lock);
+ if (notify)
+ notify_remote_via_irq(bedata->irq);
+
+ wait_event(bedata->inflight_req,
+ READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+
+ clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags);
+ wake_up(&map->passive.inflight_accept_req);
+
+ ret = bedata->rsp[req_id].ret;
+ /* read ret, then set this rsp slot to be reused */
+ smp_mb();
+ WRITE_ONCE(bedata->rsp[req_id].req_id, PVCALLS_INVALID_ID);
+ return ret;
+}
+
static const struct xenbus_device_id pvcalls_front_ids[] = {
{ "pvcalls" },
{ "" }
diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h
index aa8fe10..ab4f1da 100644
--- a/drivers/xen/pvcalls-front.h
+++ b/drivers/xen/pvcalls-front.h
@@ -10,5 +10,8 @@ int pvcalls_front_bind(struct socket *sock,
struct sockaddr *addr,
int addr_len);
int pvcalls_front_listen(struct socket *sock, int backlog);
+int pvcalls_front_accept(struct socket *sock,
+ struct socket *newsock,
+ int flags);
#endif
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Juergen Gross <jgross@suse.com> |
|---|---|
| Date | 2017-07-24 21:50 +0200 |
| Subject | Re: [PATCH v1 07/13] xen/pvcalls: implement accept command |
| Message-ID | <u6RwD-Yz-25@gated-at.bofh.it> |
| In reply to | #1694076 |
On 22/07/17 02:11, Stefano Stabellini wrote:
> Send PVCALLS_ACCEPT to the backend. Allocate a new active socket. Make
> sure that only one accept command is executed at any given time by
> setting PVCALLS_FLAG_ACCEPT_INFLIGHT and waiting on the
> inflight_accept_req waitqueue.
>
> sock->sk->sk_send_head is not used for ip sockets: reuse the field to
> store a pointer to the struct sock_mapping corresponding to the socket.
>
> Convert the new struct socket pointer into an uint64_t and use it as id
> for the new socket to pass to the backend.
>
> Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
> CC: boris.ostrovsky@oracle.com
> CC: jgross@suse.com
> ---
> drivers/xen/pvcalls-front.c | 79 +++++++++++++++++++++++++++++++++++++++++++++
> drivers/xen/pvcalls-front.h | 3 ++
> 2 files changed, 82 insertions(+)
>
> diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> index 80fd5fb..f3a04a2 100644
> --- a/drivers/xen/pvcalls-front.c
> +++ b/drivers/xen/pvcalls-front.c
> @@ -410,6 +410,85 @@ int pvcalls_front_listen(struct socket *sock, int backlog)
> return ret;
> }
>
> +int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
> +{
> + struct pvcalls_bedata *bedata;
> + struct sock_mapping *map;
> + struct sock_mapping *map2 = NULL;
> + struct xen_pvcalls_request *req;
> + int notify, req_id, ret, evtchn;
> +
> + 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 (map->passive.status != PVCALLS_STATUS_LISTEN)
> + return -EINVAL;
> +
> + /*
> + * Backend only supports 1 inflight accept request, will return
> + * errors for the others
> + */
> + if (test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
> + (void *)&map->passive.flags)) {
> + if (wait_event_interruptible(map->passive.inflight_accept_req,
> + !test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
> + (void *)&map->passive.flags))
> + != 0)
> + return -EINTR;
> + }
> +
> +
> + newsock->sk = kzalloc(sizeof(*newsock->sk), GFP_KERNEL);
> + if (newsock->sk == NULL)
> + return -ENOMEM;
> +
> + spin_lock(&bedata->pvcallss_lock);
> + req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
> + BUG_ON(req_id >= PVCALLS_NR_REQ_PER_RING);
BUG_ON()?
> + if (RING_FULL(&bedata->ring) ||
> + READ_ONCE(bedata->rsp[req_id].req_id) != PVCALLS_INVALID_ID) {
> + spin_unlock(&bedata->pvcallss_lock);
> + return -EAGAIN;
Leaking newsock->sk?
Juergen
> + }
> +
> + map2 = create_active(&evtchn);
> +
> + req = RING_GET_REQUEST(&bedata->ring, req_id);
> + req->req_id = req_id;
> + req->cmd = PVCALLS_ACCEPT;
> + req->u.accept.id = (uint64_t) sock;
> + req->u.accept.ref = map2->active.ref;
> + req->u.accept.id_new = (uint64_t) newsock;
> + req->u.accept.evtchn = evtchn;
> +
> + list_add_tail(&map2->list, &bedata->socket_mappings);
> + WRITE_ONCE(newsock->sk->sk_send_head, (void *)map2);
> + map2->sock = newsock;
> +
> + bedata->ring.req_prod_pvt++;
> + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
> + spin_unlock(&bedata->pvcallss_lock);
> + if (notify)
> + notify_remote_via_irq(bedata->irq);
> +
> + wait_event(bedata->inflight_req,
> + READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
> +
> + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags);
> + wake_up(&map->passive.inflight_accept_req);
> +
> + ret = bedata->rsp[req_id].ret;
> + /* read ret, then set this rsp slot to be reused */
> + smp_mb();
> + WRITE_ONCE(bedata->rsp[req_id].req_id, PVCALLS_INVALID_ID);
> + return ret;
> +}
> +
> static const struct xenbus_device_id pvcalls_front_ids[] = {
> { "pvcalls" },
> { "" }
> diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h
> index aa8fe10..ab4f1da 100644
> --- a/drivers/xen/pvcalls-front.h
> +++ b/drivers/xen/pvcalls-front.h
> @@ -10,5 +10,8 @@ int pvcalls_front_bind(struct socket *sock,
> struct sockaddr *addr,
> int addr_len);
> int pvcalls_front_listen(struct socket *sock, int backlog);
> +int pvcalls_front_accept(struct socket *sock,
> + struct socket *newsock,
> + int flags);
>
> #endif
>
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-25 01:00 +0200 |
| Subject | Re: [PATCH v1 07/13] xen/pvcalls: implement accept command |
| Message-ID | <u6Uut-2Z5-17@gated-at.bofh.it> |
| In reply to | #1695046 |
On Mon, 24 Jul 2017, Juergen Gross wrote:
> On 22/07/17 02:11, Stefano Stabellini wrote:
> > Send PVCALLS_ACCEPT to the backend. Allocate a new active socket. Make
> > sure that only one accept command is executed at any given time by
> > setting PVCALLS_FLAG_ACCEPT_INFLIGHT and waiting on the
> > inflight_accept_req waitqueue.
> >
> > sock->sk->sk_send_head is not used for ip sockets: reuse the field to
> > store a pointer to the struct sock_mapping corresponding to the socket.
> >
> > Convert the new struct socket pointer into an uint64_t and use it as id
> > for the new socket to pass to the backend.
> >
> > Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
> > CC: boris.ostrovsky@oracle.com
> > CC: jgross@suse.com
> > ---
> > drivers/xen/pvcalls-front.c | 79 +++++++++++++++++++++++++++++++++++++++++++++
> > drivers/xen/pvcalls-front.h | 3 ++
> > 2 files changed, 82 insertions(+)
> >
> > diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> > index 80fd5fb..f3a04a2 100644
> > --- a/drivers/xen/pvcalls-front.c
> > +++ b/drivers/xen/pvcalls-front.c
> > @@ -410,6 +410,85 @@ int pvcalls_front_listen(struct socket *sock, int backlog)
> > return ret;
> > }
> >
> > +int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
> > +{
> > + struct pvcalls_bedata *bedata;
> > + struct sock_mapping *map;
> > + struct sock_mapping *map2 = NULL;
> > + struct xen_pvcalls_request *req;
> > + int notify, req_id, ret, evtchn;
> > +
> > + 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 (map->passive.status != PVCALLS_STATUS_LISTEN)
> > + return -EINVAL;
> > +
> > + /*
> > + * Backend only supports 1 inflight accept request, will return
> > + * errors for the others
> > + */
> > + if (test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
> > + (void *)&map->passive.flags)) {
> > + if (wait_event_interruptible(map->passive.inflight_accept_req,
> > + !test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
> > + (void *)&map->passive.flags))
> > + != 0)
> > + return -EINTR;
> > + }
> > +
> > +
> > + newsock->sk = kzalloc(sizeof(*newsock->sk), GFP_KERNEL);
> > + if (newsock->sk == NULL)
> > + return -ENOMEM;
> > +
> > + spin_lock(&bedata->pvcallss_lock);
> > + req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
> > + BUG_ON(req_id >= PVCALLS_NR_REQ_PER_RING);
>
> BUG_ON()?
>
> > + if (RING_FULL(&bedata->ring) ||
> > + READ_ONCE(bedata->rsp[req_id].req_id) != PVCALLS_INVALID_ID) {
> > + spin_unlock(&bedata->pvcallss_lock);
> > + return -EAGAIN;
>
> Leaking newsock->sk?
I'll fix
> > + }
> > +
> > + map2 = create_active(&evtchn);
> > +
> > + req = RING_GET_REQUEST(&bedata->ring, req_id);
> > + req->req_id = req_id;
> > + req->cmd = PVCALLS_ACCEPT;
> > + req->u.accept.id = (uint64_t) sock;
> > + req->u.accept.ref = map2->active.ref;
> > + req->u.accept.id_new = (uint64_t) newsock;
> > + req->u.accept.evtchn = evtchn;
> > +
> > + list_add_tail(&map2->list, &bedata->socket_mappings);
> > + WRITE_ONCE(newsock->sk->sk_send_head, (void *)map2);
> > + map2->sock = newsock;
> > +
> > + bedata->ring.req_prod_pvt++;
> > + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
> > + spin_unlock(&bedata->pvcallss_lock);
> > + if (notify)
> > + notify_remote_via_irq(bedata->irq);
> > +
> > + wait_event(bedata->inflight_req,
> > + READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
> > +
> > + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags);
> > + wake_up(&map->passive.inflight_accept_req);
> > +
> > + ret = bedata->rsp[req_id].ret;
> > + /* read ret, then set this rsp slot to be reused */
> > + smp_mb();
> > + WRITE_ONCE(bedata->rsp[req_id].req_id, PVCALLS_INVALID_ID);
> > + return ret;
> > +}
> > +
> > static const struct xenbus_device_id pvcalls_front_ids[] = {
> > { "pvcalls" },
> > { "" }
> > diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h
> > index aa8fe10..ab4f1da 100644
> > --- a/drivers/xen/pvcalls-front.h
> > +++ b/drivers/xen/pvcalls-front.h
> > @@ -10,5 +10,8 @@ int pvcalls_front_bind(struct socket *sock,
> > struct sockaddr *addr,
> > int addr_len);
> > int pvcalls_front_listen(struct socket *sock, int backlog);
> > +int pvcalls_front_accept(struct socket *sock,
> > + struct socket *newsock,
> > + int flags);
> >
> > #endif
> >
>
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-22 02:20 +0200 |
| Subject | [PATCH v1 08/13] xen/pvcalls: implement sendmsg |
| Message-ID | <u5Qjh-3b8-31@gated-at.bofh.it> |
| In reply to | #1694074 |
Send data to an active socket by copying data to the "out" ring. Take
the active socket out_mutex so that only one function can access the
ring at any given time.
If not enough room 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 significantly.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-front.c | 109 ++++++++++++++++++++++++++++++++++++++++++++
drivers/xen/pvcalls-front.h | 3 ++
2 files changed, 112 insertions(+)
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index f3a04a2..bf29f40 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -27,6 +27,7 @@
#define PVCALLS_INVALID_ID (UINT_MAX)
#define RING_ORDER XENBUS_MAX_RING_GRANT_ORDER
#define PVCALLS_NR_REQ_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE)
+#define PVCALLS_FRON_MAX_SPIN 5000
struct pvcalls_bedata {
struct xen_pvcalls_front_ring ring;
@@ -77,6 +78,22 @@ struct sock_mapping {
};
};
+static int pvcalls_front_write_todo(struct sock_mapping *map)
+{
+ struct pvcalls_data_intf *intf = map->active.ring;
+ RING_IDX cons, prod, size = XEN_FLEX_RING_SIZE(intf->ring_order);
+ int32_t error;
+
+ cons = intf->out_cons;
+ prod = intf->out_prod;
+ error = intf->out_error;
+ if (error == -ENOTCONN)
+ return 0;
+ if (error != 0)
+ return error;
+ return size - pvcalls_queued(prod, cons, size);
+}
+
static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
{
struct xenbus_device *dev = dev_id;
@@ -304,6 +321,98 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
return ret;
}
+static int __write_ring(struct pvcalls_data_intf *intf,
+ struct pvcalls_data *data,
+ struct iov_iter *msg_iter,
+ size_t len)
+{
+ 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->out_cons;
+ prod = intf->out_prod;
+ error = intf->out_error;
+ /* read indexes before continuing */
+ virt_mb();
+
+ if (error < 0)
+ return error;
+
+ size = pvcalls_queued(prod, cons, array_size);
+ if (size >= array_size)
+ return 0;
+ if (len > array_size - size)
+ len = array_size - size;
+
+ masked_prod = pvcalls_mask(prod, array_size);
+ masked_cons = pvcalls_mask(cons, array_size);
+
+ if (masked_prod < masked_cons) {
+ copy_from_iter(data->out + masked_prod, len, msg_iter);
+ } else {
+ if (len > array_size - masked_prod) {
+ copy_from_iter(data->out + masked_prod,
+ array_size - masked_prod, msg_iter);
+ copy_from_iter(data->out,
+ len - (array_size - masked_prod),
+ msg_iter);
+ } else {
+ copy_from_iter(data->out + masked_prod, len, msg_iter);
+ }
+ }
+ /* write to ring before updating pointer */
+ virt_wmb();
+ intf->out_prod += len;
+
+ return len;
+}
+
+int pvcalls_front_sendmsg(struct socket *sock, struct msghdr *msg,
+ size_t len)
+{
+ struct pvcalls_bedata *bedata;
+ struct sock_mapping *map;
+ int sent = 0, tot_sent = 0;
+ int count = 0, flags;
+
+ 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;
+
+ flags = msg->msg_flags;
+ if (flags & (MSG_CONFIRM|MSG_DONTROUTE|MSG_EOR|MSG_OOB))
+ return -EOPNOTSUPP;
+
+ mutex_lock(&map->active.out_mutex);
+ if ((flags & MSG_DONTWAIT) && !pvcalls_front_write_todo(map)) {
+ mutex_unlock(&map->active.out_mutex);
+ return -EAGAIN;
+ }
+
+again:
+ count++;
+ sent = __write_ring(map->active.ring,
+ &map->active.data, &msg->msg_iter,
+ len);
+ if (sent > 0) {
+ len -= sent;
+ tot_sent += sent;
+ notify_remote_via_irq(map->active.irq);
+ }
+ if (sent >= 0 && len > 0 && count < PVCALLS_FRON_MAX_SPIN)
+ goto again;
+ if (sent < 0)
+ tot_sent = sent;
+
+ mutex_unlock(&map->active.out_mutex);
+ return tot_sent;
+}
+
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 ab4f1da..d937c24 100644
--- a/drivers/xen/pvcalls-front.h
+++ b/drivers/xen/pvcalls-front.h
@@ -13,5 +13,8 @@ int pvcalls_front_bind(struct socket *sock,
int pvcalls_front_accept(struct socket *sock,
struct socket *newsock,
int flags);
+int pvcalls_front_sendmsg(struct socket *sock,
+ struct msghdr *msg,
+ size_t len);
#endif
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Juergen Gross <jgross@suse.com> |
|---|---|
| Date | 2017-07-24 22:00 +0200 |
| Subject | Re: [PATCH v1 08/13] xen/pvcalls: implement sendmsg |
| Message-ID | <u6RGh-12s-3@gated-at.bofh.it> |
| In reply to | #1694077 |
On 22/07/17 02:11, Stefano Stabellini wrote:
> Send data to an active socket by copying data to the "out" ring. Take
> the active socket out_mutex so that only one function can access the
> ring at any given time.
>
> If not enough room 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 significantly.
>
> Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
> CC: boris.ostrovsky@oracle.com
> CC: jgross@suse.com
> ---
> drivers/xen/pvcalls-front.c | 109 ++++++++++++++++++++++++++++++++++++++++++++
> drivers/xen/pvcalls-front.h | 3 ++
> 2 files changed, 112 insertions(+)
>
> diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> index f3a04a2..bf29f40 100644
> --- a/drivers/xen/pvcalls-front.c
> +++ b/drivers/xen/pvcalls-front.c
> @@ -27,6 +27,7 @@
> #define PVCALLS_INVALID_ID (UINT_MAX)
> #define RING_ORDER XENBUS_MAX_RING_GRANT_ORDER
> #define PVCALLS_NR_REQ_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE)
> +#define PVCALLS_FRON_MAX_SPIN 5000
Any reason not to name it PVCALLS_FRONT_MAX_SPIN? I first thought you
meant FROM instead.
Juergen
>
> struct pvcalls_bedata {
> struct xen_pvcalls_front_ring ring;
> @@ -77,6 +78,22 @@ struct sock_mapping {
> };
> };
>
> +static int pvcalls_front_write_todo(struct sock_mapping *map)
> +{
> + struct pvcalls_data_intf *intf = map->active.ring;
> + RING_IDX cons, prod, size = XEN_FLEX_RING_SIZE(intf->ring_order);
> + int32_t error;
> +
> + cons = intf->out_cons;
> + prod = intf->out_prod;
> + error = intf->out_error;
> + if (error == -ENOTCONN)
> + return 0;
> + if (error != 0)
> + return error;
> + return size - pvcalls_queued(prod, cons, size);
> +}
> +
> static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
> {
> struct xenbus_device *dev = dev_id;
> @@ -304,6 +321,98 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
> return ret;
> }
>
> +static int __write_ring(struct pvcalls_data_intf *intf,
> + struct pvcalls_data *data,
> + struct iov_iter *msg_iter,
> + size_t len)
> +{
> + 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->out_cons;
> + prod = intf->out_prod;
> + error = intf->out_error;
> + /* read indexes before continuing */
> + virt_mb();
> +
> + if (error < 0)
> + return error;
> +
> + size = pvcalls_queued(prod, cons, array_size);
> + if (size >= array_size)
> + return 0;
> + if (len > array_size - size)
> + len = array_size - size;
> +
> + masked_prod = pvcalls_mask(prod, array_size);
> + masked_cons = pvcalls_mask(cons, array_size);
> +
> + if (masked_prod < masked_cons) {
> + copy_from_iter(data->out + masked_prod, len, msg_iter);
> + } else {
> + if (len > array_size - masked_prod) {
> + copy_from_iter(data->out + masked_prod,
> + array_size - masked_prod, msg_iter);
> + copy_from_iter(data->out,
> + len - (array_size - masked_prod),
> + msg_iter);
> + } else {
> + copy_from_iter(data->out + masked_prod, len, msg_iter);
> + }
> + }
> + /* write to ring before updating pointer */
> + virt_wmb();
> + intf->out_prod += len;
> +
> + return len;
> +}
> +
> +int pvcalls_front_sendmsg(struct socket *sock, struct msghdr *msg,
> + size_t len)
> +{
> + struct pvcalls_bedata *bedata;
> + struct sock_mapping *map;
> + int sent = 0, tot_sent = 0;
> + int count = 0, flags;
> +
> + 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;
> +
> + flags = msg->msg_flags;
> + if (flags & (MSG_CONFIRM|MSG_DONTROUTE|MSG_EOR|MSG_OOB))
> + return -EOPNOTSUPP;
> +
> + mutex_lock(&map->active.out_mutex);
> + if ((flags & MSG_DONTWAIT) && !pvcalls_front_write_todo(map)) {
> + mutex_unlock(&map->active.out_mutex);
> + return -EAGAIN;
> + }
> +
> +again:
> + count++;
> + sent = __write_ring(map->active.ring,
> + &map->active.data, &msg->msg_iter,
> + len);
> + if (sent > 0) {
> + len -= sent;
> + tot_sent += sent;
> + notify_remote_via_irq(map->active.irq);
> + }
> + if (sent >= 0 && len > 0 && count < PVCALLS_FRON_MAX_SPIN)
> + goto again;
> + if (sent < 0)
> + tot_sent = sent;
> +
> + mutex_unlock(&map->active.out_mutex);
> + return tot_sent;
> +}
> +
> 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 ab4f1da..d937c24 100644
> --- a/drivers/xen/pvcalls-front.h
> +++ b/drivers/xen/pvcalls-front.h
> @@ -13,5 +13,8 @@ int pvcalls_front_bind(struct socket *sock,
> int pvcalls_front_accept(struct socket *sock,
> struct socket *newsock,
> int flags);
> +int pvcalls_front_sendmsg(struct socket *sock,
> + struct msghdr *msg,
> + size_t len);
>
> #endif
>
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-25 00:40 +0200 |
| Subject | Re: [PATCH v1 08/13] xen/pvcalls: implement sendmsg |
| Message-ID | <u6Ub8-2PW-17@gated-at.bofh.it> |
| In reply to | #1695047 |
On Mon, 24 Jul 2017, Juergen Gross wrote:
> On 22/07/17 02:11, Stefano Stabellini wrote:
> > Send data to an active socket by copying data to the "out" ring. Take
> > the active socket out_mutex so that only one function can access the
> > ring at any given time.
> >
> > If not enough room 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 significantly.
> >
> > Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
> > CC: boris.ostrovsky@oracle.com
> > CC: jgross@suse.com
> > ---
> > drivers/xen/pvcalls-front.c | 109 ++++++++++++++++++++++++++++++++++++++++++++
> > drivers/xen/pvcalls-front.h | 3 ++
> > 2 files changed, 112 insertions(+)
> >
> > diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> > index f3a04a2..bf29f40 100644
> > --- a/drivers/xen/pvcalls-front.c
> > +++ b/drivers/xen/pvcalls-front.c
> > @@ -27,6 +27,7 @@
> > #define PVCALLS_INVALID_ID (UINT_MAX)
> > #define RING_ORDER XENBUS_MAX_RING_GRANT_ORDER
> > #define PVCALLS_NR_REQ_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE)
> > +#define PVCALLS_FRON_MAX_SPIN 5000
>
> Any reason not to name it PVCALLS_FRONT_MAX_SPIN? I first thought you
> meant FROM instead.
Clearly a typo :-) I'll fix it.
>
> >
> > struct pvcalls_bedata {
> > struct xen_pvcalls_front_ring ring;
> > @@ -77,6 +78,22 @@ struct sock_mapping {
> > };
> > };
> >
> > +static int pvcalls_front_write_todo(struct sock_mapping *map)
> > +{
> > + struct pvcalls_data_intf *intf = map->active.ring;
> > + RING_IDX cons, prod, size = XEN_FLEX_RING_SIZE(intf->ring_order);
> > + int32_t error;
> > +
> > + cons = intf->out_cons;
> > + prod = intf->out_prod;
> > + error = intf->out_error;
> > + if (error == -ENOTCONN)
> > + return 0;
> > + if (error != 0)
> > + return error;
> > + return size - pvcalls_queued(prod, cons, size);
> > +}
> > +
> > static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
> > {
> > struct xenbus_device *dev = dev_id;
> > @@ -304,6 +321,98 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
> > return ret;
> > }
> >
> > +static int __write_ring(struct pvcalls_data_intf *intf,
> > + struct pvcalls_data *data,
> > + struct iov_iter *msg_iter,
> > + size_t len)
> > +{
> > + 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->out_cons;
> > + prod = intf->out_prod;
> > + error = intf->out_error;
> > + /* read indexes before continuing */
> > + virt_mb();
> > +
> > + if (error < 0)
> > + return error;
> > +
> > + size = pvcalls_queued(prod, cons, array_size);
> > + if (size >= array_size)
> > + return 0;
> > + if (len > array_size - size)
> > + len = array_size - size;
> > +
> > + masked_prod = pvcalls_mask(prod, array_size);
> > + masked_cons = pvcalls_mask(cons, array_size);
> > +
> > + if (masked_prod < masked_cons) {
> > + copy_from_iter(data->out + masked_prod, len, msg_iter);
> > + } else {
> > + if (len > array_size - masked_prod) {
> > + copy_from_iter(data->out + masked_prod,
> > + array_size - masked_prod, msg_iter);
> > + copy_from_iter(data->out,
> > + len - (array_size - masked_prod),
> > + msg_iter);
> > + } else {
> > + copy_from_iter(data->out + masked_prod, len, msg_iter);
> > + }
> > + }
> > + /* write to ring before updating pointer */
> > + virt_wmb();
> > + intf->out_prod += len;
> > +
> > + return len;
> > +}
> > +
> > +int pvcalls_front_sendmsg(struct socket *sock, struct msghdr *msg,
> > + size_t len)
> > +{
> > + struct pvcalls_bedata *bedata;
> > + struct sock_mapping *map;
> > + int sent = 0, tot_sent = 0;
> > + int count = 0, flags;
> > +
> > + 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;
> > +
> > + flags = msg->msg_flags;
> > + if (flags & (MSG_CONFIRM|MSG_DONTROUTE|MSG_EOR|MSG_OOB))
> > + return -EOPNOTSUPP;
> > +
> > + mutex_lock(&map->active.out_mutex);
> > + if ((flags & MSG_DONTWAIT) && !pvcalls_front_write_todo(map)) {
> > + mutex_unlock(&map->active.out_mutex);
> > + return -EAGAIN;
> > + }
> > +
> > +again:
> > + count++;
> > + sent = __write_ring(map->active.ring,
> > + &map->active.data, &msg->msg_iter,
> > + len);
> > + if (sent > 0) {
> > + len -= sent;
> > + tot_sent += sent;
> > + notify_remote_via_irq(map->active.irq);
> > + }
> > + if (sent >= 0 && len > 0 && count < PVCALLS_FRON_MAX_SPIN)
> > + goto again;
> > + if (sent < 0)
> > + tot_sent = sent;
> > +
> > + mutex_unlock(&map->active.out_mutex);
> > + return tot_sent;
> > +}
> > +
> > 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 ab4f1da..d937c24 100644
> > --- a/drivers/xen/pvcalls-front.h
> > +++ b/drivers/xen/pvcalls-front.h
> > @@ -13,5 +13,8 @@ int pvcalls_front_bind(struct socket *sock,
> > int pvcalls_front_accept(struct socket *sock,
> > struct socket *newsock,
> > int flags);
> > +int pvcalls_front_sendmsg(struct socket *sock,
> > + struct msghdr *msg,
> > + size_t len);
> >
> > #endif
> >
>
[toc] | [prev] | [next] | [standalone]
| From | Juergen Gross <jgross@suse.com> |
|---|---|
| Date | 2017-07-24 21:10 +0200 |
| Subject | Re: [PATCH v1 01/13] xen/pvcalls: introduce the pvcalls xenbus frontend |
| Message-ID | <u6QTT-GA-11@gated-at.bofh.it> |
| In reply to | #1694074 |
On 22/07/17 02:11, Stefano Stabellini wrote:
> Introduce a xenbus frontend for the pvcalls protocol, as defined by
> https://xenbits.xen.org/docs/unstable/misc/pvcalls.html.
>
> This patch only adds the stubs, the code will be added by the following
> patches.
>
> Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
> CC: boris.ostrovsky@oracle.com
> CC: jgross@suse.com
> ---
> drivers/xen/pvcalls-front.c | 68 +++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 68 insertions(+)
> create mode 100644 drivers/xen/pvcalls-front.c
>
> diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> new file mode 100644
> index 0000000..173e204
> --- /dev/null
> +++ b/drivers/xen/pvcalls-front.c
> @@ -0,0 +1,68 @@
> +/*
> + * (c) 2017 Stefano Stabellini <stefano@aporeto.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +
> +#include <xen/events.h>
> +#include <xen/grant_table.h>
> +#include <xen/xen.h>
> +#include <xen/xenbus.h>
> +#include <xen/interface/io/pvcalls.h>
> +
> +static const struct xenbus_device_id pvcalls_front_ids[] = {
> + { "pvcalls" },
> + { "" }
> +};
> +
> +static int pvcalls_front_remove(struct xenbus_device *dev)
> +{
> + return 0;
> +}
> +
> +static int pvcalls_front_probe(struct xenbus_device *dev,
> + const struct xenbus_device_id *id)
> +{
> + return 0;
> +}
> +
> +static int pvcalls_front_resume(struct xenbus_device *dev)
> +{
> + dev_warn(&dev->dev, "suspsend/resume unsupported\n");
> + return 0;
> +}
Why are you adding a resume function doing nothing but issuing a
message? Just omit it.
Juergen
> +
> +static void pvcalls_front_changed(struct xenbus_device *dev,
> + enum xenbus_state backend_state)
> +{
> +}
> +
> +static struct xenbus_driver pvcalls_front_driver = {
> + .ids = pvcalls_front_ids,
> + .probe = pvcalls_front_probe,
> + .remove = pvcalls_front_remove,
> + .resume = pvcalls_front_resume,
> + .otherend_changed = pvcalls_front_changed,
> +};
> +
> +static int __init pvcalls_frontend_init(void)
> +{
> + if (!xen_domain())
> + return -ENODEV;
> +
> + pr_info("Initialising Xen pvcalls frontend driver\n");
> +
> + return xenbus_register_frontend(&pvcalls_front_driver);
> +}
> +
> +module_init(pvcalls_frontend_init);
>
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-25 00:40 +0200 |
| Subject | Re: [PATCH v1 01/13] xen/pvcalls: introduce the pvcalls xenbus frontend |
| Message-ID | <u6Ub7-2PW-13@gated-at.bofh.it> |
| In reply to | #1695009 |
On Mon, 24 Jul 2017, Juergen Gross wrote:
> On 22/07/17 02:11, Stefano Stabellini wrote:
> > Introduce a xenbus frontend for the pvcalls protocol, as defined by
> > https://xenbits.xen.org/docs/unstable/misc/pvcalls.html.
> >
> > This patch only adds the stubs, the code will be added by the following
> > patches.
> >
> > Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
> > CC: boris.ostrovsky@oracle.com
> > CC: jgross@suse.com
> > ---
> > drivers/xen/pvcalls-front.c | 68 +++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 68 insertions(+)
> > create mode 100644 drivers/xen/pvcalls-front.c
> >
> > diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> > new file mode 100644
> > index 0000000..173e204
> > --- /dev/null
> > +++ b/drivers/xen/pvcalls-front.c
> > @@ -0,0 +1,68 @@
> > +/*
> > + * (c) 2017 Stefano Stabellini <stefano@aporeto.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <linux/module.h>
> > +
> > +#include <xen/events.h>
> > +#include <xen/grant_table.h>
> > +#include <xen/xen.h>
> > +#include <xen/xenbus.h>
> > +#include <xen/interface/io/pvcalls.h>
> > +
> > +static const struct xenbus_device_id pvcalls_front_ids[] = {
> > + { "pvcalls" },
> > + { "" }
> > +};
> > +
> > +static int pvcalls_front_remove(struct xenbus_device *dev)
> > +{
> > + return 0;
> > +}
> > +
> > +static int pvcalls_front_probe(struct xenbus_device *dev,
> > + const struct xenbus_device_id *id)
> > +{
> > + return 0;
> > +}
> > +
> > +static int pvcalls_front_resume(struct xenbus_device *dev)
> > +{
> > + dev_warn(&dev->dev, "suspsend/resume unsupported\n");
> > + return 0;
> > +}
>
> Why are you adding a resume function doing nothing but issuing a
> message? Just omit it.
I'll do, thanks!
> > +
> > +static void pvcalls_front_changed(struct xenbus_device *dev,
> > + enum xenbus_state backend_state)
> > +{
> > +}
> > +
> > +static struct xenbus_driver pvcalls_front_driver = {
> > + .ids = pvcalls_front_ids,
> > + .probe = pvcalls_front_probe,
> > + .remove = pvcalls_front_remove,
> > + .resume = pvcalls_front_resume,
> > + .otherend_changed = pvcalls_front_changed,
> > +};
> > +
> > +static int __init pvcalls_frontend_init(void)
> > +{
> > + if (!xen_domain())
> > + return -ENODEV;
> > +
> > + pr_info("Initialising Xen pvcalls frontend driver\n");
> > +
> > + return xenbus_register_frontend(&pvcalls_front_driver);
> > +}
> > +
> > +module_init(pvcalls_frontend_init);
> >
>
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web