[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 |