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

Re: [Minios-devel] [UNIKRAFT PATCH v2 5/5] plat/drivers: Implement virtio 9P request and recv



Reviewed-by: Costin Lupu <costin.lupu@xxxxxxxxx>

On 9/7/19 12:45 PM, Vlad-Andrei BĂDOIU (78692) wrote:
> From: Cristian Banu <cristb@xxxxxxxxx>
> 
> This patch implements the virtio request and receive callbacks.
> 
> Signed-off-by: Cristian Banu <cristb@xxxxxxxxx>
> ---
>  plat/drivers/virtio/virtio_9p.c | 161 +++++++++++++++++++++++++++++++-
>  1 file changed, 156 insertions(+), 5 deletions(-)
> 
> diff --git a/plat/drivers/virtio/virtio_9p.c b/plat/drivers/virtio/virtio_9p.c
> index 8094ec70..fe0d69ab 100644
> --- a/plat/drivers/virtio/virtio_9p.c
> +++ b/plat/drivers/virtio/virtio_9p.c
> @@ -35,6 +35,9 @@
>  #include <inttypes.h>
>  #include <uk/alloc.h>
>  #include <uk/essentials.h>
> +#include <uk/sglist.h>
> +#include <uk/9pdev.h>
> +#include <uk/9preq.h>
>  #include <uk/9pdev_trans.h>
>  #include <virtio/virtio_bus.h>
>  #include <virtio/virtio_9p.h>
> @@ -61,6 +64,11 @@ struct virtio_9p_device {
>       uint16_t hwvq_id;
>       /* libuk9p associated device (NULL if the device is not in use). */
>       struct uk_9pdev *p9dev;
> +     /* Scatter-gather list. */
> +     struct uk_sglist sg;
> +     struct uk_sglist_seg sgsegs[NUM_SEGMENTS];
> +     /* Spinlock protecting the sg list and the vq. */
> +     spinlock_t spinlock;
>  };
>  
>  static int virtio_9p_connect(struct uk_9pdev *p9dev,
> @@ -120,10 +128,96 @@ static int virtio_9p_disconnect(struct uk_9pdev *p9dev)
>       return 0;
>  }
>  
> -static int virtio_9p_request(struct uk_9pdev *p9dev __unused,
> -                          struct uk_9preq *req __unused)
> +static int virtio_9p_request(struct uk_9pdev *p9dev,
> +                          struct uk_9preq *req)
>  {
> -     return -EOPNOTSUPP;
> +     struct virtio_9p_device *dev;
> +     int rc, host_notified = 0;
> +     unsigned long flags;
> +     size_t read_segs, write_segs;
> +     bool failed = false;
> +
> +     UK_ASSERT(p9dev);
> +     UK_ASSERT(req);
> +     UK_ASSERT(UK_READ_ONCE(req->state) == UK_9PREQ_READY);
> +
> +     /*
> +      * Get the request such that it won't get freed while it's
> +      * used as a cookie for the virtqueue.
> +      */
> +     uk_9preq_get(req);
> +     dev = p9dev->priv;
> +     ukplat_spin_lock_irqsave(&dev->spinlock, flags);
> +     uk_sglist_reset(&dev->sg);
> +
> +     rc = uk_sglist_append(&dev->sg, req->xmit.buf, req->xmit.size);
> +     if (rc < 0) {
> +             failed = true;
> +             goto out_unlock;
> +     }
> +
> +     if (req->xmit.zc_buf) {
> +             rc = uk_sglist_append(&dev->sg, req->xmit.zc_buf,
> +                             req->xmit.zc_size);
> +             if (rc < 0) {
> +                     failed = true;
> +                     goto out_unlock;
> +             }
> +     }
> +
> +     read_segs = dev->sg.sg_nseg;
> +
> +     rc = uk_sglist_append(&dev->sg, req->recv.buf, req->recv.size);
> +     if (rc < 0) {
> +             failed = true;
> +             goto out_unlock;
> +     }
> +
> +     if (req->recv.zc_buf) {
> +             uint32_t recv_size = req->recv.size + req->recv.zc_size;
> +
> +             rc = uk_sglist_append(&dev->sg, req->recv.zc_buf,
> +                             req->recv.zc_size);
> +             if (rc < 0) {
> +                     failed = true;
> +                     goto out_unlock;
> +             }
> +
> +             /* Make eure there is sufficient space for Rerror replies. */
> +             if (recv_size < UK_9P_RERROR_MAXSIZE) {
> +                     uint32_t leftover = UK_9P_RERROR_MAXSIZE - recv_size;
> +
> +                     rc = uk_sglist_append(&dev->sg,
> +                                     req->recv.buf + recv_size, leftover);
> +                     if (rc < 0) {
> +                             failed = true;
> +                             goto out_unlock;
> +                     }
> +             }
> +     }
> +
> +     write_segs = dev->sg.sg_nseg - read_segs;
> +
> +     rc = virtqueue_buffer_enqueue(dev->vq, req, &dev->sg,
> +                                   read_segs, write_segs);
> +     if (likely(rc >= 0)) {
> +             UK_WRITE_ONCE(req->state, UK_9PREQ_SENT);
> +             virtqueue_host_notify(dev->vq);
> +             host_notified = 1;
> +             rc = 0;
> +     }
> +
> +out_unlock:
> +     if (failed)
> +             uk_pr_err(DRIVER_NAME": Failed to append to the sg list.\n");
> +     ukplat_spin_unlock_irqrestore(&dev->spinlock, flags);
> +     /*
> +      * Release the reference to the 9P request if it was not successfully
> +      * sent.
> +      */
> +     if (!host_notified)
> +             uk_9preq_put(req);
> +     return rc;
>  }
>  
>  static const struct uk_9pdev_trans_ops v9p_trans_ops = {
> @@ -138,9 +232,63 @@ static struct uk_9pdev_trans v9p_trans = {
>       .a              = NULL /* Set by the driver initialization. */
>  };
>  
> -static int virtio_9p_recv(struct virtqueue *vq __unused, void *priv __unused)
> +static int virtio_9p_recv(struct virtqueue *vq, void *priv)
>  {
> -     return 0;
> +     struct virtio_9p_device *dev;
> +     struct uk_9preq *req = NULL;
> +     uint32_t len;
> +     int rc = 0;
> +     int handled = 0;
> +
> +     UK_ASSERT(vq);
> +     UK_ASSERT(priv);
> +
> +     dev = priv;
> +     UK_ASSERT(vq == dev->vq);
> +
> +     while (1) {
> +             /*
> +              * Protect against data races with virtio_9p_request() calls
> +              * which are trying to enqueue to the same vq.
> +              */
> +             ukarch_spin_lock(&dev->spinlock);
> +             rc = virtqueue_buffer_dequeue(dev->vq, (void **)&req, &len);
> +             ukarch_spin_unlock(&dev->spinlock);
> +             if (rc < 0)
> +                     break;
> +
> +             /*
> +              * Notify the 9P API that this request has been successfully
> +              * received, release the reference to the request.
> +              */
> +             uk_9preq_receive_cb(req, len);
> +
> +             /*
> +              * Check for Rerror messages, fixup the error message if
> +              * needed.
> +              */
> +             if (req->recv.type == UK_9P_RERROR) {
> +                     memcpy(req->recv.buf + req->recv.zc_offset,
> +                            req->recv.zc_buf,
> +                            MIN(req->recv.zc_size, len - UK_9P_HEADER_SIZE));
> +             }
> +
> +             uk_9preq_put(req);
> +             handled = 1;
> +
> +             /* Break if there are no more buffers on the virtqueue. */
> +             if (rc == 0)
> +                     break;
> +     }
> +
> +     /*
> +      * As the virtqueue might have empty slots now, notify any threads
> +      * blocked on ENOSPC errors.
> +      */
> +     if (handled)
> +             uk_9pdev_xmit_notify(dev->p9dev);
> +
> +     return handled;
>  }
>  
>  static int virtio_9p_vq_alloc(struct virtio_9p_device *d)
> @@ -165,6 +313,8 @@ static int virtio_9p_vq_alloc(struct virtio_9p_device *d)
>               goto exit;
>       }
>  
> +     uk_sglist_init(&d->sg, ARRAY_SIZE(d->sgsegs), &d->sgsegs[0]);
> +
>       d->vq = virtio_vqueue_setup(d->vdev,
>                                   d->hwvq_id,
>                                   qdesc_size,
> @@ -272,6 +422,7 @@ static int virtio_9p_add_dev(struct virtio_dev *vdev)
>               rc = -ENOMEM;
>               goto out;
>       }
> +     ukarch_spin_lock_init(&d->spinlock);
>       d->vdev = vdev;
>       virtio_9p_feature_set(d);
>       rc = virtio_9p_configure(d);
> 

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