Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1681891 > unrolled thread
| Started by | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| First post | 2017-07-06 00:00 +0200 |
| Last post | 2017-07-06 00:00 +0200 |
| Articles | 11 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v7 00/18] introduce the Xen PV Calls backend Stefano Stabellini <sstabellini@kernel.org> - 2017-07-06 00:00 +0200
[PATCH v7 01/18] xen: introduce the pvcalls interface header Stefano Stabellini <sstabellini@kernel.org> - 2017-07-06 00:00 +0200
[PATCH v7 04/18] xen/pvcalls: xenbus state handling Stefano Stabellini <sstabellini@kernel.org> - 2017-07-06 00:00 +0200
Re: [PATCH v7 04/18] xen/pvcalls: xenbus state handling Juergen Gross <jgross@suse.com> - 2017-07-06 09:20 +0200
[PATCH v7 14/18] xen/pvcalls: disconnect and module_exit Stefano Stabellini <sstabellini@kernel.org> - 2017-07-06 00:00 +0200
Re: [PATCH v7 14/18] xen/pvcalls: disconnect and module_exit Juergen Gross <jgross@suse.com> - 2017-07-06 09:30 +0200
[PATCH v7 07/18] xen/pvcalls: implement socket command Stefano Stabellini <sstabellini@kernel.org> - 2017-07-06 00:00 +0200
[PATCH v7 13/18] xen/pvcalls: implement release command Stefano Stabellini <sstabellini@kernel.org> - 2017-07-06 00:00 +0200
[PATCH v7 15/18] xen/pvcalls: implement the ioworker functions Stefano Stabellini <sstabellini@kernel.org> - 2017-07-06 00:00 +0200
[PATCH v7 12/18] xen/pvcalls: implement poll command Stefano Stabellini <sstabellini@kernel.org> - 2017-07-06 00:00 +0200
[PATCH v7 03/18] xen/pvcalls: initialize the module and register the xenbus backend Stefano Stabellini <sstabellini@kernel.org> - 2017-07-06 00:00 +0200
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-06 00:00 +0200 |
| Subject | [PATCH v7 00/18] introduce the Xen PV Calls backend |
| Message-ID | <u00v0-3uT-9@gated-at.bofh.it> |
Hi all,
this series introduces the backend 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
I tried to split the source code into small pieces to make it easier to
read and understand. Please review!
Changes in v7:
- added reviewed-bys
- version/versions in warning
- don't switch to XenbusStateInitWait in case of abort
- only unbind irq on error path if it was previously set
- don't add, then remove, work_struct and wq in patch #5 and #6
- remove call to pvcalls_back_work from backend_connect
- unbind fedata->irq before unmapping the ring
- validate req->u.connect.len
- ignore req->u.connect.flags
- cleanup of the error pathes of pvcalls_back_bind
- return void from pvcalls_conn_back_write
Changes in v6:
- send ENOTSUPP to frontends for unsupported commands
- reset notify_all
- use a threaded irq handler instead of a workqueue to handle guest
commands
Changes in v5:
- added review-byes
- remove unnecessary gotos
- ret 0 in pvcalls_back_connect
- do not lose ret values
- remove queue->rskq_lock
- make sure all accesses to socket_mappings and socketpass_mappings are
protected by socket_lock
- rename ring_size to array_size
Changes in v4:
- add reviewed-bys
- fix return values of many functions
- remove pointless initializers
- print a warning if ring_order > MAX_RING_ORDER
- remove map->ioworker.cpu
- use queue_work instead of queue_work_on
- add sock_release() on error paths where appropriate
- add a comment in __pvcalls_back_accept about racing with
pvcalls_back_accept and atomicity of reqcopy
- remove unneded (void*) casts
- remove unneded {}
- fix backend_disconnect if !mappass
- remove pointless continue in backend_disconnect
- remove pointless memset of &pvcalls_back_global
- pass *opaque to pvcalls_conn_back_read
- improve WARN_ON in pvcalls_conn_back_read
- fix error checks in pvcalls_conn_back_write
- XEN_PVCALLS_BACKEND depends on XEN_BACKEND
- rename priv to fedata across all patches
Changes in v3:
- added reviewed-bys
- return err from pvcalls_back_probe
- remove old comments
- use a xenstore transaction in pvcalls_back_probe
- ignore errors from xenbus_switch_state
- rename pvcalls_back_priv to pvcalls_fedata
- remove addr from backend_connect
- remove priv->work, add comment about theoretical race
- use IPPROTO_IP
- refactor active socket allocation in a single new function
Changes in v2:
- allocate one ioworker per socket (rather than 1 per vcpu)
- rename privs to frontends
- add newlines
- define "1" in the public header
- better error returns in pvcalls_back_probe
- do not set XenbusStateClosed twice in set_backend_state
- add more comments
- replace rw_semaphore with semaphore
- rename pvcallss to socket_lock
- move xenbus_map_ring_valloc closer to first use in backend_connect
- use more traditional return codes from pvcalls_back_handle_cmd and
callees
- remove useless dev == NULL checks
- replace lock_sock with more appropriate and fine grained socket locks
Stefano Stabellini (18):
xen: introduce the pvcalls interface header
xen/pvcalls: introduce the pvcalls xenbus backend
xen/pvcalls: initialize the module and register the xenbus backend
xen/pvcalls: xenbus state handling
xen/pvcalls: connect to a frontend
xen/pvcalls: handle commands from the frontend
xen/pvcalls: implement socket command
xen/pvcalls: implement connect command
xen/pvcalls: implement bind command
xen/pvcalls: implement listen command
xen/pvcalls: implement accept command
xen/pvcalls: implement poll command
xen/pvcalls: implement release command
xen/pvcalls: disconnect and module_exit
xen/pvcalls: implement the ioworker functions
xen/pvcalls: implement read
xen/pvcalls: implement write
xen: introduce a Kconfig option to enable the pvcalls backend
drivers/xen/Kconfig | 12 +
drivers/xen/Makefile | 1 +
drivers/xen/pvcalls-back.c | 1236 ++++++++++++++++++++++++++++++++++++
include/xen/interface/io/pvcalls.h | 121 ++++
include/xen/interface/io/ring.h | 2 +
5 files changed, 1372 insertions(+)
create mode 100644 drivers/xen/pvcalls-back.c
create mode 100644 include/xen/interface/io/pvcalls.h
[toc] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-06 00:00 +0200 |
| Subject | [PATCH v7 01/18] xen: introduce the pvcalls interface header |
| Message-ID | <u00v0-3uT-11@gated-at.bofh.it> |
| In reply to | #1681891 |
Introduce the C header file which defines the PV Calls interface. It is
imported from xen/include/public/io/pvcalls.h.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
CC: konrad.wilk@oracle.com
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
include/xen/interface/io/pvcalls.h | 121 +++++++++++++++++++++++++++++++++++++
include/xen/interface/io/ring.h | 2 +
2 files changed, 123 insertions(+)
create mode 100644 include/xen/interface/io/pvcalls.h
diff --git a/include/xen/interface/io/pvcalls.h b/include/xen/interface/io/pvcalls.h
new file mode 100644
index 0000000..ccf97b8
--- /dev/null
+++ b/include/xen/interface/io/pvcalls.h
@@ -0,0 +1,121 @@
+#ifndef __XEN_PUBLIC_IO_XEN_PVCALLS_H__
+#define __XEN_PUBLIC_IO_XEN_PVCALLS_H__
+
+#include <linux/net.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/grant_table.h>
+
+/* "1" means socket, connect, release, bind, listen, accept and poll */
+#define XENBUS_FUNCTIONS_CALLS "1"
+
+/*
+ * See docs/misc/pvcalls.markdown in xen.git for the full specification:
+ * https://xenbits.xen.org/docs/unstable/misc/pvcalls.html
+ */
+struct pvcalls_data_intf {
+ RING_IDX in_cons, in_prod, in_error;
+
+ uint8_t pad1[52];
+
+ RING_IDX out_cons, out_prod, out_error;
+
+ uint8_t pad2[52];
+
+ RING_IDX ring_order;
+ grant_ref_t ref[];
+};
+DEFINE_XEN_FLEX_RING(pvcalls);
+
+#define PVCALLS_SOCKET 0
+#define PVCALLS_CONNECT 1
+#define PVCALLS_RELEASE 2
+#define PVCALLS_BIND 3
+#define PVCALLS_LISTEN 4
+#define PVCALLS_ACCEPT 5
+#define PVCALLS_POLL 6
+
+struct xen_pvcalls_request {
+ uint32_t req_id; /* private to guest, echoed in response */
+ uint32_t cmd; /* command to execute */
+ union {
+ struct xen_pvcalls_socket {
+ uint64_t id;
+ uint32_t domain;
+ uint32_t type;
+ uint32_t protocol;
+ } socket;
+ struct xen_pvcalls_connect {
+ uint64_t id;
+ uint8_t addr[28];
+ uint32_t len;
+ uint32_t flags;
+ grant_ref_t ref;
+ uint32_t evtchn;
+ } connect;
+ struct xen_pvcalls_release {
+ uint64_t id;
+ uint8_t reuse;
+ } release;
+ struct xen_pvcalls_bind {
+ uint64_t id;
+ uint8_t addr[28];
+ uint32_t len;
+ } bind;
+ struct xen_pvcalls_listen {
+ uint64_t id;
+ uint32_t backlog;
+ } listen;
+ struct xen_pvcalls_accept {
+ uint64_t id;
+ uint64_t id_new;
+ grant_ref_t ref;
+ uint32_t evtchn;
+ } accept;
+ struct xen_pvcalls_poll {
+ uint64_t id;
+ } poll;
+ /* dummy member to force sizeof(struct xen_pvcalls_request)
+ * to match across archs */
+ struct xen_pvcalls_dummy {
+ uint8_t dummy[56];
+ } dummy;
+ } u;
+};
+
+struct xen_pvcalls_response {
+ uint32_t req_id;
+ uint32_t cmd;
+ int32_t ret;
+ uint32_t pad;
+ union {
+ struct _xen_pvcalls_socket {
+ uint64_t id;
+ } socket;
+ struct _xen_pvcalls_connect {
+ uint64_t id;
+ } connect;
+ struct _xen_pvcalls_release {
+ uint64_t id;
+ } release;
+ struct _xen_pvcalls_bind {
+ uint64_t id;
+ } bind;
+ struct _xen_pvcalls_listen {
+ uint64_t id;
+ } listen;
+ struct _xen_pvcalls_accept {
+ uint64_t id;
+ } accept;
+ struct _xen_pvcalls_poll {
+ uint64_t id;
+ } poll;
+ struct _xen_pvcalls_dummy {
+ uint8_t dummy[8];
+ } dummy;
+ } u;
+};
+
+DEFINE_RING_TYPES(xen_pvcalls, struct xen_pvcalls_request,
+ struct xen_pvcalls_response);
+
+#endif
diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h
index c794568..e547088 100644
--- a/include/xen/interface/io/ring.h
+++ b/include/xen/interface/io/ring.h
@@ -9,6 +9,8 @@
#ifndef __XEN_PUBLIC_IO_RING_H__
#define __XEN_PUBLIC_IO_RING_H__
+#include <xen/interface/grant_table.h>
+
typedef unsigned int RING_IDX;
/* Round a 32-bit unsigned constant down to the nearest power of two. */
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-06 00:00 +0200 |
| Subject | [PATCH v7 04/18] xen/pvcalls: xenbus state handling |
| Message-ID | <u00v1-3uT-49@gated-at.bofh.it> |
| In reply to | #1681892 |
Introduce the code to handle xenbus state changes.
Implement the probe function for the pvcalls backend. Write the
supported versions, max-page-order and function-calls nodes to xenstore,
as required by the protocol.
Introduce stub functions for disconnecting/connecting to a frontend.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-back.c | 155 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 155 insertions(+)
diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c
index 9044cf2..72d2fce 100644
--- a/drivers/xen/pvcalls-back.c
+++ b/drivers/xen/pvcalls-back.c
@@ -25,20 +25,175 @@
#include <xen/xenbus.h>
#include <xen/interface/io/pvcalls.h>
+#define PVCALLS_VERSIONS "1"
+#define MAX_RING_ORDER XENBUS_MAX_RING_GRANT_ORDER
+
struct pvcalls_back_global {
struct list_head frontends;
struct semaphore frontends_lock;
} pvcalls_back_global;
+static int backend_connect(struct xenbus_device *dev)
+{
+ return 0;
+}
+
+static int backend_disconnect(struct xenbus_device *dev)
+{
+ return 0;
+}
+
static int pvcalls_back_probe(struct xenbus_device *dev,
const struct xenbus_device_id *id)
{
+ int err, abort;
+ struct xenbus_transaction xbt;
+
+again:
+ abort = 1;
+
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ pr_warn("%s cannot create xenstore transaction\n", __func__);
+ return err;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "versions", "%s",
+ PVCALLS_VERSIONS);
+ if (err) {
+ pr_warn("%s write out 'versions' failed\n", __func__);
+ goto abort;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "max-page-order", "%u",
+ MAX_RING_ORDER);
+ if (err) {
+ pr_warn("%s write out 'max-page-order' failed\n", __func__);
+ goto abort;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "function-calls",
+ XENBUS_FUNCTIONS_CALLS);
+ if (err) {
+ pr_warn("%s write out 'function-calls' failed\n", __func__);
+ goto abort;
+ }
+
+ abort = 0;
+abort:
+ err = xenbus_transaction_end(xbt, abort);
+ if (err) {
+ if (err == -EAGAIN && !abort)
+ goto again;
+ pr_warn("%s cannot complete xenstore transaction\n", __func__);
+ return err;
+ }
+
+ if (abort)
+ return -EFAULT;
+
+ xenbus_switch_state(dev, XenbusStateInitWait);
+
return 0;
}
+static void set_backend_state(struct xenbus_device *dev,
+ enum xenbus_state state)
+{
+ while (dev->state != state) {
+ switch (dev->state) {
+ case XenbusStateClosed:
+ switch (state) {
+ case XenbusStateInitWait:
+ case XenbusStateConnected:
+ xenbus_switch_state(dev, XenbusStateInitWait);
+ break;
+ case XenbusStateClosing:
+ xenbus_switch_state(dev, XenbusStateClosing);
+ break;
+ default:
+ __WARN();
+ }
+ break;
+ case XenbusStateInitWait:
+ case XenbusStateInitialised:
+ switch (state) {
+ case XenbusStateConnected:
+ backend_connect(dev);
+ xenbus_switch_state(dev, XenbusStateConnected);
+ break;
+ case XenbusStateClosing:
+ case XenbusStateClosed:
+ xenbus_switch_state(dev, XenbusStateClosing);
+ break;
+ default:
+ __WARN();
+ }
+ break;
+ case XenbusStateConnected:
+ switch (state) {
+ case XenbusStateInitWait:
+ case XenbusStateClosing:
+ case XenbusStateClosed:
+ down(&pvcalls_back_global.frontends_lock);
+ backend_disconnect(dev);
+ up(&pvcalls_back_global.frontends_lock);
+ xenbus_switch_state(dev, XenbusStateClosing);
+ break;
+ default:
+ __WARN();
+ }
+ break;
+ case XenbusStateClosing:
+ switch (state) {
+ case XenbusStateInitWait:
+ case XenbusStateConnected:
+ case XenbusStateClosed:
+ xenbus_switch_state(dev, XenbusStateClosed);
+ break;
+ default:
+ __WARN();
+ }
+ break;
+ default:
+ __WARN();
+ }
+ }
+}
+
static void pvcalls_back_changed(struct xenbus_device *dev,
enum xenbus_state frontend_state)
{
+ switch (frontend_state) {
+ case XenbusStateInitialising:
+ set_backend_state(dev, XenbusStateInitWait);
+ break;
+
+ case XenbusStateInitialised:
+ case XenbusStateConnected:
+ set_backend_state(dev, XenbusStateConnected);
+ break;
+
+ case XenbusStateClosing:
+ set_backend_state(dev, XenbusStateClosing);
+ break;
+
+ case XenbusStateClosed:
+ set_backend_state(dev, XenbusStateClosed);
+ if (xenbus_dev_is_online(dev))
+ break;
+ device_unregister(&dev->dev);
+ break;
+ case XenbusStateUnknown:
+ set_backend_state(dev, XenbusStateClosed);
+ device_unregister(&dev->dev);
+ break;
+
+ default:
+ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+ frontend_state);
+ break;
+ }
}
static int pvcalls_back_remove(struct xenbus_device *dev)
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Juergen Gross <jgross@suse.com> |
|---|---|
| Date | 2017-07-06 09:20 +0200 |
| Subject | Re: [PATCH v7 04/18] xen/pvcalls: xenbus state handling |
| Message-ID | <u09eV-1bF-1@gated-at.bofh.it> |
| In reply to | #1681893 |
On 05/07/17 23:50, Stefano Stabellini wrote: > Introduce the code to handle xenbus state changes. > > Implement the probe function for the pvcalls backend. Write the > supported versions, max-page-order and function-calls nodes to xenstore, > as required by the protocol. > > Introduce stub functions for disconnecting/connecting to a frontend. > > Signed-off-by: Stefano Stabellini <stefano@aporeto.com> > Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Reviewed-by: Juergen Gross <jgross@suse.com> Thanks, Juergen
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-06 00:00 +0200 |
| Subject | [PATCH v7 14/18] xen/pvcalls: disconnect and module_exit |
| Message-ID | <u00v2-3uT-51@gated-at.bofh.it> |
| In reply to | #1681892 |
Implement backend_disconnect. Call pvcalls_back_release_active on active
sockets and pvcalls_back_release_passive on passive sockets.
Implement module_exit by calling backend_disconnect on frontend
connections.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-back.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c
index 5ac26d8..214356c 100644
--- a/drivers/xen/pvcalls-back.c
+++ b/drivers/xen/pvcalls-back.c
@@ -804,6 +804,42 @@ static int backend_connect(struct xenbus_device *dev)
static int backend_disconnect(struct xenbus_device *dev)
{
+ struct pvcalls_fedata *fedata;
+ struct sock_mapping *map, *n;
+ struct sockpass_mapping *mappass;
+ struct radix_tree_iter iter;
+ void **slot;
+
+
+ fedata = dev_get_drvdata(&dev->dev);
+
+ down(&fedata->socket_lock);
+ list_for_each_entry_safe(map, n, &fedata->socket_mappings, list) {
+ list_del(&map->list);
+ pvcalls_back_release_active(dev, fedata, map);
+ }
+
+ radix_tree_for_each_slot(slot, &fedata->socketpass_mappings, &iter, 0) {
+ mappass = radix_tree_deref_slot(slot);
+ if (!mappass)
+ continue;
+ if (radix_tree_exception(mappass)) {
+ if (radix_tree_deref_retry(mappass))
+ slot = radix_tree_iter_retry(&iter);
+ } else {
+ radix_tree_delete(&fedata->socketpass_mappings, mappass->id);
+ pvcalls_back_release_passive(dev, fedata, mappass);
+ }
+ }
+ up(&fedata->socket_lock);
+
+ unbind_from_irqhandler(fedata->irq, dev);
+ xenbus_unmap_ring_vfree(dev, fedata->sring);
+
+ list_del(&fedata->list);
+ kfree(fedata);
+ dev_set_drvdata(&dev->dev, NULL);
+
return 0;
}
@@ -1000,3 +1036,19 @@ static int __init pvcalls_back_init(void)
return 0;
}
module_init(pvcalls_back_init);
+
+static void __exit pvcalls_back_fin(void)
+{
+ struct pvcalls_fedata *fedata, *nfedata;
+
+ down(&pvcalls_back_global.frontends_lock);
+ list_for_each_entry_safe(fedata, nfedata, &pvcalls_back_global.frontends,
+ list) {
+ backend_disconnect(fedata->dev);
+ }
+ up(&pvcalls_back_global.frontends_lock);
+
+ xenbus_unregister_driver(&pvcalls_back_driver);
+}
+
+module_exit(pvcalls_back_fin);
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Juergen Gross <jgross@suse.com> |
|---|---|
| Date | 2017-07-06 09:30 +0200 |
| Subject | Re: [PATCH v7 14/18] xen/pvcalls: disconnect and module_exit |
| Message-ID | <u09oD-1hk-25@gated-at.bofh.it> |
| In reply to | #1681894 |
On 05/07/17 23:50, Stefano Stabellini wrote: > Implement backend_disconnect. Call pvcalls_back_release_active on active > sockets and pvcalls_back_release_passive on passive sockets. > > Implement module_exit by calling backend_disconnect on frontend > connections. > > Signed-off-by: Stefano Stabellini <stefano@aporeto.com> Reviewed-by: Juergen Gross <jgross@suse.com> Thanks, Juergen
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-06 00:00 +0200 |
| Subject | [PATCH v7 07/18] xen/pvcalls: implement socket command |
| Message-ID | <u00v2-3uT-61@gated-at.bofh.it> |
| In reply to | #1681892 |
Just reply with success to the other end for now. Delay the allocation
of the actual socket to bind and/or connect.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-back.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c
index f55df4d..1f176eb 100644
--- a/drivers/xen/pvcalls-back.c
+++ b/drivers/xen/pvcalls-back.c
@@ -12,12 +12,17 @@
* GNU General Public License for more details.
*/
+#include <linux/inet.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/radix-tree.h>
#include <linux/module.h>
#include <linux/semaphore.h>
#include <linux/wait.h>
+#include <net/sock.h>
+#include <net/inet_common.h>
+#include <net/inet_connection_sock.h>
+#include <net/request_sock.h>
#include <xen/events.h>
#include <xen/grant_table.h>
@@ -52,6 +57,28 @@ struct pvcalls_fedata {
static int pvcalls_back_socket(struct xenbus_device *dev,
struct xen_pvcalls_request *req)
{
+ struct pvcalls_fedata *fedata;
+ int ret;
+ struct xen_pvcalls_response *rsp;
+
+ fedata = dev_get_drvdata(&dev->dev);
+
+ if (req->u.socket.domain != AF_INET ||
+ req->u.socket.type != SOCK_STREAM ||
+ (req->u.socket.protocol != IPPROTO_IP &&
+ req->u.socket.protocol != AF_INET))
+ ret = -EAFNOSUPPORT;
+ else
+ ret = 0;
+
+ /* leave the actual socket allocation for later */
+
+ rsp = RING_GET_RESPONSE(&fedata->ring, fedata->ring.rsp_prod_pvt++);
+ rsp->req_id = req->req_id;
+ rsp->cmd = req->cmd;
+ rsp->u.socket.id = req->u.socket.id;
+ rsp->ret = ret;
+
return 0;
}
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-06 00:00 +0200 |
| Subject | [PATCH v7 13/18] xen/pvcalls: implement release command |
| Message-ID | <u00v2-3uT-57@gated-at.bofh.it> |
| In reply to | #1681892 |
Release both active and passive sockets. For active sockets, make sure
to avoid possible conflicts with the ioworker reading/writing to those
sockets concurrently. Set map->release to let the ioworker know
atomically that the socket will be released soon, then wait until the
ioworker finishes (flush_work).
Unmap indexes pages and data rings.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-back.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c
index d8476fe..5ac26d8 100644
--- a/drivers/xen/pvcalls-back.c
+++ b/drivers/xen/pvcalls-back.c
@@ -272,12 +272,80 @@ static int pvcalls_back_release_active(struct xenbus_device *dev,
struct pvcalls_fedata *fedata,
struct sock_mapping *map)
{
+ disable_irq(map->irq);
+ if (map->sock->sk != NULL) {
+ write_lock_bh(&map->sock->sk->sk_callback_lock);
+ map->sock->sk->sk_user_data = NULL;
+ map->sock->sk->sk_data_ready = map->saved_data_ready;
+ write_unlock_bh(&map->sock->sk->sk_callback_lock);
+ }
+
+ atomic_set(&map->release, 1);
+ flush_work(&map->ioworker.register_work);
+
+ xenbus_unmap_ring_vfree(dev, map->bytes);
+ xenbus_unmap_ring_vfree(dev, (void *)map->ring);
+ unbind_from_irqhandler(map->irq, map);
+
+ sock_release(map->sock);
+ kfree(map);
+
+ return 0;
+}
+
+static int pvcalls_back_release_passive(struct xenbus_device *dev,
+ struct pvcalls_fedata *fedata,
+ struct sockpass_mapping *mappass)
+{
+ if (mappass->sock->sk != NULL) {
+ write_lock_bh(&mappass->sock->sk->sk_callback_lock);
+ mappass->sock->sk->sk_user_data = NULL;
+ mappass->sock->sk->sk_data_ready = mappass->saved_data_ready;
+ write_unlock_bh(&mappass->sock->sk->sk_callback_lock);
+ }
+ sock_release(mappass->sock);
+ flush_workqueue(mappass->wq);
+ destroy_workqueue(mappass->wq);
+ kfree(mappass);
+
return 0;
}
static int pvcalls_back_release(struct xenbus_device *dev,
struct xen_pvcalls_request *req)
{
+ struct pvcalls_fedata *fedata;
+ struct sock_mapping *map, *n;
+ struct sockpass_mapping *mappass;
+ int ret = 0;
+ struct xen_pvcalls_response *rsp;
+
+ fedata = dev_get_drvdata(&dev->dev);
+
+ down(&fedata->socket_lock);
+ list_for_each_entry_safe(map, n, &fedata->socket_mappings, list) {
+ if (map->id == req->u.release.id) {
+ list_del(&map->list);
+ up(&fedata->socket_lock);
+ ret = pvcalls_back_release_active(dev, fedata, map);
+ goto out;
+ }
+ }
+ mappass = radix_tree_lookup(&fedata->socketpass_mappings,
+ req->u.release.id);
+ if (mappass != NULL) {
+ radix_tree_delete(&fedata->socketpass_mappings, mappass->id);
+ up(&fedata->socket_lock);
+ ret = pvcalls_back_release_passive(dev, fedata, mappass);
+ } else
+ up(&fedata->socket_lock);
+
+out:
+ rsp = RING_GET_RESPONSE(&fedata->ring, fedata->ring.rsp_prod_pvt++);
+ rsp->req_id = req->req_id;
+ rsp->u.release.id = req->u.release.id;
+ rsp->cmd = req->cmd;
+ rsp->ret = ret;
return 0;
}
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-06 00:00 +0200 |
| Subject | [PATCH v7 15/18] xen/pvcalls: implement the ioworker functions |
| Message-ID | <u00v2-3uT-59@gated-at.bofh.it> |
| In reply to | #1681892 |
We have one ioworker per socket. Each ioworker goes through the list of
outstanding read/write requests. Once all requests have been dealt with,
it returns.
We use one atomic counter per socket for "read" operations and one
for "write" operations to keep track of the reads/writes to do.
We also use one atomic counter ("io") per ioworker to keep track of how
many outstanding requests we have in total assigned to the ioworker. The
ioworker finishes when there are none.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-back.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c
index 214356c..a5f11d5 100644
--- a/drivers/xen/pvcalls-back.c
+++ b/drivers/xen/pvcalls-back.c
@@ -96,8 +96,34 @@ static int pvcalls_back_release_active(struct xenbus_device *dev,
struct pvcalls_fedata *fedata,
struct sock_mapping *map);
+static void pvcalls_conn_back_read(void *opaque)
+{
+}
+
+static void pvcalls_conn_back_write(struct sock_mapping *map)
+{
+}
+
static void pvcalls_back_ioworker(struct work_struct *work)
{
+ struct pvcalls_ioworker *ioworker = container_of(work,
+ struct pvcalls_ioworker, register_work);
+ struct sock_mapping *map = container_of(ioworker, struct sock_mapping,
+ ioworker);
+
+ while (atomic_read(&map->io) > 0) {
+ if (atomic_read(&map->release) > 0) {
+ atomic_set(&map->release, 0);
+ return;
+ }
+
+ if (atomic_read(&map->read) > 0)
+ pvcalls_conn_back_read(map);
+ if (atomic_read(&map->write) > 0)
+ pvcalls_conn_back_write(map);
+
+ atomic_dec(&map->io);
+ }
}
static int pvcalls_back_socket(struct xenbus_device *dev,
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-06 00:00 +0200 |
| Subject | [PATCH v7 12/18] xen/pvcalls: implement poll command |
| Message-ID | <u00v2-3uT-55@gated-at.bofh.it> |
| In reply to | #1681892 |
Implement poll on passive sockets by requesting a delayed response with
mappass->reqcopy, and reply back when there is data on the passive
socket.
Poll on active socket is unimplemented as by the spec, as the frontend
should just wait for events and check the indexes on the indexes page.
Only support one outstanding poll (or accept) request for every passive
socket at any given time.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-back.c | 73 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)
diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c
index f0fdcd4..d8476fe 100644
--- a/drivers/xen/pvcalls-back.c
+++ b/drivers/xen/pvcalls-back.c
@@ -355,11 +355,33 @@ static void __pvcalls_back_accept(struct work_struct *work)
static void pvcalls_pass_sk_data_ready(struct sock *sock)
{
struct sockpass_mapping *mappass = sock->sk_user_data;
+ struct pvcalls_fedata *fedata;
+ struct xen_pvcalls_response *rsp;
+ unsigned long flags;
+ int notify;
if (mappass == NULL)
return;
- queue_work(mappass->wq, &mappass->register_work);
+ fedata = mappass->fedata;
+ spin_lock_irqsave(&mappass->copy_lock, flags);
+ if (mappass->reqcopy.cmd == PVCALLS_POLL) {
+ rsp = RING_GET_RESPONSE(&fedata->ring, fedata->ring.rsp_prod_pvt++);
+ rsp->req_id = mappass->reqcopy.req_id;
+ rsp->u.poll.id = mappass->reqcopy.u.poll.id;
+ rsp->cmd = mappass->reqcopy.cmd;
+ rsp->ret = 0;
+
+ mappass->reqcopy.cmd = 0;
+ spin_unlock_irqrestore(&mappass->copy_lock, flags);
+
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&fedata->ring, notify);
+ if (notify)
+ notify_remote_via_irq(mappass->fedata->irq);
+ } else {
+ spin_unlock_irqrestore(&mappass->copy_lock, flags);
+ queue_work(mappass->wq, &mappass->register_work);
+ }
}
static int pvcalls_back_bind(struct xenbus_device *dev,
@@ -502,6 +524,55 @@ static int pvcalls_back_accept(struct xenbus_device *dev,
static int pvcalls_back_poll(struct xenbus_device *dev,
struct xen_pvcalls_request *req)
{
+ struct pvcalls_fedata *fedata;
+ struct sockpass_mapping *mappass;
+ struct xen_pvcalls_response *rsp;
+ struct inet_connection_sock *icsk;
+ struct request_sock_queue *queue;
+ unsigned long flags;
+ int ret;
+ bool data;
+
+ fedata = dev_get_drvdata(&dev->dev);
+
+ down(&fedata->socket_lock);
+ mappass = radix_tree_lookup(&fedata->socketpass_mappings, req->u.poll.id);
+ up(&fedata->socket_lock);
+ if (mappass == NULL)
+ return -EINVAL;
+
+ /*
+ * Limitation of the current implementation: only support one
+ * concurrent accept or poll call on one socket.
+ */
+ spin_lock_irqsave(&mappass->copy_lock, flags);
+ if (mappass->reqcopy.cmd != 0) {
+ ret = -EINTR;
+ goto out;
+ }
+
+ mappass->reqcopy = *req;
+ icsk = inet_csk(mappass->sock->sk);
+ queue = &icsk->icsk_accept_queue;
+ data = queue->rskq_accept_head != NULL;
+ if (data) {
+ mappass->reqcopy.cmd = 0;
+ ret = 0;
+ goto out;
+ }
+ spin_unlock_irqrestore(&mappass->copy_lock, flags);
+
+ /* Tell the caller we don't need to send back a notification yet */
+ return -1;
+
+out:
+ spin_unlock_irqrestore(&mappass->copy_lock, flags);
+
+ rsp = RING_GET_RESPONSE(&fedata->ring, fedata->ring.rsp_prod_pvt++);
+ rsp->req_id = req->req_id;
+ rsp->cmd = req->cmd;
+ rsp->u.poll.id = req->u.poll.id;
+ rsp->ret = ret;
return 0;
}
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-07-06 00:00 +0200 |
| Subject | [PATCH v7 03/18] xen/pvcalls: initialize the module and register the xenbus backend |
| Message-ID | <u00v2-3uT-63@gated-at.bofh.it> |
| In reply to | #1681892 |
Keep a list of connected frontends. Use a semaphore to protect list
accesses.
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
---
drivers/xen/pvcalls-back.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c
index f3d0daa..9044cf2 100644
--- a/drivers/xen/pvcalls-back.c
+++ b/drivers/xen/pvcalls-back.c
@@ -25,6 +25,11 @@
#include <xen/xenbus.h>
#include <xen/interface/io/pvcalls.h>
+struct pvcalls_back_global {
+ struct list_head frontends;
+ struct semaphore frontends_lock;
+} pvcalls_back_global;
+
static int pvcalls_back_probe(struct xenbus_device *dev,
const struct xenbus_device_id *id)
{
@@ -59,3 +64,20 @@ static int pvcalls_back_uevent(struct xenbus_device *xdev,
.uevent = pvcalls_back_uevent,
.otherend_changed = pvcalls_back_changed,
};
+
+static int __init pvcalls_back_init(void)
+{
+ int ret;
+
+ if (!xen_domain())
+ return -ENODEV;
+
+ ret = xenbus_register_backend(&pvcalls_back_driver);
+ if (ret < 0)
+ return ret;
+
+ sema_init(&pvcalls_back_global.frontends_lock, 1);
+ INIT_LIST_HEAD(&pvcalls_back_global.frontends);
+ return 0;
+}
+module_init(pvcalls_back_init);
--
1.9.1
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web