[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH v2 5/8] lib/uk9p: Add 9P device implementation
On 29.06.19 10:56, Cristian Banu wrote: This patch adds the operations that should be supported by transport layers, the API to interact with them and to manage requests. Signed-off-by: Cristian Banu <cristb@xxxxxxxxx> --- lib/uk9p/9pdev.c | 326 ++++++++++++++++++++++++++++++++++++++ lib/uk9p/9pdev_trans.c | 4 + lib/uk9p/Makefile.uk | 1 + lib/uk9p/exportsyms.uk | 9 ++ lib/uk9p/include/uk/9pdev.h | 188 ++++++++++++++++++++++ lib/uk9p/include/uk/9pdev_core.h | 169 ++++++++++++++++++++ lib/uk9p/include/uk/9pdev_trans.h | 3 + 7 files changed, 700 insertions(+) create mode 100644 lib/uk9p/9pdev.c create mode 100644 lib/uk9p/include/uk/9pdev.h create mode 100644 lib/uk9p/include/uk/9pdev_core.h diff --git a/lib/uk9p/9pdev.c b/lib/uk9p/9pdev.c new file mode 100644 index 000000000000..05a581eafbdb --- /dev/null +++ b/lib/uk9p/9pdev.c @@ -0,0 +1,326 @@ +/* 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 <stdbool.h> +#include <string.h> +#include <uk/config.h> +#include <uk/plat/spinlock.h> +#include <uk/alloc.h> +#include <uk/essentials.h> +#include <uk/errptr.h> +#include <uk/bitmap.h> +#include <uk/refcount.h> +#include <uk/wait.h> +#include <uk/9pdev.h> +#include <uk/9pdev_trans.h> +#include <uk/9preq.h> +#if CONFIG_LIBUKSCHED +#include <uk/sched.h> +#include <uk/wait.h> +#endif + +static int _req_mgmt_init(struct uk_9pdev_req_mgmt *req_mgmt) +{ + ukarch_spin_lock_init(&req_mgmt->spinlock); + uk_bitmap_zero(req_mgmt->tag_bm, UK_9P_NUMTAGS); + UK_INIT_LIST_HEAD(&req_mgmt->req_list); + + return 0; +} I think this function can be void, right? + +static void _req_mgmt_add_req_locked(struct uk_9pdev_req_mgmt *req_mgmt, + struct uk_9preq *req) +{ + uk_bitmap_set(req_mgmt->tag_bm, req->tag, 1); + uk_list_add(&req->_list, &req_mgmt->req_list); +} + +static void _req_mgmt_del_req_locked(struct uk_9pdev_req_mgmt *req_mgmt, + struct uk_9preq *req) +{ + uk_bitmap_clear(req_mgmt->tag_bm, req->tag, 1); + uk_list_del(&req->_list); +} + +static int _req_mgmt_next_tag_locked(struct uk_9pdev_req_mgmt *req_mgmt, + uint16_t *tag) +{ + *tag = uk_find_next_zero_bit(req_mgmt->tag_bm, UK_9P_NUMTAGS, 0); + + return 0; +} Don't you want to return the tag instead using it as output parameter? There are no errors returned. Otherwise this function can be void. + +static void _req_mgmt_cleanup(struct uk_9pdev_req_mgmt *req_mgmt __unused) +{ + unsigned long flags; + uint16_t tag; + struct uk_9preq *req, *reqn; + + ukplat_spin_lock_irqsave(&req_mgmt->spinlock, flags); + uk_list_for_each_entry_safe(req, reqn, &req_mgmt->req_list, _list) { + tag = req->tag; + _req_mgmt_del_req_locked(req_mgmt, req); + if (!uk_9preq_put(req)) { + uk_pr_warn("Tag %d still has references on cleanup.\n", + tag); + } + } + ukplat_spin_unlock_irqrestore(&req_mgmt->spinlock, flags); +} + +struct uk_9pdev *uk_9pdev_connect(const struct uk_9pdev_trans *trans, + const char *device_identifier, + const char *mount_args, + struct uk_alloc *a) +{ + struct uk_9pdev *dev; + int rc = 0; + + UK_ASSERT(trans); + UK_ASSERT(device_identifier); + + if (a == NULL) + a = trans->a; + + dev = uk_calloc(a, 1, sizeof(*dev)); + if (dev == NULL) { + rc = -ENOMEM; + goto out; + } + + dev->ops = trans->ops; + dev->a = a; + +#if CONFIG_LIBUKSCHED + uk_waitq_init(&dev->xmit_wq); +#endif + + rc = _req_mgmt_init(&dev->_req_mgmt); + if (rc < 0) + goto free_dev; + + rc = dev->ops->connect(dev, device_identifier, mount_args); + if (rc < 0) + goto free_req; + + UK_ASSERT(dev->msize != 0); + + dev->state = UK_9PDEV_CONNECTED; + goto out; + Minor thing: Since you do not need any clean-up in the success exit, you could return here the dev directly and remove the if statement in the out-case (which becomes to an error-only exit). +free_req: + _req_mgmt_cleanup(&dev->_req_mgmt); +free_dev: + uk_free(a, dev); +out: + if (rc == 0) + return dev; + return ERR2PTR(rc); +} + +int uk_9pdev_disconnect(struct uk_9pdev *dev) +{ + int rc = 0; + + UK_ASSERT(dev); + UK_ASSERT(dev->state == UK_9PDEV_CONNECTED); + + dev->state = UK_9PDEV_DISCONNECTING; + + /* Clean up the requests before closing the channel. */ + _req_mgmt_cleanup(&dev->_req_mgmt); + + rc = dev->ops->disconnect(dev); It seems in case of driver failure on disconnect you still proceed with disconnecting. Is this intended? + + uk_free(dev->a, dev); + return rc; +} + +int uk_9pdev_request(struct uk_9pdev *dev, struct uk_9preq *req) +{ + int rc; + + UK_ASSERT(dev); + UK_ASSERT(req); + + if (UK_READ_ONCE(req->state) != UK_9PREQ_READY) { + rc = -EINVAL; + goto out; + } + + if (dev->state != UK_9PDEV_CONNECTED) { + rc = -EIO; + goto out; + } + +#if CONFIG_LIBUKSCHED + uk_waitq_wait_event(&dev->xmit_wq, + (rc = dev->ops->request(dev, req)) >= 0 || rc != -ENOSPC); +#else + rc = -ENOSPC; + while (rc < 0 && rc == -ENOSPC) Isn't the condition (rc == -ENOSPC) good enough for the while loop? It looks also to me that a 'do {} while()' loop would be nicer in this case. + rc = dev->ops->request(dev, req); +#endif + +out: + return rc; +} + +void uk_9pdev_xmit_ready(struct uk_9pdev *dev) +{ +#if CONFIG_LIBUKSCHED + uk_waitq_wake_up(&dev->xmit_wq); +#endif +} + +struct uk_9preq *uk_9pdev_call(struct uk_9pdev *dev, uint8_t type, + uint32_t size, const char *fmt, ...) +{ + struct uk_9preq *req; + va_list vl; + int rc; + + req = uk_9pdev_req_create(dev, type, size); + if (PTRISERR(req)) + return req; + + va_start(vl, fmt); + rc = uk_9preq_vserialize(req, fmt, vl); + va_end(vl); + + if (rc < 0) + goto out; + + rc = uk_9preq_ready(req, UK_9PREQ_ZCDIR_NONE, NULL, 0, 0); + if (rc < 0) + goto out; + + rc = uk_9pdev_request(dev, req); + if (rc < 0) + goto out; + + rc = uk_9preq_waitreply(req); + if (rc < 0) + goto out; + + return req; +out: + uk_9pdev_req_remove(dev, req); + return ERR2PTR(rc); +} + +struct uk_9preq *uk_9pdev_req_create(struct uk_9pdev *dev, uint8_t type, + uint32_t size) +{ + struct uk_9preq *req; + int rc = 0; + uint16_t tag; + unsigned long flags; + + UK_ASSERT(dev); + + size = MIN(size, dev->msize); + + req = uk_9preq_alloc(dev->a, size); + if (req == NULL) { + rc = -ENOMEM; + goto out; + } + + ukplat_spin_lock_irqsave(&dev->_req_mgmt.spinlock, flags); + if (type == UK_9P_TVERSION) { + tag = UK_9P_NOTAG; + rc = 0; + } else + rc = _req_mgmt_next_tag_locked(&dev->_req_mgmt, &tag); + + if (rc < 0) { + ukplat_spin_unlock_irqrestore(&dev->_req_mgmt.spinlock, flags); + goto out_free; + } + + req->tag = tag; + req->xmit.type = type; + + _req_mgmt_add_req_locked(&dev->_req_mgmt, req); + ukplat_spin_unlock_irqrestore(&dev->_req_mgmt.spinlock, flags); + + req->state = UK_9PREQ_INITIALIZED; + goto out; I think you can also here directly return so that you do not need the if statement after the out label. But this is really a minor thing. + +out_free: + uk_9preq_put(req); +out: + if (rc == 0) + return req; + return ERR2PTR(rc); +} + +struct uk_9preq *uk_9pdev_req_lookup(struct uk_9pdev *dev, uint16_t tag) +{ + unsigned long flags; + struct uk_9preq *req; + int rc = -EINVAL; + + ukplat_spin_lock_irqsave(&dev->_req_mgmt.spinlock, flags); + uk_list_for_each_entry(req, &dev->_req_mgmt.req_list, _list) { + if (tag != req->tag) + continue; + rc = 0; + uk_9preq_get(req); + break; + } + ukplat_spin_unlock_irqrestore(&dev->_req_mgmt.spinlock, flags); + + if (rc == 0) + return req; + + return ERR2PTR(rc); +} + +int uk_9pdev_req_remove(struct uk_9pdev *dev, struct uk_9preq *req) +{ + unsigned long flags; + + ukplat_spin_lock_irqsave(&dev->_req_mgmt.spinlock, flags); + _req_mgmt_del_req_locked(&dev->_req_mgmt, req); + ukplat_spin_unlock_irqrestore(&dev->_req_mgmt.spinlock, flags); + + return uk_9preq_put(req); +} + +void uk_9pdev_adjust_msize(struct uk_9pdev *dev, uint32_t msize) +{ + dev->msize = MIN(dev->msize, msize); +} Hum, with this function you can only decrease the msize, never increase. You are also never getting a feedback on which size the device is operating now. Is all of this intended? Otherwise I would return an int to tell if the wished msize is out of range. I also would save the max possible msize separately from the current applied msize on the uk_9pdev structure. diff --git a/lib/uk9p/9pdev_trans.c b/lib/uk9p/9pdev_trans.c index 6372876765b2..0da50e51206e 100644 --- a/lib/uk9p/9pdev_trans.c +++ b/lib/uk9p/9pdev_trans.c @@ -47,6 +47,10 @@ int uk_9pdev_trans_register(struct uk_9pdev_trans *trans) { UK_ASSERT(trans); UK_ASSERT(trans->name); + UK_ASSERT(trans->ops); + UK_ASSERT(trans->ops->connect); + UK_ASSERT(trans->ops->disconnect); + UK_ASSERT(trans->ops->request); UK_ASSERT(trans->a);uk_list_add_tail(&trans->_list, &uk_9pdev_trans_list);diff --git a/lib/uk9p/Makefile.uk b/lib/uk9p/Makefile.uk index aea722a585b9..34cc987a2f9c 100644 --- a/lib/uk9p/Makefile.uk +++ b/lib/uk9p/Makefile.uk @@ -5,3 +5,4 @@ CXXINCLUDES-$(CONFIG_LIBUK9P) += -I$(LIBUK9P_BASE)/includeLIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9pdev_trans.cLIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9preq.c +LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9pdev.c diff --git a/lib/uk9p/exportsyms.uk b/lib/uk9p/exportsyms.uk index 850ffa2db233..c373308fb0a2 100644 --- a/lib/uk9p/exportsyms.uk +++ b/lib/uk9p/exportsyms.uk @@ -12,3 +12,12 @@ uk_9preq_copy_from uk_9preq_receive_cb uk_9preq_waitreply uk_9preq_error +uk_9pdev_connect +uk_9pdev_disconnect +uk_9pdev_request +uk_9pdev_xmit_ready +uk_9pdev_call +uk_9pdev_req_create +uk_9pdev_req_lookup +uk_9pdev_req_remove +uk_9pdev_adjust_msize diff --git a/lib/uk9p/include/uk/9pdev.h b/lib/uk9p/include/uk/9pdev.h new file mode 100644 index 000000000000..f2210bbffc92 --- /dev/null +++ b/lib/uk9p/include/uk/9pdev.h @@ -0,0 +1,188 @@ +/* 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_9PDEV__ +#define __UK_9PDEV__ + +#include <inttypes.h> +#include <uk/config.h> +#include <uk/alloc.h> +#include <uk/assert.h> +#include <uk/essentials.h> +#include <uk/9pdev_core.h> +#include <uk/plat/irq.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct uk_9pdev_trans; + +/** + * Connect to an underlying device, obtaining a 9pdev handle to the connection. + * + * @param trans + * The underlying transport. + * @param device_identifier + * The identifier of the device (for virtio and xen, the mount tag). + * @param mount_args + * Arguments passed down from the mount() call. + * @param a + * (Optional) Allocator used for any allocations done by this 9pdev. + * If NULL, the transport-specific allocator will be used. + * @return + * - Connection handle, if successful. + * - Error pointer, otherwise. + */ +struct uk_9pdev *uk_9pdev_connect(const struct uk_9pdev_trans *trans, + const char *device_identifier, + const char *mount_args, + struct uk_alloc *a); + +/** + * Disconnect from the underlying device. + * + * @param dev + * The Unikraft 9P Device. + * @return + * - (0): Successful. + * - (< 0): Failure to disconnect. + */ +int uk_9pdev_disconnect(struct uk_9pdev *dev); I think you should either document that even in case of failure the device is closed or expect that the user is retrying to disconnect. + +/** + * Send a 9P request to the given 9P device. + * + * @param dev + * The Unikraft 9P Device. + * @param req + * The 9P request. + * @return + * - (0): Successful. + * - (< 0): Failed. + */ +int uk_9pdev_request(struct uk_9pdev *dev, struct uk_9preq *req); + +/** + * Notify the 9P device that the device's transmit queue is not full and + * it may attempt to send requests again. + * + * @param dev + * The Unikraft 9P Device. + */ +void uk_9pdev_xmit_ready(struct uk_9pdev *dev); Maybe call this function then ..._xmit_notify() instead? + +/** + * Creates and sends 9P request to the given 9P device, serializing it with + * the given arguments. This function acts as a shorthand for the explicit + * calls to req_create(), serialize(), ready(), request(), waitreply(). + * + * @param dev + * The Unikraft 9P Device. + * @param type + * Transmit type of the request, e.g. Tversion, Tread, and so on. + * @param size + * The maximum size for the receive and send buffers. + * @param fmt + * The format of the data to be serialized, in the way uk_9preq_serialize() + * expects it. + * @param ... + * The arguments to be serialized. + * @return + * - (!PTRISERR): The 9p request in the UK_9PREQ_RECEIVED state. + * - PTRISERR: The error code with which any of the steps failed. + */ +struct uk_9preq *uk_9pdev_call(struct uk_9pdev *dev, uint8_t type, + uint32_t size, const char *fmt, ...); + +/** + * Create a new request, automatically allocating its tag, based on its type. + * + * @param dev + * The Unikraft 9P Device. + * @param type + * Transmit type of the request, e.g. Tversion, Tread, and so on. + * @param size + * The maximum size for the receive and send buffers. + * @return + * If not an error pointer, the created request. + * Otherwise, the error in creating the request: + * - ENOMEM: No memory for the request or no available tags. + */ +struct uk_9preq *uk_9pdev_req_create(struct uk_9pdev *dev, uint8_t type, + uint32_t size); + +/** + * Looks up a request based on the given tag. This is generally used by + * transport layers on receiving a 9P message. + * + * @param dev + * The Unikraft 9P Device. + * @param tag + * The tag to look up. + * @return + * - NULL: No request with the given tag was found. + * - (!=NULL): The request. + */ +struct uk_9preq *uk_9pdev_req_lookup(struct uk_9pdev *dev, uint16_t tag); + +/** + * Remove a request from the given 9p device. If the request is in-flight, + * it will be freed when all the references to it are gone. + * + * @param dev + * The Unikraft 9P Device. + * @param req + * The request to be removed. + * @return + * - 0: There are more active references. + * - 1: This was the last reference to the request. + */ +int uk_9pdev_req_remove(struct uk_9pdev *dev, struct uk_9preq *req); + +/** + * Adjusts the message size to the given maximum size. + * + * @param dev + * The Unikraft 9P Device. + * @param msize + * Allowed maximum message size. + */ +void uk_9pdev_adjust_msize(struct uk_9pdev *dev, uint32_t msize); + +#ifdef __cplusplus +} +#endif + +#endif /* __UK_9PDEV__ */ diff --git a/lib/uk9p/include/uk/9pdev_core.h b/lib/uk9p/include/uk/9pdev_core.h new file mode 100644 index 000000000000..d7ef341e12d6 --- /dev/null +++ b/lib/uk9p/include/uk/9pdev_core.h @@ -0,0 +1,169 @@ +/* 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_9PDEV_CORE__ +#define __UK_9PDEV_CORE__ + +#include <string.h> +#include <inttypes.h> +#include <uk/config.h> +#include <uk/arch/spinlock.h> +#include <uk/bitmap.h> +#include <uk/list.h> +#include <uk/9p_core.h> +#if CONFIG_LIBUKSCHED +#include <uk/wait_types.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct uk_9pdev; +struct uk_9preq; + +/** + * Function type used for connecting to a device on a certain transport. + * The implementation should also set the msize field in the 9P device + * struct to the maximum allowed message size. + * + * @param dev + * The Unikraft 9P Device. + * @param device_identifier + * The identifier of the underlying device (mount_tag for virtio, etc.) + * @param mount_args + * Arguments received by the mount() call, for transport-specific options. + * @return + * - (-EBUSY): Device is already in-use. + * - (-ENOENT): Device does not exist. + * - (0): Successful. + * - (< 0): Failed with a transport layer dependent error. + */ +typedef int (*uk_9pdev_connect_t)(struct uk_9pdev *dev, + const char *device_identifier, + const char *mount_args); + +/** + * Function type used for disconnecting from the device. + * + * @param dev + * The Unikraft 9P Device. + * @return + * - (0): Successful. + * - (< 0): Failed with a transport layer dependent error. + */ +typedef int (*uk_9pdev_disconnect_t)(struct uk_9pdev *dev); + +/** + * Function type used for sending a request to the 9P device. + * + * @param dev + * The Unikraft 9P device. + * @param req + * Reference to the request to be sent. + * @return + * - (0): Successful. + * - (< 0): Failed. If -ENOSPC, then the transport layer does not have enough + * space to send this request and retries are required. + */ +typedef int (*uk_9pdev_request_t)(struct uk_9pdev *dev, + struct uk_9preq *req); + +/** + * A structure used to store the operations supported by a certain transport. + */ +struct uk_9pdev_trans_ops { + uk_9pdev_connect_t connect; + uk_9pdev_disconnect_t disconnect; + uk_9pdev_request_t request; +}; + +/** + * @internal + * A structure used for 9p requests' management. + */ +struct uk_9pdev_req_mgmt { + /* Spinlock protecting this data. */ + spinlock_t spinlock; + /* Bitmap of available tags. */ + unsigned long tag_bm[UK_BITS_TO_LONGS(UK_9P_NUMTAGS)]; + /* List of requests allocated and not yet removed. */ + struct uk_list_head req_list; +}; + +/** + * @internal + * 9PDEV transport state + * + * - CONNECTED: Default state after initialization and during normal operation. + * - DISCONNECTING: After a uk_9pdev_disconnect() call. + * No requests are allowed anymore. When all live resources have been + * destroyed, the 9pdev will free itself. + */ +enum uk_9pdev_trans_state { + UK_9PDEV_CONNECTED, + UK_9PDEV_DISCONNECTING +}; + +/** + * 9PDEV + * A structure used to interact with a 9P device. + */ +struct uk_9pdev { + /* Underlying transport operations. */ + const struct uk_9pdev_trans_ops *ops; + /* Allocator used by this device. */ + struct uk_alloc *a; /* See uk_9pdev_connect(). */ + /* Transport state. */ + enum uk_9pdev_trans_state state; + /* Maximum size of a message. */ + uint32_t msize; + /* Transport-allocated data. */ + void *priv; + /* @internal Request management. */ + struct uk_9pdev_req_mgmt _req_mgmt; +#if CONFIG_LIBUKSCHED + /* + * Slept on by threads waiting for their turn for enough space to send + * the request. + */ + struct uk_waitq xmit_wq; +#endif +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __UK_9PDEV_CORE__ */ diff --git a/lib/uk9p/include/uk/9pdev_trans.h b/lib/uk9p/include/uk/9pdev_trans.h index 7b6645fb5e84..d73af3e3beac 100644 --- a/lib/uk9p/include/uk/9pdev_trans.h +++ b/lib/uk9p/include/uk/9pdev_trans.h @@ -37,6 +37,7 @@#include <stdbool.h>#include <uk/config.h> +#include <uk/9pdev_core.h>#ifdef __cplusplusextern "C" { @@ -51,6 +52,8 @@ struct uk_9pdev_trans { * specific transport. */ const char *name; + /* Supported operations. */ + const struct uk_9pdev_trans_ops *ops; /* Can the transport be used as a default one? */ bool is_default; /* Allocator used for devices which use this transport layer. */ _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |