[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
Reviewed-by: Simon Kuenzer <simon.kuenzer@xxxxxxxxx> On 29.06.19 10:56, 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); + 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)/includeLIBUK9P_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 |