[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH 13/17] plat/xen/drivers/blk: Send requests to backend
This patch introduces the request interface. The following steps are: -> find a free spot in the queue -> set the ring request -> notify Backend Supported operations are: read and write. Signed-off-by: Roxana Nicolescu <nicolescu.roxana1996@xxxxxxxxx> --- plat/xen/drivers/blk/blkfront.c | 182 +++++++++++++++++++++++++++++++++++++ plat/xen/drivers/blk/blkfront.h | 12 +++ plat/xen/drivers/blk/blkfront_xs.c | 4 + 3 files changed, 198 insertions(+) diff --git a/plat/xen/drivers/blk/blkfront.c b/plat/xen/drivers/blk/blkfront.c index c2f8e62d..112463a7 100644 --- a/plat/xen/drivers/blk/blkfront.c +++ b/plat/xen/drivers/blk/blkfront.c @@ -40,6 +40,8 @@ #include <uk/alloc.h> #include <uk/essentials.h> #include <uk/arch/limits.h> +#include <uk/page.h> +#include <uk/refcount.h> #include <uk/blkdev_driver.h> #include <xen-x86/mm.h> #include <xen-x86/mm_pv.h> @@ -49,6 +51,9 @@ #define DRIVER_NAME "xen-blkfront" +#define SECTOR_INDEX_IN_PAGE(a, sector_size) \ + (((a) & ~PAGE_MASK) / (sector_size)) + /* TODO Same interrupt macros we use in virtio-blk */ #define BLKFRONT_INTR_EN (1 << 0) #define BLKFRONT_INTR_EN_MASK (1) @@ -62,6 +67,182 @@ static struct uk_alloc *drv_allocator; +static void blkfront_ring_wr_init(struct blkif_request *ring_req, + __sector sector_size) +{ + uintptr_t start_sector, end_sector; + uint16_t nb_segments; + struct blkfront_request *blkfront_req; + struct uk_blkdev_request *req; + uintptr_t start_data, end_data; + uint16_t seg; + + UK_ASSERT(ring_req); + blkfront_req = (struct blkfront_request *)ring_req->id; + req = blkfront_req->req; + start_data = (uintptr_t)req->aio_buf; + end_data = (uintptr_t)req->aio_buf + req->nb_sectors * sector_size; + + /* Can't io non-sector-aligned buffer */ + UK_ASSERT(!(start_data & (sector_size - 1))); + + /* + * Find number of segments (pages) + * Being sector-size aligned buffer, it may not be aligned + * to page_size. If so, it is necessary to find the start and end + * of the pages the buffer is allocated, in order to calculate the + * number of pages the request has. + **/ + start_sector = round_pgdown(start_data); + end_sector = round_pgup(end_data); + nb_segments = (end_sector - start_sector) / PAGE_SIZE; + UK_ASSERT(nb_segments <= BLKIF_MAX_SEGMENTS_PER_REQUEST); + + /* Set ring request */ + ring_req->operation = (req->operation == UK_BLKDEV_WRITE) ? + BLKIF_OP_WRITE : BLKIF_OP_READ; + ring_req->nr_segments = nb_segments; + ring_req->sector_number = req->start_sector; + + /* Set for each page the offset of sectors used for request */ + for (seg = 0; seg < nb_segments; ++seg) { + ring_req->seg[seg].first_sect = 0; + ring_req->seg[seg].last_sect = PAGE_SIZE / sector_size - 1; + } + + ring_req->seg[0].first_sect = + SECTOR_INDEX_IN_PAGE(start_data, sector_size); + ring_req->seg[nb_segments - 1].last_sect = + SECTOR_INDEX_IN_PAGE(end_data - 1, sector_size); +} + +static int blkfront_request_write_wr(struct blkfront_request *blkfront_req, + struct blkif_request *ring_req) +{ + struct blkfront_dev *dev; + struct uk_blkdev_request *req; + struct uk_blkdev_cap *cap; + __sector sector_size; + int rc = 0; + + UK_ASSERT(blkfront_req); + req = blkfront_req->req; + dev = blkfront_req->queue->dev; + cap = &dev->blkdev.capabilities; + sector_size = cap->ssize; + if (req->operation == UK_BLKDEV_WRITE && cap->mode == O_RDONLY) + return -EPERM; + + if (req->aio_buf == NULL) + return -EINVAL; + + if (req->nb_sectors == 0) + return -EINVAL; + + if (req->start_sector + req->nb_sectors > cap->sectors) + return -EINVAL; + + if (req->nb_sectors > cap->max_sectors_per_req) + return -EINVAL; + + blkfront_ring_wr_init(ring_req, sector_size); + blkfront_req->nb_segments = ring_req->nr_segments; + + return rc; +} + +static int blkfront_queue_enqueue(struct uk_blkdev_queue *queue, + struct uk_blkdev_request *req) +{ + struct blkfront_request *blkfront_req; + struct blkfront_dev *dev; + RING_IDX ring_idx; + struct blkif_request *ring_req; + struct blkif_front_ring *ring; + int rc = 0; + + UK_ASSERT(queue); + UK_ASSERT(req); + + blkfront_req = uk_malloc(drv_allocator, sizeof(*blkfront_req)); + if (!blkfront_req) + return -ENOMEM; + + blkfront_req->req = req; + blkfront_req->queue = queue; + dev = queue->dev; + ring = &queue->ring; + ring_idx = ring->req_prod_pvt; + ring_req = RING_GET_REQUEST(ring, ring_idx); + ring_req->id = (uintptr_t) blkfront_req; + ring_req->handle = dev->handle; + + if (req->operation == UK_BLKDEV_READ || + req->operation == UK_BLKDEV_WRITE) + rc = blkfront_request_write_wr(blkfront_req, ring_req); + else + rc = -EINVAL; + + if (rc) + goto err_out; + + ring->req_prod_pvt = ring_idx + 1; + + /* Memory barrier */ + wmb(); +out: + return rc; + +err_out: + uk_free(drv_allocator, blkfront_req); + goto out; +} + +static int blkfront_submit_request(struct uk_blkdev *blkdev, + uint16_t queue_id, + struct uk_blkdev_request *req) +{ + int err = 0; + int notify; + int status = 0x0; + struct uk_blkdev_queue *queue; + struct blkfront_dev *dev; + + UK_ASSERT(blkdev != NULL); + UK_ASSERT(req != NULL); + + dev = to_blkfront(blkdev); + if (queue_id >= dev->nb_queues) { + uk_pr_err("Invalid queue identifier: %"__PRIu16"\n", queue_id); + return -EINVAL; + } + + queue = &dev->queues[queue_id]; + if (RING_FULL(&queue->ring)) { + uk_pr_err("Queue-%"PRIu16" is full\n", + queue_id); + return -EBUSY; + } + + err = blkfront_queue_enqueue(queue, req); + if (err) { + uk_pr_err("Failed to set ring req for %d op: %d\n", + req->operation, err); + return err; + } + + status |= UK_BLKDEV_STATUS_SUCCESS; + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&queue->ring, notify); + if (notify) { + err = notify_remote_via_evtchn(queue->evtchn); + if (err) + return err; + } + + status |= (!RING_FULL(&queue->ring)) ? UK_BLKDEV_STATUS_MORE : 0x0; + return status; +} + /* Returns 1 if more responses available */ static int blkfront_xen_ring_intr_enable(struct uk_blkdev_queue *queue) { @@ -394,6 +575,7 @@ static int blkfront_add_dev(struct xenbus_device *dev) return -ENOMEM; d->xendev = dev; + d->blkdev.submit_one = blkfront_submit_request; d->blkdev.dev_ops = &blkfront_ops; /* Xenbus initialization */ diff --git a/plat/xen/drivers/blk/blkfront.h b/plat/xen/drivers/blk/blkfront.h index bf6d231e..be610858 100644 --- a/plat/xen/drivers/blk/blkfront.h +++ b/plat/xen/drivers/blk/blkfront.h @@ -48,6 +48,18 @@ #include <common/events.h> +/** + * Structure used to describe a front device request. + */ +struct blkfront_request { + /* Request from the API. */ + struct uk_blkdev_request *req; + /* Number of segments. */ + uint16_t nb_segments; + /* Queue in which the request will be stored */ + struct uk_blkdev_queue *queue; +}; + /* * Structure used to describe a queue used for both requests and responses */ diff --git a/plat/xen/drivers/blk/blkfront_xs.c b/plat/xen/drivers/blk/blkfront_xs.c index d7d5ee94..014a25d3 100644 --- a/plat/xen/drivers/blk/blkfront_xs.c +++ b/plat/xen/drivers/blk/blkfront_xs.c @@ -197,6 +197,10 @@ static int blkfront_xb_get_capabilities(struct blkfront_dev *blkdev) } blkdev->blkdev.capabilities.mode = (*mode == 'r') ? O_RDONLY : O_RDWR; + blkdev->blkdev.capabilities.max_sectors_per_req = + (BLKIF_MAX_SEGMENTS_PER_REQUEST - 1) * + (PAGE_SIZE / blkdev->blkdev.capabilities.ssize) + 1; + blkdev->blkdev.capabilities.align = blkdev->blkdev.capabilities.ssize; free(mode); return 0; -- 2.11.0 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |