|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH 4/6] lib/ukblkdev: Request interface
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 | 32 +++++
lib/ukblkdev/exportsyms.uk | 10 ++
lib/ukblkdev/include/uk/blkdev.h | 200 ++++++++++++++++++++++++++++++++
lib/ukblkdev/include/uk/blkdev_core.h | 63 ++++++++++
lib/ukblkdev/include/uk/blkdev_driver.h | 28 +++++
lib/ukblkdev/include/uk/blkreq.h | 110 ++++++++++++++++++
6 files changed, 443 insertions(+)
create mode 100644 lib/ukblkdev/include/uk/blkreq.h
diff --git a/lib/ukblkdev/blkdev.c b/lib/ukblkdev/blkdev.c
index 6b82cf8d..3c58061b 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)
@@ -371,3 +377,29 @@ 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_blkdev_request *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(req != NULL);
+
+ return dev->submit_one(dev, 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);
+
+ return dev->finish_reqs(dev, queue_id);
+}
diff --git a/lib/ukblkdev/exportsyms.uk b/lib/ukblkdev/exportsyms.uk
index 077994f0..5888be69 100644
--- a/lib/ukblkdev/exportsyms.uk
+++ b/lib/ukblkdev/exportsyms.uk
@@ -9,3 +9,13 @@ uk_blkdev_configure
uk_blkdev_queue_get_info
uk_blkdev_queue_configure
uk_blkdev_start
+uk_blkdev_queue_intr_enable
+uk_blkdev_queue_intr_disable
+uk_blkdev_capabilities
+uk_blkdev_ssize
+uk_blkdev_max_nb_sectors_per_req
+uk_blkdev_mode
+uk_blkdev_sectors
+uk_blkdev_align
+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 d32f62fc..db6d3b80 100644
--- a/lib/ukblkdev/include/uk/blkdev.h
+++ b/lib/ukblkdev/include/uk/blkdev.h
@@ -221,6 +221,206 @@ int uk_blkdev_queue_configure(struct uk_blkdev *dev,
*/
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
+ *
+ * @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_nb_sectors_per_req(bldev) \
+ (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_align(blkdev) \
+ (uk_blkdev_capabilities(blkdev)->align)
+/**
+ * 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, 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, 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_blkdev_request *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 364c05d7..309b7a7f 100644
--- a/lib/ukblkdev/include/uk/blkdev_core.h
+++ b/lib/ukblkdev/include/uk/blkdev_core.h
@@ -38,6 +38,7 @@
#include <uk/list.h>
#include <uk/config.h>
+#include <uk/blkreq.h>
#if defined(CONFIG_LIBUKBLKDEV_DISPATCHERTHREADS)
#include <uk/sched.h>
#include <uk/semaphore.h>
@@ -119,6 +120,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);
@@ -161,15 +165,68 @@ typedef struct uk_blkdev_queue *
(*uk_blkdev_queue_configure_t)(
uint16_t nb_desc,
const struct uk_blkdev_queue_conf *queue_conf);
+/**
+ * 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,
+ uint16_t queue_id);
+
/** Driver callback type to start a configured Unikraft block device. */
typedef int (*uk_blkdev_start_t)(struct uk_blkdev *dev);
+/**
+ * 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,
+ uint16_t queue_id);
+/**
+ * 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,
+ uint16_t queue_id,
+ struct uk_blkdev_request *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,
+ uint16_t queue_id);
+
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_queue_intr_enable_t queue_intr_enable;
uk_blkdev_start_t dev_start;
+ uk_blkdev_queue_intr_disable_t queue_intr_disable;
+};
+
+/**
+ * Device info
+ */
+struct uk_blkdev_cap {
+ /* Number of sectors */
+ __sector sectors;
+ /* Sector size */
+ __sector ssize;
+ /* Access mode */
+ int mode;
+ /* Max nb of supported sectors for an op */
+ __sector max_sectors_per_req;
+ /* Alignment for data used in future read/write requests */
+ uint16_t align;
};
/**
@@ -215,8 +272,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 b72f52ab..37b5a3e8 100644
--- a/lib/ukblkdev/include/uk/blkdev_driver.h
+++ b/lib/ukblkdev/include/uk/blkdev_driver.h
@@ -70,6 +70,34 @@ 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
+}
+
#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..85c25587
--- /dev/null
+++ b/lib/ukblkdev/include/uk/blkreq.h
@@ -0,0 +1,110 @@
+/* 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_
+
+/**
+ * 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_blkdev_request;
+
+/**
+ * Operation status
+ */
+enum uk_blkdev_req_state {
+ UK_BLKDEV_REQ_FINISHED = 0,
+ UK_BLKDEV_REQ_UNFINISHED
+};
+
+/**
+ * Supported operations
+ */
+enum uk_blkdev_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
+ */
+typedef int (*uk_blkdev_request_event_t)(struct uk_blkdev_request *req,
+ void *cookie_callback);
+
+/**
+ * Used for sending a request to the device.
+ */
+struct uk_blkdev_request {
+ /* Input members */
+ /* Operation type */
+ enum uk_blkdev_op operation;
+ /* Start Sector from where the op begin */
+ size_t start_sector;
+ /* Pointer to data */
+ void *aio_buf;
+ /* Size in number of sectors */
+ __sector nb_sectors;
+ /* Request callback and its parameters */
+ uk_blkdev_request_event_t cb;
+ void *cookie_callback;
+
+ /* Output members */
+ /* State of request: finished/unfinished*/
+ __atomic state;
+ /* Result status of operation */
+ uint8_t result_status;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UK_BLKREQ_H_ */
--
2.11.0
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |