|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH 09/12] 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 | 6 +
plat/drivers/virtio/virtio_blk.c | 183 +++++++++++++++++++++++++++++++
2 files changed, 189 insertions(+)
diff --git a/plat/drivers/include/virtio/virtio_blk.h
b/plat/drivers/include/virtio/virtio_blk.h
index c88dc45c..fde1953c 100644
--- a/plat/drivers/include/virtio/virtio_blk.h
+++ b/plat/drivers/include/virtio/virtio_blk.h
@@ -49,6 +49,12 @@ struct virtio_blk_config {
__u16 num_queues;
};
+/* Header comes first in the scatter-gather list */
+struct virtio_blk_hdr {
+ /* Operation type */
+ uint32_t type;
+ /* Start-sector */
+ uint64_t sector;
};
#endif /* __PLAT_DRV_VIRTIO_BLK_H */
diff --git a/plat/drivers/virtio/virtio_blk.c b/plat/drivers/virtio/virtio_blk.c
index e18ef805..bc845d97 100644
--- a/plat/drivers/virtio/virtio_blk.c
+++ b/plat/drivers/virtio/virtio_blk.c
@@ -100,6 +100,188 @@ struct uk_blkdev_queue {
struct uk_sglist_seg *sgsegs;
};
+static int virtio_blkdev_request_set_sglist(struct uk_blkdev_queue *queue,
+ struct uk_blkdev_request *req,
+ __sector sector_size)
+{
+ struct virtio_blk_device *vbdev;
+ 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(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, req, sizeof(struct virtio_blk_hdr));
+ if (unlikely(rc != 0)) {
+ uk_pr_err("Failed to append to sg list %d\n", rc);
+ goto out;
+ }
+
+ /* Append to sglist chunks of `segment_max_size` size
+ * Only for read / write operations
+ **/
+ 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, &req->result_status,
+ sizeof(req->result_status));
+ 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 uk_blkdev_request *req, __u16 *read_segs,
+ __u16 *write_segs)
+{
+ struct virtio_blk_device *vbdev;
+ struct uk_blkdev_cap *cap;
+ int rc = 0;
+
+ UK_ASSERT(queue);
+ UK_ASSERT(req);
+
+ vbdev = queue->vbd;
+ cap = &vbdev->blkdev.capabilities;
+ 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, req, cap->ssize, true);
+ 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;
+ } else if (req->operation == UK_BLKDEV_READ) {
+ *read_segs = 1;
+ *write_segs = queue->sg.sg_nseg - 1;
+ }
+
+out:
+ return rc;
+}
+
+static int virtio_blkdev_queue_enqueue(struct uk_blkdev_queue *queue,
+ struct uk_blkdev_request *req)
+{
+ __u16 write_segs;
+ __u16 read_segs;
+ 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;
+ }
+
+ if (req->operation == UK_BLKDEV_WRITE ||
+ req->operation == UK_BLKDEV_READ)
+ rc = virtio_blkdev_request_write(queue, req, &read_segs,
+ &write_segs);
+ else
+ return -EINVAL;
+
+ if (rc)
+ goto out;
+
+ rc = virtqueue_buffer_enqueue(queue->vq, req, &queue->sg,
+ read_segs, write_segs);
+
+out:
+ return rc;
+}
+
+static int virtio_blkdev_submit_request(struct uk_blkdev *dev,
+ uint16_t queue_id,
+ struct uk_blkdev_request *req)
+{
+ struct virtio_blk_device *vbdev;
+ struct uk_blkdev_queue *queue;
+ int rc = 0;
+ int status = 0x0;
+
+ UK_ASSERT(req);
+ UK_ASSERT(dev);
+
+ vbdev = to_virtioblkdev(dev);
+ if (unlikely(queue_id >= vbdev->nb_queues)) {
+ uk_pr_err("Invalid queue_id %"__PRIu16"\n", queue_id);
+ return -EINVAL;
+ }
+
+ queue = &vbdev->qs[queue_id];
+ 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)
{
@@ -588,6 +770,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.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 |