|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH 5/9] plat/xen/drivers/9p: Connect to xenbus device
Reviewed-by: Costin Lupu <costin.lupu@xxxxxxxxx>
On 9/7/19 1:21 PM, Vlad-Andrei BĂDOIU (78692) wrote:
> From: Cristian Banu <cristb@xxxxxxxxx>
>
> This patch implements ring allocation, reference granting and event channel
> allocation, with the purpose of establishing the connection to the
> backend 9pfs device.
>
> Signed-off-by: Cristian Banu <cristb@xxxxxxxxx>
> ---
> plat/xen/Config.uk | 19 ++-
> plat/xen/drivers/9p/9pfront.c | 167 +++++++++++++++++++++++++
> plat/xen/drivers/9p/9pfront.h | 29 +++++
> plat/xen/drivers/9p/9pfront_xb.h | 12 ++
> plat/xen/drivers/9p/9pfront_xs.c | 204 +++++++++++++++++++++++++++++++
> 5 files changed, 430 insertions(+), 1 deletion(-)
>
> diff --git a/plat/xen/Config.uk b/plat/xen/Config.uk
> index dfffb320..1ad7f7e4 100644
> --- a/plat/xen/Config.uk
> +++ b/plat/xen/Config.uk
> @@ -73,11 +73,28 @@ menu "Xenbus Drivers"
> depends on XEN_XENBUS
> depends on XEN_GNTTAB
>
> -config XEN_9PFRONT
> +menuconfig XEN_9PFRONT
> bool "Xenbus 9pfront Driver"
> default n
> depends on LIBUK9P
> help
> Driver for 9pfs devices
> +
> +config XEN_9PFRONT_NB_RINGS
> + int "Xen 9P ring number"
> + default 2
> + depends on XEN_9PFRONT
> + help
> + Number of rings to allocate.
> + Will be clamped to the maximum value allowed by the backend.
> +
> +config XEN_9PFRONT_RING_ORDER
> + int "Xen 9P ring order"
> + default 6
> + depends on XEN_9PFRONT
> + help
> + Ring order for xen 9P devices. Orders of 0, 1, 2, ..., 9 will
> + create rings of size 4K, 8K, 16K, ..., 2M respectively.
> + Will be clamped to the maximum value allowed by the backend.
> endmenu
> endif
> diff --git a/plat/xen/drivers/9p/9pfront.c b/plat/xen/drivers/9p/9pfront.c
> index f289cd05..3898cb85 100644
> --- a/plat/xen/drivers/9p/9pfront.c
> +++ b/plat/xen/drivers/9p/9pfront.c
> @@ -32,12 +32,15 @@
> * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
> */
>
> +#include <stdbool.h>
> #include <uk/config.h>
> #include <uk/alloc.h>
> #include <uk/assert.h>
> #include <uk/essentials.h>
> #include <uk/list.h>
> #include <uk/plat/spinlock.h>
> +#include <xen-x86/mm.h>
> +#include <xen-x86/irq.h>
> #include <xenbus/xenbus.h>
>
> #include "9pfront_xb.h"
> @@ -48,6 +51,142 @@ static struct uk_alloc *a;
> static UK_LIST_HEAD(p9front_device_list);
> static DEFINE_SPINLOCK(p9front_device_list_lock);
>
> +static void p9front_handler(evtchn_port_t evtchn __unused,
> + struct __regs *regs __unused,
> + void *arg __unused)
> +{
> +}
> +
> +static void p9front_free_dev_ring(struct p9front_dev *p9fdev, int idx)
> +{
> + struct p9front_dev_ring *ring = &p9fdev->rings[idx];
> + int i;
> +
> + UK_ASSERT(ring->initialized);
> +
> + unbind_evtchn(ring->evtchn);
> + for (i = 0; i < (1 << p9fdev->ring_order); i++)
> + gnttab_end_access(ring->intf->ref[i]);
> + uk_pfree(a, ring->data.in,
> + p9fdev->ring_order + XEN_PAGE_SHIFT - PAGE_SHIFT);
> + gnttab_end_access(ring->ref);
> + uk_pfree(a, ring->intf, 0);
> + ring->initialized = false;
> +}
> +
> +static void p9front_free_dev_rings(struct p9front_dev *p9fdev)
> +{
> + int i;
> +
> + for (i = 0; i < p9fdev->nb_rings; i++) {
> + if (!p9fdev->rings[i].initialized)
> + continue;
> + p9front_free_dev_ring(p9fdev, i);
> + }
> +
> + uk_free(a, p9fdev->rings);
> +}
> +
> +static int p9front_allocate_dev_ring(struct p9front_dev *p9fdev, int idx)
> +{
> + struct xenbus_device *xendev = p9fdev->xendev;
> + struct p9front_dev_ring *ring;
> + int rc, i;
> + void *data_bytes;
> +
> + /* Sanity checks. */
> + UK_ASSERT(idx >= 0 && idx < p9fdev->nb_rings);
> +
> + ring = &p9fdev->rings[idx];
> + UK_ASSERT(!ring->initialized);
> +
> + ukarch_spin_lock_init(&ring->spinlock);
> + ring->dev = p9fdev;
> +
> + /* Allocate ring intf page. */
> + ring->intf = uk_palloc(a, 0);
> + if (!ring->intf) {
> + rc = -ENOMEM;
> + goto out;
> + }
> + memset(ring->intf, 0, PAGE_SIZE);
> +
> + /* Grant access to the allocated page to the backend. */
> + ring->ref = gnttab_grant_access(xendev->otherend_id,
> + virt_to_mfn(ring->intf), 0);
> + UK_ASSERT(ring->ref != GRANT_INVALID_REF);
> +
> + /* Allocate memory for the data. */
> + data_bytes = uk_palloc(a,
> + p9fdev->ring_order + XEN_PAGE_SHIFT - PAGE_SHIFT);
> + if (!data_bytes) {
> + rc = -ENOMEM;
> + goto out_free_intf;
> + }
> + memset(data_bytes, 0, XEN_FLEX_RING_SIZE(p9fdev->ring_order) * 2);
> +
> + /* Grant refs to the entire data. */
> + for (i = 0; i < (1 << p9fdev->ring_order); i++) {
> + ring->intf->ref[i] = gnttab_grant_access(xendev->otherend_id,
> + virt_to_mfn(data_bytes) + i, 0);
> + UK_ASSERT(ring->intf->ref[i] != GRANT_INVALID_REF);
> + }
> +
> + ring->intf->ring_order = p9fdev->ring_order;
> + ring->data.in = data_bytes;
> + ring->data.out = data_bytes + XEN_FLEX_RING_SIZE(p9fdev->ring_order);
> +
> + /* Allocate event channel. */
> + rc = evtchn_alloc_unbound(xendev->otherend_id, p9front_handler, ring,
> + &ring->evtchn);
> + if (rc) {
> + uk_pr_err(DRIVER_NAME": Error creating evt channel: %d\n", rc);
> + goto out_free_grants;
> + }
> +
> + unmask_evtchn(ring->evtchn);
> +
> + /* Mark ring as initialized. */
> + ring->initialized = true;
> +
> + return 0;
> +
> +out_free_grants:
> + for (i = 0; i < (1 << p9fdev->ring_order); i++)
> + gnttab_end_access(ring->intf->ref[i]);
> + uk_pfree(a, data_bytes,
> + p9fdev->ring_order + XEN_PAGE_SHIFT - PAGE_SHIFT);
> +out_free_intf:
> + gnttab_end_access(ring->ref);
> + uk_pfree(a, ring->intf, 0);
> +out:
> + return rc;
> +}
> +
> +static int p9front_allocate_dev_rings(struct p9front_dev *p9fdev)
> +{
> + int rc, i;
> +
> + p9fdev->rings = uk_calloc(a, p9fdev->nb_rings, sizeof(*p9fdev->rings));
> + if (!p9fdev->rings) {
> + rc = -ENOMEM;
> + goto out;
> + }
> +
> + for (i = 0; i < p9fdev->nb_rings; i++) {
> + rc = p9front_allocate_dev_ring(p9fdev, i);
> + if (rc)
> + goto out_free;
> + }
> +
> + return 0;
> +
> +out_free:
> + p9front_free_dev_rings(p9fdev);
> +out:
> + return rc;
> +}
> +
> static int p9front_drv_init(struct uk_alloc *drv_allocator)
> {
> if (!drv_allocator)
> @@ -75,11 +214,39 @@ static int p9front_add_dev(struct xenbus_device *xendev)
> if (rc)
> goto out_free;
>
> + uk_pr_info("Initialized 9pfront dev: tag=%s,maxrings=%d,maxorder=%d\n",
> + p9fdev->tag, p9fdev->nb_max_rings, p9fdev->max_ring_page_order);
> +
> + p9fdev->nb_rings = MIN(CONFIG_XEN_9PFRONT_NB_RINGS,
> + p9fdev->nb_max_rings);
> + p9fdev->ring_order = MIN(CONFIG_XEN_9PFRONT_RING_ORDER,
> + p9fdev->max_ring_page_order);
> +
> + rc = p9front_allocate_dev_rings(p9fdev);
> + if (rc) {
> + uk_pr_err(DRIVER_NAME": Could not initialize device rings:
> %d\n",
> + rc);
> + goto out_free;
> + }
> +
> + rc = p9front_xb_connect(p9fdev);
> + if (rc) {
> + uk_pr_err(DRIVER_NAME": Could not connect: %d\n", rc);
> + goto out_free_rings;
> + }
> +
> rc = 0;
> ukplat_spin_lock_irqsave(&p9front_device_list_lock, flags);
> uk_list_add(&p9fdev->_list, &p9front_device_list);
> ukplat_spin_unlock_irqrestore(&p9front_device_list_lock, flags);
>
> + uk_pr_info(DRIVER_NAME": Connected 9pfront dev:
> tag=%s,rings=%d,order=%d\n",
> + p9fdev->tag, p9fdev->nb_rings, p9fdev->ring_order);
> +
> + goto out;
> +
> +out_free_rings:
> + p9front_free_dev_rings(p9fdev);
> out_free:
> uk_free(a, p9fdev);
> out:
> diff --git a/plat/xen/drivers/9p/9pfront.h b/plat/xen/drivers/9p/9pfront.h
> index e77f315a..97c986d8 100644
> --- a/plat/xen/drivers/9p/9pfront.h
> +++ b/plat/xen/drivers/9p/9pfront.h
> @@ -35,9 +35,31 @@
> #ifndef __9PFRONT_H__
> #define __9PFRONT_H__
>
> +#include <string.h>
> #include <uk/config.h>
> #include <uk/essentials.h>
> #include <uk/list.h>
> +#include <uk/plat/spinlock.h>
> +#include <xen/io/9pfs.h>
> +#include <common/events.h>
> +#include <common/gnttab.h>
> +
> +struct p9front_dev_ring {
> + /* Backpointer to the p9front device. */
> + struct p9front_dev *dev;
> + /* The 9pfs data interface, as dedfined by the xen headers. */
> + struct xen_9pfs_data_intf *intf;
> + /* The 9pfs data, as defined by the xen headers. */
> + struct xen_9pfs_data data;
> + /* The event channel for this ring. */
> + evtchn_port_t evtchn;
> + /* Grant reference for the interface. */
> + grant_ref_t ref;
> + /* Per-ring spinlock. */
> + spinlock_t spinlock;
> + /* Tracks if this ring was initialized. */
> + bool initialized;
> +};
>
> struct p9front_dev {
> /* Xenbus device. */
> @@ -50,6 +72,13 @@ struct p9front_dev {
> int max_ring_page_order;
> /* Mount tag for this device, read from xenstore. */
> char *tag;
> +
> + /* Number of rings to use. */
> + int nb_rings;
> + /* Ring page order. */
> + int ring_order;
> + /* Device data rings. */
> + struct p9front_dev_ring *rings;
> };
>
> #endif /* __9PFRONT_H__ */
> diff --git a/plat/xen/drivers/9p/9pfront_xb.h
> b/plat/xen/drivers/9p/9pfront_xb.h
> index 224df7af..6e2697f9 100644
> --- a/plat/xen/drivers/9p/9pfront_xb.h
> +++ b/plat/xen/drivers/9p/9pfront_xb.h
> @@ -50,4 +50,16 @@
> */
> int p9front_xb_init(struct p9front_dev *p9fdev);
>
> +/**
> + * Connects to the backend by setting up the communication between
> + * frontend and backend.
> + *
> + * @param p9fdev
> + * 9P frontend device
> + * @return
> + * - (0): Successful.
> + * - (< 0): Error while committing XenStore transaction.
> + */
> +int p9front_xb_connect(struct p9front_dev *p9fdev);
> +
> #endif /* __9PFRONT_XB_H__ */
> diff --git a/plat/xen/drivers/9p/9pfront_xs.c
> b/plat/xen/drivers/9p/9pfront_xs.c
> index 5b5dc2e4..7185061c 100644
> --- a/plat/xen/drivers/9p/9pfront_xs.c
> +++ b/plat/xen/drivers/9p/9pfront_xs.c
> @@ -154,3 +154,207 @@ int p9front_xb_init(struct p9front_dev *p9fdev)
> out:
> return rc;
> }
> +
> +static int xs_write_ring(struct p9front_dev *p9fdev,
> + int i,
> + xenbus_transaction_t xbt)
> +{
> + struct xenbus_device *xendev = p9fdev->xendev;
> + struct p9front_dev_ring *ring = &p9fdev->rings[i];
> + char *path;
> + int rc;
> +
> + rc = asprintf(&path, "ring-ref%u", i);
> + if (rc < 0)
> + goto out;
> +
> + rc = xs_printf(xbt, xendev->nodename, path, "%u", ring->ref);
> + if (rc < 0)
> + goto out_path;
> +
> + free(path);
> + rc = asprintf(&path, "event-channel-%u", i);
> + if (rc < 0)
> + goto out;
> +
> + rc = xs_printf(xbt, xendev->nodename, path, "%u", ring->evtchn);
> + if (rc < 0)
> + goto out_path;
> +
> + rc = 0;
> +
> +out_path:
> + free(path);
> +out:
> + return rc;
> +}
> +
> +static void xs_delete_ring(struct p9front_dev *p9fdev,
> + int i,
> + xenbus_transaction_t xbt)
> +{
> + struct xenbus_device *xendev = p9fdev->xendev;
> + int rc;
> + char *path;
> +
> + rc = asprintf(&path, "%s/ring-ref%u", xendev->nodename, i);
> + if (rc < 0)
> + return;
> + xs_rm(xbt, path);
> + free(path);
> +
> + rc = asprintf(&path, "%s/event-channel-%u", xendev->nodename, i);
> + if (rc < 0)
> + return;
> + xs_rm(xbt, path);
> + free(path);
> +}
> +
> +static int p9front_xb_front_init(struct p9front_dev *p9fdev,
> + xenbus_transaction_t xbt)
> +{
> + int i, rc;
> + struct xenbus_device *xendev = p9fdev->xendev;
> +
> + /*
> + * Assert that the p9fdev ring information has been properly
> + * configured before attempting to connect.
> + */
> + UK_ASSERT(p9fdev->nb_rings != 0 && p9fdev->nb_rings <= 9);
> + UK_ASSERT(p9fdev->ring_order != 0);
> +
> + /*
> + * Assert that the p9fdev rings have been initialized.
> + */
> + UK_ASSERT(p9fdev->rings != NULL);
> +
> + /* Write version... */
> + rc = xs_printf(xbt, xendev->nodename, "version", "%u", 1);
> + if (rc < 0)
> + goto out;
> +
> + /* ... and num-rings... */
> + rc = xs_printf(xbt, xendev->nodename, "num-rings", "%u",
> + p9fdev->nb_rings);
> + if (rc < 0)
> + goto out;
> +
> + /* ... and each ring. */
> + for (i = 0; i < p9fdev->nb_rings; i++) {
> + rc = xs_write_ring(p9fdev, i, xbt);
> + if (rc)
> + goto out;
> + }
> +
> +out:
> + return rc;
> +}
> +
> +static void p9front_xb_front_fini(struct p9front_dev *p9fdev,
> + xenbus_transaction_t xbt)
> +{
> + int i;
> +
> + for (i = 0; i < p9fdev->nb_rings; i++)
> + xs_delete_ring(p9fdev, i, xbt);
> +}
> +
> +static int be_watch_start(struct xenbus_device *xendev, const char *path)
> +{
> + struct xenbus_watch *watch;
> +
> + watch = xs_watch_path(XBT_NIL, path);
> + if (PTRISERR(watch))
> + return PTR2ERR(watch);
> +
> + xendev->otherend_watch = watch;
> +
> + return 0;
> +}
> +
> +static int be_watch_stop(struct xenbus_device *xendev)
> +{
> + return xs_unwatch(XBT_NIL, xendev->otherend_watch);
> +}
> +
> +#define WAIT_BE_STATE_CHANGE_WHILE_COND(state_cond) \
> + do { \
> + rc = xs_read_integer(XBT_NIL, be_state_path, \
> + (int *) &be_state); \
> + if (rc) \
> + goto out; \
> + while (!rc && (state_cond)) \
> + rc = xenbus_wait_for_state_change(be_state_path, \
> + &be_state, xendev->otherend_watch); \
> + if (rc) \
> + goto out; \
> + } while (0)
> +
> +static int p9front_xb_wait_be_connect(struct p9front_dev *p9fdev)
> +{
> + struct xenbus_device *xendev = p9fdev->xendev;
> + char be_state_path[strlen(xendev->otherend) + sizeof("/state")];
> + XenbusState be_state;
> + int rc;
> +
> + sprintf(be_state_path, "%s/state", xendev->otherend);
> +
> + rc = be_watch_start(xendev, be_state_path);
> + if (rc)
> + goto out;
> +
> + WAIT_BE_STATE_CHANGE_WHILE_COND(be_state < XenbusStateConnected);
> +
> + if (be_state != XenbusStateConnected) {
> + uk_pr_err("Backend not available, state=%s\n",
> + xenbus_state_to_str(be_state));
> + be_watch_stop(xendev);
> + goto out;
> + }
> +
> + rc = xenbus_switch_state(XBT_NIL, xendev, XenbusStateConnected);
> + if (rc)
> + goto out;
> +
> +out:
> + return rc;
> +}
> +
> +int p9front_xb_connect(struct p9front_dev *p9fdev)
> +{
> + struct xenbus_device *xendev;
> + xenbus_transaction_t xbt;
> + int rc;
> +
> + UK_ASSERT(p9fdev != NULL);
> +
> + xendev = p9fdev->xendev;
> + UK_ASSERT(xendev != NULL);
> +
> +again:
> + rc = xs_transaction_start(&xbt);
> + if (rc)
> + goto abort_transaction;
> +
> + rc = p9front_xb_front_init(p9fdev, xbt);
> + if (rc)
> + goto abort_transaction;
> +
> + rc = xenbus_switch_state(xbt, xendev, XenbusStateInitialised);
> + if (rc)
> + goto abort_transaction;
> +
> + rc = xs_transaction_end(xbt, 0);
> + if (rc == -EAGAIN)
> + goto again;
> +
> + rc = p9front_xb_wait_be_connect(p9fdev);
> + if (rc)
> + p9front_xb_front_fini(p9fdev, XBT_NIL);
> +
> + return rc;
> +
> +abort_transaction:
> + xs_transaction_end(xbt, 1);
> + return rc;
> +}
>
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |