[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH v3 4/6] lib/ukblkdev: Request interface
Thanks a lot for the changes. Reviewed-by: Simon Kuenzer <simon.kuenzer@xxxxxxxxx> On 06.10.19 14:21, Roxana Nicolescu wrote: This patch introduces the interface for sending a request and receiving a response. This is designed to support asynchronous operations. The interface permits sector-wide access only. Receiving the response from backend can be done with interrupts or with polling. Signed-off-by: Roxana Nicolescu <nicolescu.roxana1996@xxxxxxxxx> --- lib/ukblkdev/blkdev.c | 34 ++++ lib/ukblkdev/exportsyms.uk | 2 + lib/ukblkdev/include/uk/blkdev.h | 199 ++++++++++++++++++++++++ lib/ukblkdev/include/uk/blkdev_core.h | 63 ++++++++ lib/ukblkdev/include/uk/blkdev_driver.h | 37 +++++ lib/ukblkdev/include/uk/blkreq.h | 112 +++++++++++++ 6 files changed, 447 insertions(+) create mode 100644 lib/ukblkdev/include/uk/blkreq.h diff --git a/lib/ukblkdev/blkdev.c b/lib/ukblkdev/blkdev.c index f696dd5f..fcc3d75e 100644 --- a/lib/ukblkdev/blkdev.c +++ b/lib/ukblkdev/blkdev.c @@ -84,6 +84,12 @@ int uk_blkdev_drv_register(struct uk_blkdev *dev, struct uk_alloc *a, UK_ASSERT(dev->dev_ops->queue_setup); UK_ASSERT(dev->dev_ops->get_info); UK_ASSERT(dev->dev_ops->queue_get_info); + UK_ASSERT(dev->submit_one); + UK_ASSERT(dev->finish_reqs); + UK_ASSERT((dev->dev_ops->queue_intr_enable && + dev->dev_ops->queue_intr_disable) + || (!dev->dev_ops->queue_intr_enable + && !dev->dev_ops->queue_intr_disable));dev->_data = _alloc_data(a, blkdev_count, drv_name);if (!dev->_data) @@ -374,3 +380,31 @@ int uk_blkdev_start(struct uk_blkdev *dev)return rc;} + +int uk_blkdev_queue_submit_one(struct uk_blkdev *dev, + uint16_t queue_id, + struct uk_blkreq *req) +{ + UK_ASSERT(dev); + UK_ASSERT(dev->_data); + UK_ASSERT(dev->submit_one); + UK_ASSERT(queue_id < CONFIG_LIBUKBLKDEV_MAXNBQUEUES); + UK_ASSERT(dev->_data->state == UK_BLKDEV_RUNNING); + UK_ASSERT(!PTRISERR(dev->_queue[queue_id])); + UK_ASSERT(req != NULL); + + return dev->submit_one(dev, dev->_queue[queue_id], req); +} + +int uk_blkdev_queue_finish_reqs(struct uk_blkdev *dev, + uint16_t queue_id) +{ + UK_ASSERT(dev); + UK_ASSERT(dev->finish_reqs); + UK_ASSERT(dev->_data); + UK_ASSERT(queue_id < CONFIG_LIBUKBLKDEV_MAXNBQUEUES); + UK_ASSERT(dev->_data->state == UK_BLKDEV_RUNNING); + UK_ASSERT(!PTRISERR(dev->_queue[queue_id])); + + return dev->finish_reqs(dev, dev->_queue[queue_id]); +} diff --git a/lib/ukblkdev/exportsyms.uk b/lib/ukblkdev/exportsyms.uk index 077994f0..8cdb8757 100644 --- a/lib/ukblkdev/exportsyms.uk +++ b/lib/ukblkdev/exportsyms.uk @@ -9,3 +9,5 @@ uk_blkdev_configure uk_blkdev_queue_get_info uk_blkdev_queue_configure uk_blkdev_start +uk_blkdev_queue_submit_one +uk_blkdev_queue_finish_reqs diff --git a/lib/ukblkdev/include/uk/blkdev.h b/lib/ukblkdev/include/uk/blkdev.h index 375407ed..b941911c 100644 --- a/lib/ukblkdev/include/uk/blkdev.h +++ b/lib/ukblkdev/include/uk/blkdev.h @@ -222,6 +222,205 @@ int uk_blkdev_queue_configure(struct uk_blkdev *dev, uint16_t queue_id, */ int uk_blkdev_start(struct uk_blkdev *dev);+/**+ * Get the capabilities info which stores info about the device, + * like nb_of_sectors, sector_size etc + * The device state has to be UK_BLKDEV_RUNNING. + * + * @param dev + * The Unikraft Block Device. + * + * @return + * A pointer to a structure of type *uk_blkdev_capabilities*. + **/ +static inline const struct uk_blkdev_cap *uk_blkdev_capabilities( + struct uk_blkdev *blkdev) +{ + UK_ASSERT(blkdev); + UK_ASSERT(blkdev->_data->state >= UK_BLKDEV_RUNNING); + + return &blkdev->capabilities; +} + +#define uk_blkdev_ssize(blkdev) \ + (uk_blkdev_capabilities(blkdev)->ssize) + +#define uk_blkdev_max_sec_per_req(blkdev) \ + (uk_blkdev_capabilities(blkdev)->max_sectors_per_req) + +#define uk_blkdev_mode(blkdev) \ + (uk_blkdev_capabilities(blkdev)->mode) + +#define uk_blkdev_sectors(blkdev) \ + (uk_blkdev_capabilities(blkdev)->sectors) + +#define uk_blkdev_ioalign(blkdev) \ + (uk_blkdev_capabilities(blkdev)->ioalign) +/** + * Enable interrupts for a queue. + * + * @param dev + * The Unikraft Block Device in running state. + * @param queue_id + * The index of the queue to set up. + * The value must be in the range [0, nb_queue - 1] previously supplied + * to uk_blkdev_configure(). + * @return + * - (0): Success, interrupts enabled. + * - (-ENOTSUP): Driver does not support interrupts. + */ +static inline int uk_blkdev_queue_intr_enable(struct uk_blkdev *dev, + uint16_t queue_id) +{ + UK_ASSERT(dev); + UK_ASSERT(dev->dev_ops); + UK_ASSERT(dev->_data); + UK_ASSERT(queue_id < CONFIG_LIBUKBLKDEV_MAXNBQUEUES); + UK_ASSERT(!PTRISERR(dev->_queue[queue_id])); + + if (unlikely(!dev->dev_ops->queue_intr_enable)) + return -ENOTSUP; + + return dev->dev_ops->queue_intr_enable(dev, dev->_queue[queue_id]); +} + +/** + * Disable interrupts for a queue. + * + * @param dev + * The Unikraft Block Device in running state. + * @param queue_id + * The index of the queue to set up. + * The value must be in the range [0, nb_queue - 1] previously supplied + * to uk_blkdev_configure(). + * @return + * - (0): Success, interrupts disabled. + * - (-ENOTSUP): Driver does not support interrupts. + */ +static inline int uk_blkdev_queue_intr_disable(struct uk_blkdev *dev, + uint16_t queue_id) +{ + UK_ASSERT(dev); + UK_ASSERT(dev->dev_ops); + UK_ASSERT(dev->_data); + UK_ASSERT(queue_id < CONFIG_LIBUKBLKDEV_MAXNBQUEUES); + UK_ASSERT(!PTRISERR(dev->_queue[queue_id])); + + if (unlikely(!dev->dev_ops->queue_intr_disable)) + return -ENOTSUP; + + return dev->dev_ops->queue_intr_disable(dev, dev->_queue[queue_id]); +} + +/** + * Make an aio request to the device + * + * @param dev + * The Unikraft Block Device + * @param queue_id + * The index of the receive queue to receive from. + * The value must be in the range [0, nb_queue - 1] previously supplied + * to uk_blkdev_configure(). + * @param req + * Request structure + * @return + * - (>=0): Positive value with status flags + * - UK_BLKDEV_STATUS_SUCCESS: `req` was successfully put to the + * queue. + * - UK_BLKDEV_STATUS_MORE: Indicates there is still at least + * one descriptor available for a subsequent transmission. + * If the flag is unset means that the queue is full. + * This may only be set together with UK_BLKDEV_STATUS_SUCCESS. + * - (<0): Negative value with error code from driver, no request was sent. + */ +int uk_blkdev_queue_submit_one(struct uk_blkdev *dev, uint16_t queue_id, + struct uk_blkreq *req); + +/** + * Tests for status flags returned by `uk_blkdev_submit_one` + * When the function returned an error code or one of the selected flags is + * unset, this macro returns False. + * + * @param status + * Return status (int) + * @param flag + * Flag(s) to test + * @return + * - (True): All flags are set and status is not negative + * - (False): At least one flag is not set or status is negative + */ +#define uk_blkdev_status_test_set(status, flag) \ + (((int)(status) & ((int)(flag) | INT_MIN)) == (flag)) + +/** + * Tests for unset status flags returned by `uk_blkdev_submit_one` + * When the function returned an error code or one of the + * selected flags is set, this macro returns False. + * + * @param status + * Return status (int) + * @param flag + * Flag(s) to test + * @return + * - (True): Flags are not set and status is not negative + * - (False): At least one flag is set or status is negative + */ +#define uk_blkdev_status_test_unset(status, flag) \ + (((int)(status) & ((int)(flag) | INT_MIN)) == (0x0)) + +/** + * Tests if the return status of `uk_blkdev_submit_one` + * indicates a successful operation. + * + * @param status + * Return status (int) + * @return + * - (True): Operation was successful + * - (False): Operation was unsuccessful or error happened + */ +#define uk_blkdev_status_successful(status) \ + uk_blkdev_status_test_set((status), UK_BLKDEV_STATUS_SUCCESS) + +/** + * Tests if the return status of `uk_blkdev_submit_one` + * indicates that the operation should be retried/ + * + * @param status + * Return status (int) + * @return + * - (True): Operation should be retried + * - (False): Operation was successful or error happened + */ +#define uk_blkdev_status_notready(status) \ + uk_blkdev_status_test_unset((status), UK_BLKDEV_STATUS_SUCCESS) + +/** + * Tests if the return status of `uk_blkdev_submit_one` + * indicates that the last operation can be successfully repeated again. + * + * @param status + * Return status (int) + * @return + * - (True): Flag UK_BLKDEV_STATUS_MORE is set + * - (False): Operation was successful or error happened + */ +#define uk_blkdev_status_more(status) \ + uk_blkdev_status_test_set((status), (UK_BLKDEV_STATUS_SUCCESS \ + | UK_BLKDEV_STATUS_MORE)) + +/** + * Get responses from the queue + * + * @param dev + * The Unikraft Block Device + * @param queue_id + * queue id + * @return + * - 0: Success + * - (<0): on error returned by driver + */ +int uk_blkdev_queue_finish_reqs(struct uk_blkdev *dev, uint16_t queue_id); + #ifdef __cplusplus } #endif diff --git a/lib/ukblkdev/include/uk/blkdev_core.h b/lib/ukblkdev/include/uk/blkdev_core.h index c4c458ab..ae8eb07f 100644 --- a/lib/ukblkdev/include/uk/blkdev_core.h +++ b/lib/ukblkdev/include/uk/blkdev_core.h @@ -38,6 +38,8 @@#include <uk/list.h>#include <uk/config.h> +#include <uk/blkreq.h> +#include <fcntl.h> #if defined(CONFIG_LIBUKBLKDEV_DISPATCHERTHREADS) #include <uk/sched.h> #include <uk/semaphore.h> @@ -121,6 +123,9 @@ struct uk_blkdev_queue; * The queue on the Unikraft block device on which the event happened. * @param argp * Extra argument that can be defined on callback registration. + * + * Note: This should call dev->finish_reqs function in order to process the + * received responses. */ typedef void (*uk_blkdev_queue_event_t)(struct uk_blkdev *dev, uint16_t queue_id, void *argp); @@ -163,12 +168,64 @@ typedef struct uk_blkdev_queue * (*uk_blkdev_queue_configure_t)( /** Driver callback type to start a configured Unikraft block device. */ typedef int (*uk_blkdev_start_t)(struct uk_blkdev *dev);+/**+ * Driver callback type to enable interrupts + * for a queue on Unikraft block device. + **/ +typedef int (*uk_blkdev_queue_intr_enable_t)(struct uk_blkdev *dev, + struct uk_blkdev_queue *queue); + +/** + * Driver callback type to disable interrupts + * for a queue on Unikraft block device. + **/ +typedef int (*uk_blkdev_queue_intr_disable_t)(struct uk_blkdev *dev, + struct uk_blkdev_queue *queue); +/** + * Status code flags returned queue_submit_one function + */ +/** Successful operation. */ +#define UK_BLKDEV_STATUS_SUCCESS (0x1) +/** + * More room available for operation (e.g., still space on queue for sending + * a request. + */ +#define UK_BLKDEV_STATUS_MORE (0x2) + +/** Driver callback type to submit a request to Unikraft block device. */ +typedef int (*uk_blkdev_queue_submit_one_t)(struct uk_blkdev *dev, + struct uk_blkdev_queue *queue, struct uk_blkreq *req); +/** + * Driver callback type to finish + * a bunch of requests to Unikraft block device. + **/ +typedef int (*uk_blkdev_queue_finish_reqs_t)(struct uk_blkdev *dev, + struct uk_blkdev_queue *queue); + struct uk_blkdev_ops { uk_blkdev_get_info_t get_info; uk_blkdev_configure_t dev_configure; uk_blkdev_queue_get_info_t queue_get_info; uk_blkdev_queue_configure_t queue_setup; uk_blkdev_start_t dev_start; + uk_blkdev_queue_intr_enable_t queue_intr_enable; + uk_blkdev_queue_intr_disable_t queue_intr_disable; +}; + +/** + * Device info + */ +struct uk_blkdev_cap { + /* Number of sectors */ + __sector sectors; + /* Sector size */ + size_t ssize; + /* Access mode (O_RDONLY, O_RDWR, O_WRONLY) */ + int mode; + /* Max nb of supported sectors for an op */ + __sector max_sectors_per_req; + /* Alignment (number of bytes) for data used in future requests */ + uint16_t ioalign; };/**@@ -216,8 +273,14 @@ struct uk_blkdev_data { };struct uk_blkdev {+ /* Pointer to submit request function */ + uk_blkdev_queue_submit_one_t submit_one; + /* Pointer to handle_responses function */ + uk_blkdev_queue_finish_reqs_t finish_reqs; /* Pointer to API-internal state data. */ struct uk_blkdev_data *_data; + /* Capabilities. */ + struct uk_blkdev_cap capabilities; /* Functions callbacks by driver. */ const struct uk_blkdev_ops *dev_ops; /* Pointers to queues (API-private) */ diff --git a/lib/ukblkdev/include/uk/blkdev_driver.h b/lib/ukblkdev/include/uk/blkdev_driver.h index 5dc9657d..a3c41da3 100644 --- a/lib/ukblkdev/include/uk/blkdev_driver.h +++ b/lib/ukblkdev/include/uk/blkdev_driver.h @@ -69,6 +69,43 @@ extern "C" { int uk_blkdev_drv_register(struct uk_blkdev *dev, struct uk_alloc *a, const char *drv_name);+/**+ * Forwards a queue event to the API user + * Can (and should) be called from device interrupt context + * + * @param dev + * Unikraft block device to which the event relates to + * @param queue_id + * receive queue ID to which the event relates to + */ +static inline void uk_blkdev_drv_queue_event(struct uk_blkdev *dev, + uint16_t queue_id) +{ + struct uk_blkdev_event_handler *queue_handler; + + UK_ASSERT(dev); + UK_ASSERT(dev->_data); + UK_ASSERT(queue_id < CONFIG_LIBUKBLKDEV_MAXNBQUEUES); + + queue_handler = &dev->_data->queue_handler[queue_id]; + +#if CONFIG_LIBUKBLKDEV_DISPATCHERTHREADS + uk_semaphore_up(&queue_handler->events); +#else + if (queue_handler->callback) + queue_handler->callback(dev, queue_id, queue_handler->cookie); +#endif +} + +/** + * Sets a request as finished. + * + * @param req + * uk_blkreq structure + */ +#define uk_blkreq_finished(req) \ + (ukarch_store_n(&(req)->state.counter, UK_BLKDEV_REQ_FINISHED)) + #ifdef __cplusplus } #endif diff --git a/lib/ukblkdev/include/uk/blkreq.h b/lib/ukblkdev/include/uk/blkreq.h new file mode 100644 index 00000000..6467b7ee --- /dev/null +++ b/lib/ukblkdev/include/uk/blkreq.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Roxana Nicolescu <nicolescu.roxana1996@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_BLKREQ_H_ +#define UK_BLKREQ_H_ + +#include <uk/arch/types.h> + +/** + * Unikraft block API request declaration. + * + * This header contains all the API data types used for requests operation. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define __sector size_t +struct uk_blkreq; + +/** + * Operation status + */ +enum uk_blkreq_state { + UK_BLKDEV_REQ_FINISHED = 0, + UK_BLKDEV_REQ_UNFINISHED +}; + +/** + * Supported operations + */ +enum uk_blkreq_op { + /* Read operation */ + UK_BLKDEV_READ = 0, + /* Write operation */ + UK_BLKDEV_WRITE, + /* Flush the volatile write cache */ + UK_BLKDEV_FFLUSH = 4 +}; + +/** + * Function type used for request callback after a response is processed. + * + * @param req + * The request object on which the event is triggered + * @param cookie_callback + * Optional parameter set by user at request submit. + */ +typedef void (*uk_blkreq_event_t)(struct uk_blkreq *req, void *cb_cookie); + +/** + * Used for sending a request to the device. + */ +struct uk_blkreq { + /* Input members */ + /* Operation type */ + enum uk_blkreq_op operation; + /* Start Sector from where the op begin */ + __sector start_sector; + /* Size in number of sectors */ + __sector nb_sectors; + /* Pointer to data */ + void *aio_buf; + /* Request callback and its parameters */ + uk_blkreq_event_t cb; + void *cb_cookie; + + /* Output members */ + /* State of request: finished/unfinished*/ + __atomic state; + /* Result status of operation (< 0 on errors)*/ + int result; + +}; + +#ifdef __cplusplus +} +#endif + +#endif /* UK_BLKREQ_H_ */ _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |