[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |