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

Re: [Minios-devel] [UNIKRAFT PATCH v2 4/8] lib/uk9p: Add 9P requests abstraction



Hi Costin,

I updated this in v3.

Thanks!
Cristi

On Sat, Aug 24, 2019 at 3:07 PM Costin Lupu <costin.lup@xxxxxxxxx> wrote:
>
> Hi Cristi,
>
> Since we're going to have another version of 9p, I have one small
> comment inline.
>
> On 6/29/19 11:56 AM, Cristian Banu wrote:
> > This patch introduces a struct uk_9preq which abstracts the lifecycle of
> > allocating memory, serializing data, sending it over a transport layer,
> > receiving the response, detecting errors, deserializing the received
> > message and freeing the memory.
> >
> > Signed-off-by: Cristian Banu <cristb@xxxxxxxxx>
> > ---
> >  lib/uk9p/9preq.c            | 569 
> > ++++++++++++++++++++++++++++++++++++++++++++
> >  lib/uk9p/Makefile.uk        |   1 +
> >  lib/uk9p/exportsyms.uk      |  11 +
> >  lib/uk9p/include/uk/9preq.h | 300 +++++++++++++++++++++++
> >  4 files changed, 881 insertions(+)
> >  create mode 100644 lib/uk9p/9preq.c
> >  create mode 100644 lib/uk9p/include/uk/9preq.h
> >
> > diff --git a/lib/uk9p/9preq.c b/lib/uk9p/9preq.c
> > new file mode 100644
> > index 000000000000..e48aae17d50f
> > --- /dev/null
> > +++ b/lib/uk9p/9preq.c
> > @@ -0,0 +1,569 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause */
> > +/*
> > + * Authors: Cristian Banu <cristb@xxxxxxxxx>
> > + *
> > + * Copyright (c) 2019, University Politehnica of Bucharest. All rights 
> > reserved.
> > + *
> > + * Redistribution and use in source and binary forms, with or without
> > + * modification, are permitted provided that the following conditions
> > + * are met:
> > + *
> > + * 1. Redistributions of source code must retain the above copyright
> > + *    notice, this list of conditions and the following disclaimer.
> > + * 2. Redistributions in binary form must reproduce the above copyright
> > + *    notice, this list of conditions and the following disclaimer in the
> > + *    documentation and/or other materials provided with the distribution.
> > + * 3. Neither the name of the copyright holder nor the names of its
> > + *    contributors may be used to endorse or promote products derived from
> > + *    this software without specific prior written permission.
> > + *
> > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
> > IS"
> > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
> > THE
> > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
> > PURPOSE
> > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 
> > BE
> > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
> > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
> > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
> > THE
> > + * POSSIBILITY OF SUCH DAMAGE.
> > + *
> > + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
> > + */
> > +
> > +#include <string.h>
> > +#include <uk/config.h>
> > +#include <uk/9preq.h>
> > +#include <uk/9p_core.h>
> > +#include <uk/list.h>
> > +#include <uk/refcount.h>
> > +#include <uk/essentials.h>
> > +#include <uk/alloc.h>
> > +#if CONFIG_LIBUKSCHED
> > +#include <uk/sched.h>
> > +#include <uk/wait.h>
> > +#endif
> > +
> > +static int _fcall_alloc(struct uk_alloc *a, struct uk_9preq_fcall *f,
> > +                     uint32_t size)
> > +{
> > +     UK_ASSERT(a);
> > +     UK_ASSERT(f);
> > +     UK_ASSERT(size > 0);
> > +
> > +     f->buf = uk_calloc(a, size, sizeof(char));
> > +     if (f->buf == NULL)
> > +             return -ENOMEM;
> > +
> > +     f->size = size;
> > +     f->offset = 0;
> > +     f->zc_buf = NULL;
> > +     f->zc_size = 0;
> > +     f->zc_offset = 0;
> > +
> > +     return 0;
> > +}
> > +
> > +static void _fcall_free(struct uk_alloc *a, struct uk_9preq_fcall *f)
> > +{
> > +     UK_ASSERT(a);
> > +     UK_ASSERT(f);
> > +
> > +     if (f->buf)
> > +             uk_free(a, f->buf);
> > +}
> > +
> > +struct uk_9preq *uk_9preq_alloc(struct uk_alloc *a, uint32_t size)
> > +{
> > +     struct uk_9preq *req;
> > +     int rc;
> > +
> > +     req = uk_calloc(a, 1, sizeof(*req));
> > +     if (req == NULL)
> > +             goto out;
> > +
> > +     rc = _fcall_alloc(a, &req->xmit, size);
> > +     if (rc < 0)
> > +             goto out_free;
> > +
> > +     rc = _fcall_alloc(a, &req->recv, MAX(size, UK_9P_RERROR_MAXSIZE));
> > +     if (rc < 0)
> > +             goto out_free;
> > +
> > +     UK_INIT_LIST_HEAD(&req->_list);
> > +     req->_a = a;
> > +     uk_refcount_init(&req->refcount, 1);
> > +#if CONFIG_LIBUKSCHED
> > +     uk_waitq_init(&req->wq);
> > +#endif
> > +
> > +     /*
> > +      * Assume the header has already been written.
> > +      * The header itself will be written on uk_9preq_ready(), when the
> > +      * actual message size is known.
> > +      */
> > +     req->xmit.offset = UK_9P_HEADER_SIZE;
> > +
> > +     return req;
> > +
> > +out_free:
> > +     _fcall_free(a, &req->recv);
> > +     _fcall_free(a, &req->xmit);
> > +     uk_free(a, req);
> > +out:
> > +     return NULL;
> > +}
> > +
> > +static void _req_free(struct uk_9preq *req)
> > +{
> > +     _fcall_free(req->_a, &req->recv);
> > +     _fcall_free(req->_a, &req->xmit);
> > +     uk_free(req->_a, req);
> > +}
> > +
> > +void uk_9preq_get(struct uk_9preq *req)
> > +{
> > +     uk_refcount_acquire(&req->refcount);
> > +}
> > +
> > +int uk_9preq_put(struct uk_9preq *req)
> > +{
> > +     int last;
> > +
> > +     last = uk_refcount_release(&req->refcount);
> > +     if (last)
> > +             _req_free(req);
> > +
> > +     return last;
> > +}
> > +
> > +static int _fcall_write(struct uk_9preq_fcall *fcall, const void *buf,
> > +             uint32_t size)
> > +{
> > +     if (fcall->offset + size > fcall->size)
> > +             return -ENOBUFS;
> > +
> > +     memcpy((char *)fcall->buf + fcall->offset, buf, size);
> > +     fcall->offset += size;
> > +     return 0;
> > +}
> > +
> > +static int _fcall_serialize(struct uk_9preq_fcall *f, const char *fmt, 
> > ...);
> > +
> > +static int _fcall_vserialize(struct uk_9preq_fcall *fcall, const char *fmt,
> > +                     va_list vl)
> > +{
> > +     int rc = 0;
> > +
> > +     while (*fmt) {
> > +             switch (*fmt) {
> > +             case 'b': {
> > +                     uint8_t x;
> > +
> > +                     x = va_arg(vl, unsigned int);
> > +                     rc = _fcall_write(fcall, &x, sizeof(x));
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             case 'w': {
> > +                     uint16_t x;
> > +
> > +                     x = va_arg(vl, unsigned int);
> > +                     rc = _fcall_write(fcall, &x, sizeof(x));
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             case 'd': {
> > +                     uint32_t x;
> > +
> > +                     x = va_arg(vl, uint32_t);
> > +                     rc = _fcall_write(fcall, &x, sizeof(x));
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             case 'q': {
> > +                     uint64_t x;
> > +
> > +                     x = va_arg(vl, uint64_t);
> > +                     rc = _fcall_write(fcall, &x, sizeof(x));
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             case 's': {
> > +                     struct uk_9p_str *p;
> > +
> > +                     p = va_arg(vl, struct uk_9p_str *);
> > +                     rc = _fcall_write(fcall, &p->size, sizeof(p->size));
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     rc = _fcall_write(fcall, p->data, p->size);
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             case 'Q': {
> > +                     struct uk_9p_qid *p;
> > +
> > +                     p = va_arg(vl, struct uk_9p_qid *);
> > +                     rc = _fcall_serialize(fcall, "bdq", p->type,
> > +                                     p->version, p->path);
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             case 'S': {
> > +                     struct uk_9p_stat *p;
> > +
> > +                     p = va_arg(vl, struct uk_9p_stat *);
> > +                     rc = _fcall_serialize(fcall, "wwdQdddqsssssddd",
> > +                                     p->size, p->type, p->dev, &p->qid,
> > +                                     p->mode, p->atime, p->mtime, 
> > p->length,
> > +                                     &p->name, &p->uid, &p->gid, &p->muid,
> > +                                     &p->extension, p->n_uid, p->n_gid,
> > +                                     p->n_muid);
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             default:
> > +                     rc = -EINVAL;
> > +                     goto out;
> > +             }
> > +
> > +             fmt++;
> > +     }
> > +
> > +out:
> > +     return rc;
> > +}
> > +
> > +static int _fcall_serialize(struct uk_9preq_fcall *f, const char *fmt, ...)
> > +{
> > +     va_list vl;
> > +     int rc;
> > +
> > +     va_start(vl, fmt);
> > +     rc = _fcall_vserialize(f, fmt, vl);
> > +     va_end(vl);
> > +
> > +     return rc;
> > +}
> > +
> > +int uk_9preq_vserialize(struct uk_9preq *req, const char *fmt, va_list vl)
> > +{
> > +     int rc;
> > +
> > +     UK_ASSERT(req);
> > +     UK_ASSERT(UK_READ_ONCE(req->state) == UK_9PREQ_INITIALIZED);
> > +     rc = _fcall_vserialize(&req->xmit, fmt, vl);
> > +
> > +     return rc;
> > +}
> > +
> > +int uk_9preq_serialize(struct uk_9preq *req, const char *fmt, ...)
> > +{
> > +     va_list vl;
> > +     int rc;
> > +
> > +     va_start(vl, fmt);
> > +     rc = uk_9preq_vserialize(req, fmt, vl);
> > +     va_end(vl);
> > +
> > +     return rc;
> > +}
> > +
> > +static int _fcall_read(struct uk_9preq_fcall *fcall, void *buf, uint32_t 
> > size)
> > +{
> > +     if (fcall->offset + size > fcall->size)
> > +             return -ENOBUFS;
> > +
> > +     memcpy(buf, (char *)fcall->buf + fcall->offset, size);
> > +     fcall->offset += size;
> > +     return 0;
> > +}
> > +
> > +static int _fcall_deserialize(struct uk_9preq_fcall *f, const char *fmt, 
> > ...);
> > +
> > +static int _fcall_vdeserialize(struct uk_9preq_fcall *fcall,
> > +                           const char *fmt,
> > +                           va_list vl)
> > +{
> > +     int rc = 0;
> > +
> > +     while (*fmt) {
> > +             switch (*fmt) {
> > +             case 'b': {
> > +                     uint8_t *x;
> > +
> > +                     x = va_arg(vl, uint8_t *);
> > +                     rc = _fcall_read(fcall, x, sizeof(*x));
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             case 'w': {
> > +                     uint16_t *x;
> > +
> > +                     x = va_arg(vl, uint16_t *);
> > +                     rc = _fcall_read(fcall, x, sizeof(*x));
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             case 'd': {
> > +                     uint32_t *x;
> > +
> > +                     x = va_arg(vl, uint32_t *);
> > +                     rc = _fcall_read(fcall, x, sizeof(*x));
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             case 'q': {
> > +                     uint64_t *x;
> > +
> > +                     x = va_arg(vl, uint64_t *);
> > +                     rc = _fcall_read(fcall, x, sizeof(*x));
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             case 's': {
> > +                     struct uk_9p_str *p;
> > +
> > +                     p = va_arg(vl, struct uk_9p_str *);
> > +                     rc = _fcall_read(fcall, &p->size, sizeof(p->size));
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     p->data = (char *)fcall->buf + fcall->offset;
> > +                     fcall->offset += p->size;
> > +                     break;
> > +             }
> > +             case 'Q': {
> > +                     struct uk_9p_qid *p;
> > +
> > +                     p = va_arg(vl, struct uk_9p_qid *);
> > +                     rc = _fcall_deserialize(fcall, "bdq", &p->type,
> > +                                     &p->version, &p->path);
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             case 'S': {
> > +                     struct uk_9p_stat *p;
> > +
> > +                     p = va_arg(vl, struct uk_9p_stat *);
> > +                     rc = _fcall_deserialize(fcall, "wwdQdddqsssssddd",
> > +                                     &p->size, &p->type, &p->dev, &p->qid,
> > +                                     &p->mode, &p->atime, &p->mtime,
> > +                                     &p->length, &p->name, &p->uid, 
> > &p->gid,
> > +                                     &p->muid, &p->extension, &p->n_uid,
> > +                                     &p->n_gid, &p->n_muid);
> > +                     if (rc < 0)
> > +                             goto out;
> > +                     break;
> > +             }
> > +             default:
> > +                     rc = -EINVAL;
> > +                     goto out;
> > +             }
> > +
> > +             fmt++;
> > +     }
> > +
> > +out:
> > +     return rc;
> > +}
> > +
> > +static int _fcall_deserialize(struct uk_9preq_fcall *f, const char *fmt, 
> > ...)
> > +{
> > +     va_list vl;
> > +     int rc;
> > +
> > +     va_start(vl, fmt);
> > +     rc = _fcall_vdeserialize(f, fmt, vl);
> > +     va_end(vl);
> > +
> > +     return rc;
> > +}
> > +
> > +int uk_9preq_vdeserialize(struct uk_9preq *req, const char *fmt, va_list 
> > vl)
> > +{
> > +     int rc;
> > +
> > +     UK_ASSERT(req);
> > +     UK_ASSERT(UK_READ_ONCE(req->state) == UK_9PREQ_RECEIVED);
> > +     rc = _fcall_vdeserialize(&req->recv, fmt, vl);
> > +
> > +     return rc;
> > +}
> > +
> > +int uk_9preq_deserialize(struct uk_9preq *req, const char *fmt, ...)
> > +{
> > +     va_list vl;
> > +     int rc;
> > +
> > +     va_start(vl, fmt);
> > +     rc = uk_9preq_vdeserialize(req, fmt, vl);
> > +     va_end(vl);
> > +
> > +     return rc;
> > +}
> > +
> > +int uk_9preq_copy_to(struct uk_9preq *req, void *buf, uint32_t size)
> > +{
> > +     return _fcall_read(&req->recv, buf, size);
> > +}
> > +
> > +int uk_9preq_copy_from(struct uk_9preq *req, const void *buf, uint32_t 
> > size)
> > +{
> > +     return _fcall_write(&req->xmit, buf, size);
> > +}
> > +
> > +int uk_9preq_ready(struct uk_9preq *req, enum uk_9preq_zcdir zc_dir,
> > +             void *zc_buf, uint32_t zc_size, uint32_t zc_offset)
> > +{
> > +     int rc;
> > +     uint32_t total_size;
> > +     uint32_t total_size_with_zc;
> > +
> > +     UK_ASSERT(req);
> > +
> > +     if (UK_READ_ONCE(req->state) != UK_9PREQ_INITIALIZED) {
> > +             rc = -EIO;
> > +             goto out;
> > +     }
> > +
> > +     /* Save current offset as the size of the message. */
> > +     total_size = req->xmit.offset;
> > +
> > +     total_size_with_zc = total_size;
> > +     if (zc_dir == UK_9PREQ_ZCDIR_WRITE)
> > +             total_size_with_zc += zc_size;
> > +
> > +     /* Serialize the header. */
> > +     req->xmit.offset = 0;
> > +     rc = uk_9preq_serialize(req, "dbw", total_size_with_zc, 
> > req->xmit.type,
> > +                     req->tag);
> > +     if (rc < 0)
> > +             goto out;
> > +
> > +     /* Reset offset and size to sane values. */
> > +     req->xmit.offset = 0;
> > +     req->xmit.size = total_size;
> > +
> > +     /* Update zero copy buffers. */
> > +     if (zc_dir == UK_9PREQ_ZCDIR_WRITE) {
> > +             req->xmit.zc_buf = zc_buf;
> > +             req->xmit.zc_size = zc_size;
> > +             /* Zero-copy offset for writes must start at the end of buf. 
> > */
> > +             req->xmit.zc_offset = req->xmit.size;
> > +     } else if (zc_dir == UK_9PREQ_ZCDIR_READ) {
> > +             req->recv.zc_buf = zc_buf;
> > +             req->recv.zc_size = zc_size;
> > +             req->recv.zc_offset = zc_offset;
> > +             /* The receive buffer must end before the zc buf. */
> > +             req->recv.size = zc_offset;
> > +     }
> > +
> > +     /* Update the state. */
> > +     UK_WRITE_ONCE(req->state, UK_9PREQ_READY);
> > +
> > +out:
> > +     return rc;
> > +}
> > +
> > +int uk_9preq_receive_cb(struct uk_9preq *req, uint32_t recv_size)
> > +{
> > +     uint32_t size;
> > +     uint16_t tag;
> > +     int rc;
> > +
> > +     UK_ASSERT(req);
> > +
> > +     /* Check state and the existence of the header. */
> > +     if (UK_READ_ONCE(req->state) != UK_9PREQ_SENT)
> > +             return -EIO;
> > +     if (recv_size < UK_9P_HEADER_SIZE)
> > +             return -EIO;
> > +
> > +     /* Deserialize the header into request fields. */
> > +     req->recv.offset = 0;
> > +     req->recv.size = recv_size;
> > +     rc = _fcall_deserialize(&req->recv, "dbw", &size,
> > +                     &req->recv.type, &tag);
> > +
> > +     /* Check sanity of deserialized values. */
> > +     if (rc < 0)
> > +             return rc;
> > +     if (size > recv_size)
> > +             return -EIO;
> > +     if (req->tag != tag)
> > +             return -EIO;
> > +
> > +     /* Fix the receive size for zero-copy requests. */
> > +     if (req->recv.zc_buf && req->recv.type != UK_9P_RERROR)
> > +             req->recv.size = req->recv.zc_offset;
> > +     else
> > +             req->recv.size = size;
> > +
> > +     /* Update the state. */
> > +     UK_WRITE_ONCE(req->state, UK_9PREQ_RECEIVED);
> > +
> > +#if CONFIG_LIBUKSCHED
> > +     /* Notify any waiting threads. */
> > +     uk_waitq_wake_up(&req->wq);
> > +#endif
> > +
> > +     return 0;
> > +}
> > +
> > +int uk_9preq_waitreply(struct uk_9preq *req)
> > +{
> > +     int rc;
> > +
> > +#if CONFIG_LIBUKSCHED
> > +     uk_waitq_wait_event(&req->wq, req->state == UK_9PREQ_RECEIVED);
> > +#else
> > +     while (UK_READ_ONCE(req->state) != UK_9PREQ_RECEIVED)
> > +             ;
> > +#endif
> > +
> > +     /* Check for 9P server-side errors. */
> > +     rc = uk_9preq_error(req);
> > +
> > +     return rc;
> > +}
> > +
> > +int uk_9preq_error(struct uk_9preq *req)
> > +{
> > +     uint32_t errcode;
> > +     struct uk_9p_str error;
> > +     int rc = 0;
> > +
> > +     if (UK_READ_ONCE(req->state) != UK_9PREQ_RECEIVED)
> > +             return -EIO;
> > +     if (req->recv.type != UK_9P_RERROR)
> > +             return 0;
> > +
> > +     /*
> > +      * The request should not have had any data deserialized from it prior
> > +      * to this call.
> > +      */
> > +     UK_BUGON(req->recv.offset != UK_9P_HEADER_SIZE);
> > +
> > +     rc = uk_9preq_deserialize(req, "sd", &error, &errcode);
> > +     if (rc < 0)
> > +             return rc;
> > +
> > +     uk_pr_info("uk9p: RERROR %.*s %d\n", error.size, error.data, errcode);
>
> I think we should use uk_pr_debug() instead. The errors should be
> printed on a higher level, if needed, here we need them only as debug
> messages. Otherwise we will have lots of message printed when testing if
> files/directories exist.
>
> > +     if (errcode == 0 || errcode >= 512)
> > +             return -EIO;
> > +
> > +     return -errcode;
> > +}
> > diff --git a/lib/uk9p/Makefile.uk b/lib/uk9p/Makefile.uk
> > index b1071a0e7d3c..aea722a585b9 100644
> > --- a/lib/uk9p/Makefile.uk
> > +++ b/lib/uk9p/Makefile.uk
> > @@ -4,3 +4,4 @@ CINCLUDES-$(CONFIG_LIBUK9P)           += 
> > -I$(LIBUK9P_BASE)/include
> >  CXXINCLUDES-$(CONFIG_LIBUK9P)                += -I$(LIBUK9P_BASE)/include
> >
> >  LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9pdev_trans.c
> > +LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9preq.c
> > diff --git a/lib/uk9p/exportsyms.uk b/lib/uk9p/exportsyms.uk
> > index 45f487da2fff..850ffa2db233 100644
> > --- a/lib/uk9p/exportsyms.uk
> > +++ b/lib/uk9p/exportsyms.uk
> > @@ -1,3 +1,14 @@
> >  uk_9pdev_trans_register
> >  uk_9pdev_trans_by_name
> >  uk_9pdev_trans_default
> > +uk_9preq_get
> > +uk_9preq_put
> > +uk_9preq_vserialize
> > +uk_9preq_serialize
> > +uk_9preq_vdeserialize
> > +uk_9preq_deserialize
> > +uk_9preq_copy_to
> > +uk_9preq_copy_from
> > +uk_9preq_receive_cb
> > +uk_9preq_waitreply
> > +uk_9preq_error
> > diff --git a/lib/uk9p/include/uk/9preq.h b/lib/uk9p/include/uk/9preq.h
> > new file mode 100644
> > index 000000000000..ee4d2af8635d
> > --- /dev/null
> > +++ b/lib/uk9p/include/uk/9preq.h
> > @@ -0,0 +1,300 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause */
> > +/*
> > + * Authors: Cristian Banu <cristb@xxxxxxxxx>
> > + *
> > + * Copyright (c) 2019, University Politehnica of Bucharest. All rights 
> > reserved.
> > + *
> > + * Redistribution and use in source and binary forms, with or without
> > + * modification, are permitted provided that the following conditions
> > + * are met:
> > + *
> > + * 1. Redistributions of source code must retain the above copyright
> > + *    notice, this list of conditions and the following disclaimer.
> > + * 2. Redistributions in binary form must reproduce the above copyright
> > + *    notice, this list of conditions and the following disclaimer in the
> > + *    documentation and/or other materials provided with the distribution.
> > + * 3. Neither the name of the copyright holder nor the names of its
> > + *    contributors may be used to endorse or promote products derived from
> > + *    this software without specific prior written permission.
> > + *
> > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
> > IS"
> > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
> > THE
> > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
> > PURPOSE
> > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 
> > BE
> > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
> > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
> > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
> > THE
> > + * POSSIBILITY OF SUCH DAMAGE.
> > + *
> > + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
> > + */
> > +
> > +#ifndef __UK_9PREQ__
> > +#define __UK_9PREQ__
> > +
> > +#include <inttypes.h>
> > +#include <uk/config.h>
> > +#include <uk/alloc.h>
> > +#include <uk/essentials.h>
> > +#include <uk/list.h>
> > +#include <uk/refcount.h>
> > +#if CONFIG_LIBUKSCHED
> > +#include <uk/wait_types.h>
> > +#endif
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +/*
> > + * The header consists of the following fields: size (4 bytes), type (1) 
> > and
> > + * tag (2).
> > + */
> > +#define UK_9P_HEADER_SIZE               7U
> > +
> > +/*
> > + * The maximum buffer size for an error reply is given by the header (7), 
> > the
> > + * string size (2), the error string (128) and the error code (4): in 
> > total,
> > + * 141.
> > + */
> > +#define UK_9P_RERROR_MAXSIZE            141U
> > +
> > +/**
> > + * @internal
> > + *
> > + * Describes the 9p zero-copy direction.
> > + */
> > +enum uk_9preq_zcdir {
> > +     UK_9PREQ_ZCDIR_NONE,
> > +     UK_9PREQ_ZCDIR_READ,
> > +     UK_9PREQ_ZCDIR_WRITE,
> > +};
> > +
> > +/**
> > + * @internal
> > + *
> > + * Describes a 9p fcall structure.
> > + */
> > +struct uk_9preq_fcall {
> > +     /*
> > +      * Total size of the fcall. Initially, this is the buffer size.
> > +      * After ready (on xmit) or reply (on recv), this will be the size of
> > +      * the sent/received data.
> > +      */
> > +     uint32_t                        size;
> > +     /* Type of the fcall. Should be T* for transmit, R* for receive. */
> > +     uint8_t                         type;
> > +     /* Offset while serializing or deserializing. */
> > +     uint32_t                        offset;
> > +     /* Buffer pointer. */
> > +     void                            *buf;
> > +
> > +     /* Zero-copy buffer pointer. */
> > +     void                            *zc_buf;
> > +     /* Zero-copy buffer size. */
> > +     uint32_t                        zc_size;
> > +     /* Zero-copy buffer offset in the 9P message. */
> > +     uint32_t                        zc_offset;
> > +};
> > +
> > +/**
> > + * Describes the possible states in which a request may be.
> > + *
> > + * - NONE: Right after allocating.
> > + * - INITIALIZED: Request is ready to receive serialization data.
> > + * - READY: Request is ready to be sent.
> > + * - RECEIVED: Transport layer has received the reply and important data 
> > such
> > + *   as the tag, type and size have been validated.
> > + */
> > +enum uk_9preq_state {
> > +     UK_9PREQ_NONE = 0,
> > +     UK_9PREQ_INITIALIZED,
> > +     UK_9PREQ_READY,
> > +     UK_9PREQ_SENT,
> > +     UK_9PREQ_RECEIVED
> > +};
> > +
> > +/**
> > + *  Describes a 9P request.
> > + *
> > + *  This gets allocated via uk_9pdev_req_create(), and freed when it is not
> > + *  referenced anymore. A call to uk_9pdev_req_remove() is mandatory to
> > + *  correctly free this and remove it from the list of requests managed
> > + *  by the 9p device.
> > + */
> > +struct uk_9preq {
> > +     /* Transmit fcall. */
> > +     struct uk_9preq_fcall           xmit;
> > +     /* Receive fcall. */
> > +     struct uk_9preq_fcall           recv;
> > +     /* State of the request. See the state enum for details. */
> > +     enum uk_9preq_state             state;
> > +     /* Tag allocated to this request. */
> > +     uint16_t                        tag;
> > +     /* Entry into the list of requests (API-internal). */
> > +     struct uk_list_head             _list;
> > +     /* @internal Allocator used to allocate this request. */
> > +     struct uk_alloc                 *_a;
> > +     /* Tracks the number of references to this structure. */
> > +     __atomic                        refcount;
> > +#if CONFIG_LIBUKSCHED
> > +     /* Wait-queue for state changes. */
> > +     struct uk_waitq                 wq;
> > +#endif
> > +};
> > +
> > +/**
> > + * @internal
> > + * Allocates a 9p request.
> > + * Should not be used directly, use uk_9pdev_req_create() instead.
> > + *
> > + * @param a
> > + *   Allocator to use.
> > + * @param size
> > + *   Minimum size of the receive and transmit buffers.
> > + * @return
> > + *   - (==NULL): Out of memory.
> > + *   - (!=NULL): Successful.
> > + */
> > +struct uk_9preq *uk_9preq_alloc(struct uk_alloc *a, uint32_t size);
> > +
> > +/**
> > + * Gets the 9p request, incrementing the reference count.
> > + *
> > + * @param req
> > + *   Reference to the 9p request.
> > + */
> > +void uk_9preq_get(struct uk_9preq *req);
> > +
> > +/**
> > + * Puts the 9p request, decrementing the reference count.
> > + * If this was the last live reference, the memory will be freed.
> > + *
> > + * @param req
> > + *   Reference to the 9p request.
> > + * @return
> > + *   - 0: This was not the last live reference.
> > + *   - 1: This was the last live reference.
> > + */
> > +int uk_9preq_put(struct uk_9preq *req);
> > +
> > +/*
> > + * The following family of serialization and deserialization functions work
> > + * by employing a printf-like formatting mechanism for data types 
> > supported by
> > + * the 9p protocol:
> > + * - 'b': byte (uint8_t)
> > + * - 'w': word (uint16_t)
> > + * - 'd': double-word (uint32_t)
> > + * - 'q': quad-word (uint64_t)
> > + * - 's': uk_9p_str *
> > + * - 'S': uk_9p_stat *
> > + *
> > + * Similarly to vprintf(), the vserialize() and vdeserialize() functions 
> > take
> > + * a va_list instead of a variable number of arguments.
> > + *
> > + * Possible return values:
> > + * - 0: Operation successful.
> > + * - (-EINVAL): Invalid format specifier.
> > + * - (-ENOBUFS): End of buffer reached.
> > + */
> > +
> > +int uk_9preq_vserialize(struct uk_9preq *req, const char *fmt, va_list vl);
> > +int uk_9preq_serialize(struct uk_9preq *req, const char *fmt, ...);
> > +int uk_9preq_vdeserialize(struct uk_9preq *req, const char *fmt, va_list 
> > vl);
> > +int uk_9preq_deserialize(struct uk_9preq *req, const char *fmt, ...);
> > +
> > +/**
> > + * Copies raw data from the request receive buffer to the provided buffer.
> > + *
> > + * @param req
> > + *   Reference to the 9p request.
> > + * @param buf
> > + *   Destination buffer.
> > + * @param size
> > + *   Amount to copy.
> > + * Possible return values:
> > + * - 0: Operation successful.
> > + * - (-ENOBUFS): End of buffer reached.
> > + */
> > +int uk_9preq_copy_to(struct uk_9preq *req, void *buf, uint32_t size);
> > +
> > +/**
> > + * Copies raw data from the provided buffer to the request transmission 
> > buffer.
> > + *
> > + * @param req
> > + *   Reference to the 9p request.
> > + * @param buf
> > + *   Source buffer.
> > + * @param size
> > + *   Amount to copy.
> > + * Possible return values:
> > + * - 0: Operation successful.
> > + * - (-ENOBUFS): End of buffer reached.
> > + */
> > +int uk_9preq_copy_from(struct uk_9preq *req, const void *buf, uint32_t 
> > size);
> > +
> > +/**
> > + * Marks the given request as being ready, transitioning between states
> > + * INITIALIZED and READY.
> > + *
> > + * @param req
> > + *   Reference to the 9p request.
> > + * @param zc_dir
> > + *   Zero-copy direction.
> > + * @param zc_buf
> > + *   Zero-copy buffer, if zc_dir is not NONE.
> > + * @param zc_size
> > + *   Zero-copy buffer size, if zc_dir is not NONE.
> > + * @param zc_offset
> > + *   Zero-copy offset within the received message, if zc_dir is READ.
> > + * @return
> > + *   - 0: Successful.
> > + *   - (< 0): Invalid state or request size serialization failed.
> > + */
> > +int uk_9preq_ready(struct uk_9preq *req, enum uk_9preq_zcdir zc_dir,
> > +             void *zc_buf, uint32_t zc_size, uint32_t zc_offset);
> > +
> > +/**
> > + * Function called from the transport layer when a request has been 
> > received.
> > + * Implements the transition from the SENT to the RECEIVED state.
> > + *
> > + * @param req
> > + *   The 9P request.
> > + * @param recv_size
> > + *   Size of the packet received from the transport layer.
> > + * @return
> > + *   - (0): Successfully received.
> > + *   - (< 0): An error occurred.
> > + */
> > +int uk_9preq_receive_cb(struct uk_9preq *req, uint32_t recv_size);
> > +
> > +/**
> > + * Waits for the reply to be received.
> > + *
> > + * @param req
> > + *   The 9P request.
> > + * @return
> > + *   - (0): Successful.
> > + *   - (< 0): Failed. Returns the error code received from the 9P server.
> > + */
> > +int uk_9preq_waitreply(struct uk_9preq *req);
> > +
> > +/**
> > + * Extracts the error from the received reply.
> > + *
> > + * @param req
> > + *   The 9P request.
> > + * @return
> > + *   - (0): No error occurred.
> > + *   - (< 0): An Rerror was received, the error code is 9pfs-specific.
> > + */
> > +int uk_9preq_error(struct uk_9preq *req);
> > +
> > +#ifdef __cplusplus
> > +}
> > +#endif
> > +
> > +#endif /* __UK_9PREQ__ */
> >

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