[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 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 |