[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Minios-devel] [UNIKRAFT PATCH v3 11/14] plat/drivers: Request interface for virtio block



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/drivers/include/virtio/virtio_blk.h |  22 +++
 plat/drivers/virtio/virtio_blk.c         | 192 +++++++++++++++++++++++
 2 files changed, 214 insertions(+)

diff --git a/plat/drivers/include/virtio/virtio_blk.h 
b/plat/drivers/include/virtio/virtio_blk.h
index 4877e404..8b50d889 100644
--- a/plat/drivers/include/virtio/virtio_blk.h
+++ b/plat/drivers/include/virtio/virtio_blk.h
@@ -60,4 +60,26 @@ struct virtio_blk_config {
        __u16 num_queues;
 } __packed;
 
+/*
+ * Command types
+ */
+
+/* These two define direction. */
+#define VIRTIO_BLK_T_IN                0
+#define VIRTIO_BLK_T_OUT       1
+
+/*
+ * This comes first in the read scatter-gather list.
+ * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
+ * this is the first element of the read scatter-gather list.
+ */
+struct virtio_blk_outhdr {
+       /* VIRTIO_BLK_T* */
+       __virtio_le32 type;
+       /* io priority. */
+       __virtio_le32 ioprio;
+       /* Sector (ie. 512 byte offset) */
+       __virtio_le64 sector;
+};
+
 #endif /* __PLAT_DRV_VIRTIO_BLK_H */
diff --git a/plat/drivers/virtio/virtio_blk.c b/plat/drivers/virtio/virtio_blk.c
index ecd8e691..6bdefd9c 100644
--- a/plat/drivers/virtio/virtio_blk.c
+++ b/plat/drivers/virtio/virtio_blk.c
@@ -100,6 +100,197 @@ struct uk_blkdev_queue {
        struct uk_sglist_seg *sgsegs;
 };
 
