Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1700458 > unrolled thread
| Started by | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| First post | 2017-08-01 01:00 +0200 |
| Last post | 2017-08-10 20:20 +0200 |
| Articles | 9 on this page of 29 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v3 00/13] introduce the Xen PV Calls frontend Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:00 +0200
[PATCH v3 12/13] xen/pvcalls: implement release command Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:00 +0200
Re: [PATCH v3 12/13] xen/pvcalls: implement release command Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-15 22:50 +0200
[PATCH v3 06/13] xen/pvcalls: implement bind command Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:00 +0200
Re: [PATCH v3 06/13] xen/pvcalls: implement bind command Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-13 03:30 +0200
[PATCH v3 07/13] xen/pvcalls: implement listen command Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:00 +0200
Re: [PATCH v3 07/13] xen/pvcalls: implement listen command Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-13 03:30 +0200
[PATCH v3 11/13] xen/pvcalls: implement poll command Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:00 +0200
Re: [PATCH v3 11/13] xen/pvcalls: implement poll command Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-15 22:40 +0200
[PATCH v3 01/13] xen/pvcalls: introduce the pvcalls xenbus frontend Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:10 +0200
[PATCH v3 03/13] xen/pvcalls: connect to the backend Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:10 +0200
Re: [PATCH v3 03/13] xen/pvcalls: connect to the backend Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-12 01:00 +0200
[PATCH v3 09/13] xen/pvcalls: implement sendmsg Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:10 +0200
Re: [PATCH v3 09/13] xen/pvcalls: implement sendmsg Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-15 04:40 +0200
[PATCH v3 13/13] xen: introduce a Kconfig option to enable the pvcalls frontend Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:10 +0200
[PATCH v3 08/13] xen/pvcalls: implement accept command Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:10 +0200
Re: [PATCH v3 08/13] xen/pvcalls: implement accept command Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-15 04:10 +0200
Re: [PATCH v3 08/13] xen/pvcalls: implement accept command Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-15 04:10 +0200
[PATCH v3 02/13] xen/pvcalls: implement frontend disconnect Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:10 +0200
Re: [PATCH v3 02/13] xen/pvcalls: implement frontend disconnect Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-12 00:50 +0200
[PATCH v3 10/13] xen/pvcalls: implement recvmsg Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:10 +0200
Re: [PATCH v3 10/13] xen/pvcalls: implement recvmsg Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-15 04:50 +0200
[PATCH v3 05/13] xen/pvcalls: implement connect command Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:10 +0200
Re: [PATCH v3 05/13] xen/pvcalls: implement connect command Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-13 03:20 +0200
[PATCH v3 04/13] xen/pvcalls: implement socket command and handle events Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 01:10 +0200
Re: [PATCH v3 04/13] xen/pvcalls: implement socket command and handle events Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-13 02:50 +0200
Re: [PATCH v3 01/13] xen/pvcalls: introduce the pvcalls xenbus frontend Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-12 00:40 +0200
Re: [PATCH v3 00/13] introduce the Xen PV Calls frontend Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-10 17:10 +0200
Re: [PATCH v3 00/13] introduce the Xen PV Calls frontend Stefano Stabellini <sstabellini@kernel.org> - 2017-08-10 20:20 +0200
Page 2 of 2 — ← Prev page 1 [2]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-08-01 01:10 +0200 |
| Subject | [PATCH v3 10/13] xen/pvcalls: implement recvmsg |
| Message-ID | <u9rZ0-3YU-35@gated-at.bofh.it> |
| In reply to | #1700477 |
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
[toc] | [prev] | [next] | [standalone]
| From | Boris Ostrovsky <boris.ostrovsky@oracle.com> |
|---|---|
| Date | 2017-08-15 04:50 +0200 |
| Subject | Re: [PATCH v3 10/13] xen/pvcalls: implement recvmsg |
| Message-ID | <ueA5z-3To-7@gated-at.bofh.it> |
| In reply to | #1700491 |
On 07/31/2017 06:57 PM, 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 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;
Not necessary to initialize.
> + 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;
Are errors converted by the caller? (I am asking because recvmsg can
only return -1 for errors)
-boris
> +}
> +
> 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-08-01 01:10 +0200 |
| Subject | [PATCH v3 05/13] xen/pvcalls: implement connect command |
| Message-ID | <u9rZ0-3YU-37@gated-at.bofh.it> |
| In reply to | #1700477 |
Send PVCALLS_CONNECT to the backend. Allocate a new ring and evtchn for
the active socket.
Introduce fields in struct sock_mapping to keep track of active sockets.
Introduce a waitqueue to allow the frontend to wait on data coming from
the backend on the active socket (recvmsg command).
Two mutexes (one of reads and one for writes) will be used to protect
the active socket in and out rings from concurrent accesses.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-front.c | 146 ++++++++++++++++++++++++++++++++++++++++++++
drivers/xen/pvcalls-front.h | 2 +
2 files changed, 148 insertions(+)
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index 7c4a7cb..379b8fb 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -13,6 +13,10 @@
*/
#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+
+#include <net/sock.h>
#include <xen/events.h>
#include <xen/grant_table.h>
@@ -44,6 +48,18 @@ struct sock_mapping {
bool active_socket;
struct list_head list;
struct socket *sock;
+ union {
+ struct {
+ int irq;
+ grant_ref_t ref;
+ struct pvcalls_data_intf *ring;
+ struct pvcalls_data data;
+ struct mutex in_mutex;
+ struct mutex out_mutex;
+
+ wait_queue_head_t inflight_conn_req;
+ } active;
+ };
};
static inline int get_request(struct pvcalls_bedata *bedata, int *req_id)
@@ -97,6 +113,18 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static irqreturn_t pvcalls_front_conn_handler(int irq, void *sock_map)
+{
+ struct sock_mapping *map = sock_map;
+
+ if (map == NULL)
+ return IRQ_HANDLED;
+
+ wake_up_interruptible(&map->active.inflight_conn_req);
+
+ return IRQ_HANDLED;
+}
+
int pvcalls_front_socket(struct socket *sock)
{
struct pvcalls_bedata *bedata;
@@ -162,6 +190,124 @@ int pvcalls_front_socket(struct socket *sock)
return ret;
}
+static int create_active(struct sock_mapping *map, int *evtchn)
+{
+ void *bytes;
+ int ret = -ENOMEM, irq = -1, i;
+
+ init_waitqueue_head(&map->active.inflight_conn_req);
+
+ map->active.ring = (struct pvcalls_data_intf *)
+ __get_free_page(GFP_KERNEL | __GFP_ZERO);
+ if (map->active.ring == NULL)
+ goto out_error;
+ memset(map->active.ring, 0, XEN_PAGE_SIZE);
+ map->active.ring->ring_order = PVCALLS_RING_ORDER;
+ bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ map->active.ring->ring_order);
+ if (bytes == NULL)
+ goto out_error;
+ for (i = 0; i < (1 << map->active.ring->ring_order); i++)
+ map->active.ring->ref[i] = gnttab_grant_foreign_access(
+ pvcalls_front_dev->otherend_id,
+ pfn_to_gfn(virt_to_pfn(bytes) + i), 0);
+
+ map->active.ref = gnttab_grant_foreign_access(
+ pvcalls_front_dev->otherend_id,
+ pfn_to_gfn(virt_to_pfn((void *)map->active.ring)), 0);
+
+ map->active.data.in = bytes;
+ map->active.data.out = bytes +
+ XEN_FLEX_RING_SIZE(map->active.ring->ring_order);
+
+ ret = xenbus_alloc_evtchn(pvcalls_front_dev, evtchn);
+ if (ret)
+ goto out_error;
+ irq = bind_evtchn_to_irqhandler(*evtchn, pvcalls_front_conn_handler,
+ 0, "pvcalls-frontend", map);
+ if (irq < 0) {
+ ret = irq;
+ goto out_error;
+ }
+
+ map->active.irq = irq;
+ map->active_socket = true;
+ mutex_init(&map->active.in_mutex);
+ mutex_init(&map->active.out_mutex);
+
+ return 0;
+
+out_error:
+ if (irq >= 0)
+ unbind_from_irqhandler(irq, map);
+ else if (*evtchn >= 0)
+ xenbus_free_evtchn(pvcalls_front_dev, *evtchn);
+ kfree(map->active.data.in);
+ kfree(map->active.ring);
+ kfree(map);
+ return ret;
+}
+
+int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
+ int addr_len, int flags)
+{
+ struct pvcalls_bedata *bedata;
+ struct sock_mapping *map = NULL;
+ struct xen_pvcalls_request *req;
+ int notify, req_id, ret, evtchn;
+
+ if (!pvcalls_front_dev)
+ return -ENETUNREACH;
+ if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM)
+ return -ENOTSUPP;
+
+ bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
+
+ map = (struct sock_mapping *) READ_ONCE(sock->sk->sk_send_head);
+ if (!map)
+ return -EINVAL;
+
+ spin_lock(&bedata->pvcallss_lock);
+ ret = get_request(bedata, &req_id);
+ if (ret < 0) {
+ spin_unlock(&bedata->pvcallss_lock);
+ return ret;
+ }
+ ret = create_active(map, &evtchn);
+ if (ret < 0) {
+ spin_unlock(&bedata->pvcallss_lock);
+ return ret;
+ }
+
+ req = RING_GET_REQUEST(&bedata->ring, req_id);
+ req->req_id = req_id;
+ req->cmd = PVCALLS_CONNECT;
+ req->u.connect.id = (uint64_t)map;
+ memcpy(req->u.connect.addr, addr, sizeof(*addr));
+ req->u.connect.len = addr_len;
+ req->u.connect.flags = flags;
+ req->u.connect.ref = map->active.ref;
+ req->u.connect.evtchn = evtchn;
+
+ map->sock = 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);
+
+ 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 b7dabed..63b0417 100644
--- a/drivers/xen/pvcalls-front.h
+++ b/drivers/xen/pvcalls-front.h
@@ -4,5 +4,7 @@
#include <linux/net.h>
int pvcalls_front_socket(struct socket *sock);
+int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
+ int addr_len, int flags);
#endif
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Boris Ostrovsky <boris.ostrovsky@oracle.com> |
|---|---|
| Date | 2017-08-13 03:20 +0200 |
| Subject | Re: [PATCH v3 05/13] xen/pvcalls: implement connect command |
| Message-ID | <udPJn-en-1@gated-at.bofh.it> |
| In reply to | #1700493 |
On 07/31/2017 06:57 PM, Stefano Stabellini wrote:
> Send PVCALLS_CONNECT to the backend. Allocate a new ring and evtchn for
> the active socket.
>
> Introduce fields in struct sock_mapping to keep track of active sockets.
> Introduce a waitqueue to allow the frontend to wait on data coming from
> the backend on the active socket (recvmsg command).
>
> Two mutexes (one of reads and one for writes) will be used to protect
> the active socket in and out rings from concurrent accesses.
>
> Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
> CC: boris.ostrovsky@oracle.com
> CC: jgross@suse.com
> ---
> drivers/xen/pvcalls-front.c | 146 ++++++++++++++++++++++++++++++++++++++++++++
> drivers/xen/pvcalls-front.h | 2 +
> 2 files changed, 148 insertions(+)
>
> diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> index 7c4a7cb..379b8fb 100644
> --- a/drivers/xen/pvcalls-front.c
> +++ b/drivers/xen/pvcalls-front.c
> @@ -13,6 +13,10 @@
> */
>
> #include <linux/module.h>
> +#include <linux/net.h>
> +#include <linux/socket.h>
> +
> +#include <net/sock.h>
>
> #include <xen/events.h>
> #include <xen/grant_table.h>
> @@ -44,6 +48,18 @@ struct sock_mapping {
> bool active_socket;
> struct list_head list;
> struct socket *sock;
> + union {
> + struct {
> + int irq;
> + grant_ref_t ref;
> + struct pvcalls_data_intf *ring;
> + struct pvcalls_data data;
> + struct mutex in_mutex;
> + struct mutex out_mutex;
> +
> + wait_queue_head_t inflight_conn_req;
> + } active;
> + };
> };
>
> static inline int get_request(struct pvcalls_bedata *bedata, int *req_id)
> @@ -97,6 +113,18 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
> return IRQ_HANDLED;
> }
>
> +static irqreturn_t pvcalls_front_conn_handler(int irq, void *sock_map)
> +{
> + struct sock_mapping *map = sock_map;
> +
> + if (map == NULL)
> + return IRQ_HANDLED;
> +
> + wake_up_interruptible(&map->active.inflight_conn_req);
> +
> + return IRQ_HANDLED;
> +}
> +
> int pvcalls_front_socket(struct socket *sock)
> {
> struct pvcalls_bedata *bedata;
> @@ -162,6 +190,124 @@ int pvcalls_front_socket(struct socket *sock)
> return ret;
> }
>
> +static int create_active(struct sock_mapping *map, int *evtchn)
> +{
> + void *bytes;
> + int ret = -ENOMEM, irq = -1, i;
> +
> + init_waitqueue_head(&map->active.inflight_conn_req);
> +
> + map->active.ring = (struct pvcalls_data_intf *)
> + __get_free_page(GFP_KERNEL | __GFP_ZERO);
> + if (map->active.ring == NULL)
> + goto out_error;
> + memset(map->active.ring, 0, XEN_PAGE_SIZE);
Not needed (page allocated with __GFP_ZERO)
BTW, are you operating on XEN_PAGE_SIZE of PAGE_SIZE? Because if it's
the former than __get_free_page() may be way more than what you need.
(below too)
> + map->active.ring->ring_order = PVCALLS_RING_ORDER;
> + bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
> + map->active.ring->ring_order);
> + if (bytes == NULL)
> + goto out_error;
> + for (i = 0; i < (1 << map->active.ring->ring_order); i++)
PVCALLS_RING_ORDER
> + map->active.ring->ref[i] = gnttab_grant_foreign_access(
> + pvcalls_front_dev->otherend_id,
> + pfn_to_gfn(virt_to_pfn(bytes) + i), 0);
> +
> + map->active.ref = gnttab_grant_foreign_access(
> + pvcalls_front_dev->otherend_id,
> + pfn_to_gfn(virt_to_pfn((void *)map->active.ring)), 0);
> +
> + map->active.data.in = bytes;
> + map->active.data.out = bytes +
> + XEN_FLEX_RING_SIZE(map->active.ring->ring_order);
> +
> + ret = xenbus_alloc_evtchn(pvcalls_front_dev, evtchn);
> + if (ret)
> + goto out_error;
> + irq = bind_evtchn_to_irqhandler(*evtchn, pvcalls_front_conn_handler,
> + 0, "pvcalls-frontend", map);
> + if (irq < 0) {
> + ret = irq;
> + goto out_error;
> + }
> +
> + map->active.irq = irq;
> + map->active_socket = true;
> + mutex_init(&map->active.in_mutex);
> + mutex_init(&map->active.out_mutex);
> +
> + return 0;
> +
> +out_error:
> + if (irq >= 0)
> + unbind_from_irqhandler(irq, map);
> + else if (*evtchn >= 0)
*evtchn may have been passed in as >=0. You probably want to set to -1
or something in the beginning.
> + xenbus_free_evtchn(pvcalls_front_dev, *evtchn);
> + kfree(map->active.data.in);
> + kfree(map->active.ring);
> + kfree(map);
Probably a matter of personal style but I think it's better to free map
in the caller.
Actually, should it be freed? The caller gets an error if get_request()
or create_active() fail. In the first case map is not freed. Is the
caller going to distinguish EAGAIN from any other error and know that
map does not need to be allocated?
(Also I think you need to unlink the map from socket_mapping list before
freeing it).
-boris
> + return ret;
> +}
> +
> +int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
> + int addr_len, int flags)
> +{
> + struct pvcalls_bedata *bedata;
> + struct sock_mapping *map = NULL;
> + struct xen_pvcalls_request *req;
> + int notify, req_id, ret, evtchn;
> +
> + if (!pvcalls_front_dev)
> + return -ENETUNREACH;
> + if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM)
> + return -ENOTSUPP;
> +
> + bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
> +
> + map = (struct sock_mapping *) READ_ONCE(sock->sk->sk_send_head);
> + if (!map)
> + return -EINVAL;
> +
> + spin_lock(&bedata->pvcallss_lock);
> + ret = get_request(bedata, &req_id);
> + if (ret < 0) {
> + spin_unlock(&bedata->pvcallss_lock);
> + return ret;
> + }
> + ret = create_active(map, &evtchn);
> + if (ret < 0) {
> + spin_unlock(&bedata->pvcallss_lock);
> + return ret;
> + }
> +
> + req = RING_GET_REQUEST(&bedata->ring, req_id);
> + req->req_id = req_id;
> + req->cmd = PVCALLS_CONNECT;
> + req->u.connect.id = (uint64_t)map;
> + memcpy(req->u.connect.addr, addr, sizeof(*addr));
> + req->u.connect.len = addr_len;
> + req->u.connect.flags = flags;
> + req->u.connect.ref = map->active.ref;
> + req->u.connect.evtchn = evtchn;
> +
> + map->sock = 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);
> +
> + 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 b7dabed..63b0417 100644
> --- a/drivers/xen/pvcalls-front.h
> +++ b/drivers/xen/pvcalls-front.h
> @@ -4,5 +4,7 @@
> #include <linux/net.h>
>
> int pvcalls_front_socket(struct socket *sock);
> +int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
> + int addr_len, int flags);
>
> #endif
>
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-08-01 01:10 +0200 |
| Subject | [PATCH v3 04/13] xen/pvcalls: implement socket command and handle events |
| Message-ID | <u9rYZ-3YU-11@gated-at.bofh.it> |
| In reply to | #1700477 |
Send a PVCALLS_SOCKET command to the backend, use the masked
req_prod_pvt as req_id. This way, req_id is guaranteed to be between 0
and PVCALLS_NR_REQ_PER_RING. We already have a slot in the rsp array
ready for the response, and there cannot be two outstanding responses
with the same req_id.
Wait for the response by waiting on the inflight_req waitqueue and
check for the req_id field in rsp[req_id]. Use atomic accesses and
barriers to read the field. Note that the barriers are simple smp
barriers (as opposed to virt barriers) because they are for internal
frontend synchronization, not frontend<->backend communication.
Once a response is received, clear the corresponding rsp slot by setting
req_id to PVCALLS_INVALID_ID. Note that PVCALLS_INVALID_ID is invalid
only from the frontend point of view. It is not part of the PVCalls
protocol.
pvcalls_front_event_handler is in charge of copying responses from the
ring to the appropriate rsp slot. It is done by copying the body of the
response first, then by copying req_id atomically. After the copies,
wake up anybody waiting on waitqueue.
pvcallss_lock protects accesses to the ring.
Create a new struct sock_mapping and convert the pointer into an
uint64_t and use it as id for the new socket to pass to the backend. The
struct will be fully initialized later on connect or bind. In this patch
the struct sock_mapping is empty, the fields will be added by the next
patch.
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.
This way, we can easily get the struct sock_mapping from the struct
socket.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-front.c | 119 ++++++++++++++++++++++++++++++++++++++++++++
drivers/xen/pvcalls-front.h | 8 +++
2 files changed, 127 insertions(+)
create mode 100644 drivers/xen/pvcalls-front.h
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index 2afe36d..7c4a7cb 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -20,6 +20,8 @@
#include <xen/xenbus.h>
#include <xen/interface/io/pvcalls.h>
+#include "pvcalls-front.h"
+
#define PVCALLS_INVALID_ID UINT_MAX
#define PVCALLS_RING_ORDER XENBUS_MAX_RING_GRANT_ORDER
#define PVCALLS_NR_REQ_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE)
@@ -38,11 +40,128 @@ struct pvcalls_bedata {
};
static struct xenbus_device *pvcalls_front_dev;
+struct sock_mapping {
+ bool active_socket;
+ struct list_head list;
+ struct socket *sock;
+};
+
+static inline int get_request(struct pvcalls_bedata *bedata, int *req_id)
+{
+ *req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
+ if (RING_FULL(&bedata->ring) ||
+ READ_ONCE(bedata->rsp[*req_id].req_id) != PVCALLS_INVALID_ID)
+ return -EAGAIN;
+ return 0;
+}
+
static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
{
+ struct xenbus_device *dev = dev_id;
+ struct pvcalls_bedata *bedata;
+ struct xen_pvcalls_response *rsp;
+ uint8_t *src, *dst;
+ int req_id = 0, more = 0, done = 0;
+
+ if (dev == NULL)
+ return IRQ_HANDLED;
+
+ bedata = dev_get_drvdata(&dev->dev);
+ if (bedata == NULL)
+ return IRQ_HANDLED;
+
+again:
+ while (RING_HAS_UNCONSUMED_RESPONSES(&bedata->ring)) {
+ rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons);
+
+ req_id = rsp->req_id;
+ dst = (uint8_t *)&bedata->rsp[req_id] + sizeof(rsp->req_id);
+ src = (uint8_t *)rsp + sizeof(rsp->req_id);
+ memcpy(dst, src, sizeof(*rsp) - sizeof(rsp->req_id));
+ /*
+ * First copy the rest of the data, then req_id. It is
+ * paired with the barrier when accessing bedata->rsp.
+ */
+ smp_wmb();
+ WRITE_ONCE(bedata->rsp[req_id].req_id, rsp->req_id);
+
+ done = 1;
+ bedata->ring.rsp_cons++;
+ }
+
+ RING_FINAL_CHECK_FOR_RESPONSES(&bedata->ring, more);
+ if (more)
+ goto again;
+ if (done)
+ wake_up(&bedata->inflight_req);
return IRQ_HANDLED;
}
+int pvcalls_front_socket(struct socket *sock)
+{
+ struct pvcalls_bedata *bedata;
+ struct sock_mapping *map = NULL;
+ struct xen_pvcalls_request *req;
+ int notify, req_id, ret;
+
+ if (!pvcalls_front_dev)
+ return -EACCES;
+ /*
+ * PVCalls only supports domain AF_INET,
+ * type SOCK_STREAM and protocol 0 sockets for now.
+ *
+ * Check socket type here, AF_INET and protocol checks are done
+ * by the caller.
+ */
+ if (sock->type != SOCK_STREAM)
+ return -ENOTSUPP;
+
+ bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (map == NULL)
+ return -ENOMEM;
+ /*
+ * 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. This way, we can easily get the
+ * struct sock_mapping from the struct socket.
+ */
+ WRITE_ONCE(sock->sk->sk_send_head, (void *)map);
+
+ spin_lock(&bedata->pvcallss_lock);
+ list_add_tail(&map->list, &bedata->socket_mappings);
+
+ ret = get_request(bedata, &req_id);
+ if (ret < 0) {
+ spin_unlock(&bedata->pvcallss_lock);
+ return ret;
+ }
+ req = RING_GET_REQUEST(&bedata->ring, req_id);
+ req->req_id = req_id;
+ req->cmd = PVCALLS_SOCKET;
+ req->u.socket.id = (uint64_t) map;
+ req->u.socket.domain = AF_INET;
+ req->u.socket.type = SOCK_STREAM;
+ req->u.socket.protocol = 0;
+
+ 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);
+
+ 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
new file mode 100644
index 0000000..b7dabed
--- /dev/null
+++ b/drivers/xen/pvcalls-front.h
@@ -0,0 +1,8 @@
+#ifndef __PVCALLS_FRONT_H__
+#define __PVCALLS_FRONT_H__
+
+#include <linux/net.h>
+
+int pvcalls_front_socket(struct socket *sock);
+
+#endif
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Boris Ostrovsky <boris.ostrovsky@oracle.com> |
|---|---|
| Date | 2017-08-13 02:50 +0200 |
| Subject | Re: [PATCH v3 04/13] xen/pvcalls: implement socket command and handle events |
| Message-ID | <udPgm-8d3-3@gated-at.bofh.it> |
| In reply to | #1700495 |
On 07/31/2017 06:57 PM, Stefano Stabellini wrote:
> Send a PVCALLS_SOCKET command to the backend, use the masked
> req_prod_pvt as req_id. This way, req_id is guaranteed to be between 0
> and PVCALLS_NR_REQ_PER_RING. We already have a slot in the rsp array
> ready for the response, and there cannot be two outstanding responses
> with the same req_id.
>
> Wait for the response by waiting on the inflight_req waitqueue and
> check for the req_id field in rsp[req_id]. Use atomic accesses and
> barriers to read the field. Note that the barriers are simple smp
> barriers (as opposed to virt barriers) because they are for internal
> frontend synchronization, not frontend<->backend communication.
>
> Once a response is received, clear the corresponding rsp slot by setting
> req_id to PVCALLS_INVALID_ID. Note that PVCALLS_INVALID_ID is invalid
> only from the frontend point of view. It is not part of the PVCalls
> protocol.
>
> pvcalls_front_event_handler is in charge of copying responses from the
> ring to the appropriate rsp slot. It is done by copying the body of the
> response first, then by copying req_id atomically. After the copies,
> wake up anybody waiting on waitqueue.
>
> pvcallss_lock protects accesses to the ring.
>
> Create a new struct sock_mapping and convert the pointer into an
> uint64_t and use it as id for the new socket to pass to the backend. The
> struct will be fully initialized later on connect or bind. In this patch
> the struct sock_mapping is empty, the fields will be added by the next
> patch.
>
> 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.
> This way, we can easily get the struct sock_mapping from the struct
> socket.
>
> Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
> CC: boris.ostrovsky@oracle.com
> CC: jgross@suse.com
> ---
> drivers/xen/pvcalls-front.c | 119 ++++++++++++++++++++++++++++++++++++++++++++
> drivers/xen/pvcalls-front.h | 8 +++
> 2 files changed, 127 insertions(+)
> create mode 100644 drivers/xen/pvcalls-front.h
>
> diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
> index 2afe36d..7c4a7cb 100644
> --- a/drivers/xen/pvcalls-front.c
> +++ b/drivers/xen/pvcalls-front.c
> @@ -20,6 +20,8 @@
> #include <xen/xenbus.h>
> #include <xen/interface/io/pvcalls.h>
>
> +#include "pvcalls-front.h"
> +
> #define PVCALLS_INVALID_ID UINT_MAX
> #define PVCALLS_RING_ORDER XENBUS_MAX_RING_GRANT_ORDER
> #define PVCALLS_NR_REQ_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE)
> @@ -38,11 +40,128 @@ struct pvcalls_bedata {
> };
> static struct xenbus_device *pvcalls_front_dev;
>
> +struct sock_mapping {
> + bool active_socket;
> + struct list_head list;
> + struct socket *sock;
> +};
> +
> +static inline int get_request(struct pvcalls_bedata *bedata, int *req_id)
> +{
> + *req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
> + if (RING_FULL(&bedata->ring) ||
> + READ_ONCE(bedata->rsp[*req_id].req_id) != PVCALLS_INVALID_ID)
> + return -EAGAIN;
> + return 0;
> +}
> +
> static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
> {
> + struct xenbus_device *dev = dev_id;
> + struct pvcalls_bedata *bedata;
> + struct xen_pvcalls_response *rsp;
> + uint8_t *src, *dst;
> + int req_id = 0, more = 0, done = 0;
> +
> + if (dev == NULL)
> + return IRQ_HANDLED;
> +
> + bedata = dev_get_drvdata(&dev->dev);
> + if (bedata == NULL)
> + return IRQ_HANDLED;
> +
> +again:
> + while (RING_HAS_UNCONSUMED_RESPONSES(&bedata->ring)) {
> + rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons);
> +
> + req_id = rsp->req_id;
> + dst = (uint8_t *)&bedata->rsp[req_id] + sizeof(rsp->req_id);
> + src = (uint8_t *)rsp + sizeof(rsp->req_id);
> + memcpy(dst, src, sizeof(*rsp) - sizeof(rsp->req_id));
> + /*
> + * First copy the rest of the data, then req_id. It is
> + * paired with the barrier when accessing bedata->rsp.
> + */
> + smp_wmb();
> + WRITE_ONCE(bedata->rsp[req_id].req_id, rsp->req_id);
> +
> + done = 1;
> + bedata->ring.rsp_cons++;
> + }
> +
> + RING_FINAL_CHECK_FOR_RESPONSES(&bedata->ring, more);
> + if (more)
> + goto again;
> + if (done)
> + wake_up(&bedata->inflight_req);
> return IRQ_HANDLED;
> }
>
> +int pvcalls_front_socket(struct socket *sock)
> +{
> + struct pvcalls_bedata *bedata;
> + struct sock_mapping *map = NULL;
> + struct xen_pvcalls_request *req;
> + int notify, req_id, ret;
> +
> + if (!pvcalls_front_dev)
> + return -EACCES;
> + /*
> + * PVCalls only supports domain AF_INET,
> + * type SOCK_STREAM and protocol 0 sockets for now.
> + *
> + * Check socket type here, AF_INET and protocol checks are done
> + * by the caller.
> + */
> + if (sock->type != SOCK_STREAM)
> + return -ENOTSUPP;
> +
> + bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
> +
> + map = kzalloc(sizeof(*map), GFP_KERNEL);
> + if (map == NULL)
> + return -ENOMEM;
> + /*
> + * 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. This way, we can easily get the
> + * struct sock_mapping from the struct socket.
Is this a safe assumption? Is it conceivable that at some point in the
future sk_send_head might become used?
> + */
> + WRITE_ONCE(sock->sk->sk_send_head, (void *)map);
> +
> + spin_lock(&bedata->pvcallss_lock);
> + list_add_tail(&map->list, &bedata->socket_mappings);
> +
> + ret = get_request(bedata, &req_id);
> + if (ret < 0) {
> + spin_unlock(&bedata->pvcallss_lock);
> + return ret;
What is happening to the mapping you've linked above? Should it be
unlinked and freed? (or defer its creation until we've got a request slot?)
> + }
> + req = RING_GET_REQUEST(&bedata->ring, req_id);
> + req->req_id = req_id;
> + req->cmd = PVCALLS_SOCKET;
> + req->u.socket.id = (uint64_t) map;
> + req->u.socket.domain = AF_INET;
> + req->u.socket.type = SOCK_STREAM;
> + req->u.socket.protocol = 0;
IPPROTO_IP?
-boris
> +
> + 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);
> +
> + 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
> new file mode 100644
> index 0000000..b7dabed
> --- /dev/null
> +++ b/drivers/xen/pvcalls-front.h
> @@ -0,0 +1,8 @@
> +#ifndef __PVCALLS_FRONT_H__
> +#define __PVCALLS_FRONT_H__
> +
> +#include <linux/net.h>
> +
> +int pvcalls_front_socket(struct socket *sock);
> +
> +#endif
>
[toc] | [prev] | [next] | [standalone]
| From | Boris Ostrovsky <boris.ostrovsky@oracle.com> |
|---|---|
| Date | 2017-08-12 00:40 +0200 |
| Subject | Re: [PATCH v3 01/13] xen/pvcalls: introduce the pvcalls xenbus frontend |
| Message-ID | <udqKZ-NG-1@gated-at.bofh.it> |
| In reply to | #1700477 |
On 07/31/2017 06:57 PM, 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 Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
[toc] | [prev] | [next] | [standalone]
| From | Boris Ostrovsky <boris.ostrovsky@oracle.com> |
|---|---|
| Date | 2017-08-10 17:10 +0200 |
| Message-ID | <ucXfZ-7nB-31@gated-at.bofh.it> |
| In reply to | #1700458 |
On 07/31/2017 06:57 PM, Stefano Stabellini wrote: > 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, Should this be reviewed or are you going to send another version? -boris
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-08-10 20:20 +0200 |
| Message-ID | <ud0dQ-Jr-21@gated-at.bofh.it> |
| In reply to | #1708714 |
On Thu, 10 Aug 2017, Boris Ostrovsky wrote: > On 07/31/2017 06:57 PM, Stefano Stabellini wrote: > > 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, > > > Should this be reviewed or are you going to send another version? Sorry for the delay, I am dealing with a personal issue at the moment and I didn't manage to address your valid comments on the release function implementation. However in this version I did address all other comments, so it would be good if you could give a look at it, bearing in mind that the problem on release is still unaddressed here. Thanks, Stefano
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web