[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.