+struct virtio_blkdev_request {
+       struct uk_blkreq *req;
+       struct virtio_blk_outhdr virtio_blk_outhdr;
+       uint8_t status;
+};
+
+static int virtio_blkdev_request_set_sglist(struct uk_blkdev_queue *queue,
+               struct virtio_blkdev_request *virtio_blk_req,
+               __sector sector_size)
+{
+       struct virtio_blk_device *vbdev;
+       struct uk_blkreq *req;
+       size_t data_size = 0;
+       size_t segment_size;
+       size_t segment_max_size;
+       size_t idx;
+       uintptr_t start_data;
+       int rc = 0;
+
+       UK_ASSERT(queue);
+       UK_ASSERT(virtio_blk_req);
+
+       req = virtio_blk_req->req;
+       vbdev = queue->vbd;
+       start_data = (uintptr_t)req->aio_buf;
+       data_size = req->nb_sectors * sector_size;
+       segment_max_size = vbdev->max_size_segment;
+
+       /* Prepare the sglist */
+       uk_sglist_reset(&queue->sg);
+       rc = uk_sglist_append(&queue->sg, &virtio_blk_req->virtio_blk_outhdr,
+                       sizeof(struct virtio_blk_outhdr));
+       if (unlikely(rc != 0)) {
+               uk_pr_err("Failed to append to sg list %d\n", rc);
+               goto out;
+       }
+
+       for (idx = 0; idx < data_size; idx += segment_max_size) {
+               segment_size = data_size - idx;
+               segment_size = (segment_size > segment_max_size) ?
+                                       segment_max_size : segment_size;
+               rc = uk_sglist_append(&queue->sg,
+                               (void *)(start_data + idx),
+                               segment_size);
+               if (unlikely(rc != 0)) {
+                       uk_pr_err("Failed to append to sg list %d\n",
+                                       rc);
+                       goto out;
+               }
+       }
+
+       rc = uk_sglist_append(&queue->sg, &virtio_blk_req->status,
+                       sizeof(uint8_t));
+       if (unlikely(rc != 0)) {
+               uk_pr_err("Failed to append to sg list %d\n", rc);
+               goto out;
+       }
+
+out:
+       return rc;
+}
+
+static int virtio_blkdev_request_write(struct uk_blkdev_queue *queue,
+               struct virtio_blkdev_request *virtio_blk_req,
+               __u16 *read_segs, __u16 *write_segs)
+{
+       struct virtio_blk_device *vbdev;
+       struct uk_blkdev_cap *cap;
+       struct uk_blkreq *req;
+       int rc = 0;
+
+       UK_ASSERT(queue);
+       UK_ASSERT(virtio_blk_req);
+
+       vbdev = queue->vbd;
+       cap = &vbdev->blkdev.capabilities;
+       req = virtio_blk_req->req;
+       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;
+
+       rc = virtio_blkdev_request_set_sglist(queue, virtio_blk_req,
+                       cap->ssize);
+       if (rc) {
+               uk_pr_err("Failed to set sglist %d\n", rc);
+               goto out;
+       }
+
+       if (req->operation == UK_BLKDEV_WRITE) {
+               *read_segs = queue->sg.sg_nseg - 1;
+               *write_segs = 1;
+               virtio_blk_req->virtio_blk_outhdr.type = VIRTIO_BLK_T_OUT;
+       } else if (req->operation == UK_BLKDEV_READ) {
+               *read_segs = 1;
+               *write_segs = queue->sg.sg_nseg - 1;
+               virtio_blk_req->virtio_blk_outhdr.type = VIRTIO_BLK_T_IN;
+       }
+
+out:
+       return rc;
+}
+
+static int virtio_blkdev_queue_enqueue(struct uk_blkdev_queue *queue,
+               struct uk_blkreq *req)
+{
+       struct virtio_blkdev_request *virtio_blk_req;
+       __u16 write_segs = 0;
+       __u16 read_segs = 0;
+       int rc = 0;
+
+       UK_ASSERT(queue);
+       UK_ASSERT(req);
+
+       if (virtqueue_is_full(queue->vq)) {
+               uk_pr_debug("The virtqueue is full\n");
+               return -ENOSPC;
+       }
+
+       virtio_blk_req = uk_malloc(a, sizeof(*virtio_blk_req));
+       if (!virtio_blk_req)
+               return -ENOMEM;
+
+       virtio_blk_req->req = req;
+       virtio_blk_req->virtio_blk_outhdr.sector = req->start_sector;
+       if (req->operation == UK_BLKDEV_WRITE ||
+                       req->operation == UK_BLKDEV_READ)
+               rc = virtio_blkdev_request_write(queue, virtio_blk_req,
+                               &read_segs, &write_segs);
+       else
+               return -EINVAL;
+
+       if (rc)
+               goto out;
+
+       rc = virtqueue_buffer_enqueue(queue->vq, virtio_blk_req, &queue->sg,
+                                     read_segs, write_segs);
+
+out:
+       return rc;
+}
+
+static int virtio_blkdev_submit_request(struct uk_blkdev *dev,
+               struct uk_blkdev_queue *queue,
+               struct uk_blkreq *req)
+{
+       int rc = 0;
+       int status = 0x0;
+
+       UK_ASSERT(req);
+       UK_ASSERT(queue);
+       UK_ASSERT(dev);
+
+       rc = virtio_blkdev_queue_enqueue(queue, req);
+       if (likely(rc >= 0)) {
+               uk_pr_debug("Success and more descriptors available\n");
+               status |= UK_BLKDEV_STATUS_SUCCESS;
+               /**
+                * Notify the host the new buffer.
+                */
+               virtqueue_host_notify(queue->vq);
+               /**
+                * When there is further space available in the ring
+                * return UK_BLKDEV_STATUS_MORE.
+                */
+               status |= likely(rc > 0) ? UK_BLKDEV_STATUS_MORE : 0x0;
+       } else if (rc == -ENOSPC) {
+               uk_pr_debug("No more descriptors available\n");
+               goto err;
+       } else {
+               uk_pr_err("Failed to enqueue descriptors into the ring: %d\n",
+                         rc);
+               goto err;
+       }
+
+       return status;
+
+err:
+       return rc;
+}
 
 static int virtio_blkdev_recv_done(struct virtqueue *vq, void *priv)
 {
@@ -572,6 +763,7 @@ static int virtio_blk_add_dev(struct virtio_dev *vdev)
                return -ENOMEM;
 
        vbdev->vdev = vdev;
+       vbdev->blkdev.submit_one = virtio_blkdev_submit_request;
        vbdev->blkdev.dev_ops = &virtio_blkdev_ops;
 
        rc = uk_blkdev_drv_register(&vbdev->blkdev, a, drv_name);
-- 
2.17.1


_______________________________________________
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®.