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