[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH v2 5/6] lib/ukblkdev: Synchronous requests interface
Hey,I like this new version of this patch. However, I have a few comments to your uk_blkreq_is_done() and uk_blkreq_init() helpers. Thanks, Simon On 01.07.19 12:04, Roxana Nicolescu wrote: This patch introduces sync operations. It requires the use of semaphore in the implementation. Signed-off-by: Roxana Nicolescu <nicolescu.roxana1996@xxxxxxxxx> --- lib/ukblkdev/Config.uk | 9 ++++++ lib/ukblkdev/blkdev.c | 58 +++++++++++++++++++++++++++++++++++ lib/ukblkdev/exportsyms.uk | 5 +++ lib/ukblkdev/include/uk/blkdev.h | 50 ++++++++++++++++++++++++++++++ lib/ukblkdev/include/uk/blkdev_core.h | 3 +- lib/ukblkdev/include/uk/blkreq.h | 36 ++++++++++++++++++++++ 6 files changed, 160 insertions(+), 1 deletion(-) diff --git a/lib/ukblkdev/Config.uk b/lib/ukblkdev/Config.uk index f0c89654..d5c96090 100644 --- a/lib/ukblkdev/Config.uk +++ b/lib/ukblkdev/Config.uk @@ -25,4 +25,13 @@ if LIBUKBLKDEV When this option is enabled a dispatcher thread is allocated for each configured queue. libuksched is required for this option. + + config LIBUKBLKDEV_SYNC_IO_BLOCKED_WAITING + bool "Synchronous I/O API" + default n + select LIBUKSCHED + select LIBUKLOCK + select LIBUKLOCK_SEMAPHORE + help + Use semaphore for waiting after a request I/O is done. endif diff --git a/lib/ukblkdev/blkdev.c b/lib/ukblkdev/blkdev.c index a92b29f1..21346d50 100644 --- a/lib/ukblkdev/blkdev.c +++ b/lib/ukblkdev/blkdev.c @@ -408,3 +408,61 @@ int uk_blkdev_queue_finish_reqs(struct uk_blkdev *dev,return dev->finish_reqs(dev, dev->_queue[queue_id]);} + +#if CONFIG_LIBUKBLKDEV_SYNC_IO_BLOCKED_WAITING +/** + * Used for sending a synchronous request. + */ +struct uk_blkdev_sync_io_request { + struct uk_blkreq req; /* Request structure. */ + + /* Semaphore used for waiting after the response is done. */ + struct uk_semaphore s; +}; + +static void __sync_io_callback(struct uk_blkreq *req, + void *cookie_callback) +{ + struct uk_blkdev_sync_io_request *sync_io_req; + + UK_ASSERT(req); + UK_ASSERT(cookie_callback); + + sync_io_req = (struct uk_blkdev_sync_io_request *)cookie_callback; + uk_semaphore_up(&sync_io_req->s); +} + +int uk_blkdev_sync_io(struct uk_blkdev *dev, + uint16_t queue_id, + enum uk_blkreq_op operation, + __sector start_sector, + __sector nb_sectors, + void *buf) +{ + struct uk_blkreq *req; + int rc = 0; + struct uk_blkdev_sync_io_request sync_io_req; + + UK_ASSERT(dev != NULL); + UK_ASSERT(queue_id < CONFIG_LIBUKBLKDEV_MAXNBQUEUES); + UK_ASSERT(dev->_data); + UK_ASSERT(dev->submit_one); + UK_ASSERT(dev->_data->state == UK_BLKDEV_RUNNING); + UK_ASSERT(!PTRISERR(dev->_queue[queue_id])); + + req = &sync_io_req.req; + uk_blkreq_init(req, operation, start_sector, nb_sectors, + __sync_io_callback, (void *)&sync_io_req, buf); + uk_semaphore_init(&sync_io_req.s, 0); + + rc = uk_blkdev_queue_submit_one(dev, queue_id, req); + if (unlikely(!uk_blkdev_status_successful(rc))) { + uk_pr_err("blkdev%"PRIu16"-q%"PRIu16": Failed to submit I/O req: %d\n", + dev->_data->id, queue_id, rc); + return rc; + } + + uk_semaphore_down(&sync_io_req.s); + return req->result; +} +#endif diff --git a/lib/ukblkdev/exportsyms.uk b/lib/ukblkdev/exportsyms.uk index 33402f78..85135b95 100644 --- a/lib/ukblkdev/exportsyms.uk +++ b/lib/ukblkdev/exportsyms.uk @@ -19,3 +19,8 @@ uk_blkdev_sectors uk_blkdev_ioalign uk_blkdev_queue_submit_one uk_blkdev_queue_finish_reqs +uk_blkreq_init +uk_blkdev_sync_io +uk_blkdev_sync_read +uk_blkdev_sync_write uk_blkreq_init, uk_blkdev_sync_read, and uk_blkdev_sync_write are not needed to be listed in exportsyms.uk. It doesn't hurt but they are just defined as macro and static inline function in the header. +uk_blkreq_is_done diff --git a/lib/ukblkdev/include/uk/blkdev.h b/lib/ukblkdev/include/uk/blkdev.h index b941911c..ad0f2629 100644 --- a/lib/ukblkdev/include/uk/blkdev.h +++ b/lib/ukblkdev/include/uk/blkdev.h @@ -421,6 +421,56 @@ int uk_blkdev_queue_submit_one(struct uk_blkdev *dev, uint16_t queue_id, */ int uk_blkdev_queue_finish_reqs(struct uk_blkdev *dev, uint16_t queue_id);+#if CONFIG_LIBUKBLKDEV_SYNC_IO_BLOCKED_WAITING+/** + * Make a sync io request on a specific queue. + * `uk_blkdev_queue_finish_reqs()` must be called in queue interrupt context + * or another thread context in order to avoid blocking of the thread forever. + * + * @param dev + * The Unikraft Block Device + * @param queue_id + * queue_id + * @param op + * Type of operation + * @param sector + * Start Sector + * @param nb_sectors + * Number of sectors + * @param buf + * Buffer where data is found + * @return + * - 0: Success + * - (<0): on error returned by driver + */ +int uk_blkdev_sync_io(struct uk_blkdev *dev, + uint16_t queue_id, + enum uk_blkreq_op op, + __sector sector, + __sector nb_sectors, + void *buf); + +/* + * Wrappers for uk_blkdev_sync_io + */ +#define uk_blkdev_sync_write(blkdev,\ + queue_id, \ + sector, \ + nb_sectors, \ + buf) \ + uk_blkdev_sync_io(blkdev, queue_id, UK_BLKDEV_WRITE, sector, \ + nb_sectors, buf) \ + +#define uk_blkdev_sync_read(blkdev,\ + queue_id, \ + sector, \ + nb_sectors, \ + buf) \ + uk_blkdev_sync_io(blkdev, queue_id, UK_BLKDEV_READ, sector, \ + nb_sectors, buf) \ + +#endif + #ifdef __cplusplus } #endif diff --git a/lib/ukblkdev/include/uk/blkdev_core.h b/lib/ukblkdev/include/uk/blkdev_core.h index 13cd44ba..8bf08cdd 100644 --- a/lib/ukblkdev/include/uk/blkdev_core.h +++ b/lib/ukblkdev/include/uk/blkdev_core.h @@ -39,7 +39,8 @@ #include <uk/list.h> #include <uk/config.h> #include <uk/blkreq.h> -#if defined(CONFIG_LIBUKBLKDEV_DISPATCHERTHREADS) +#if defined(CONFIG_LIBUKBLKDEV_DISPATCHERTHREADS) || \ + defined(CONFIG_LIBUKBLKDEV_SYNC_IO_BLOCKED_WAITING) #include <uk/sched.h> #include <uk/semaphore.h> #endif diff --git a/lib/ukblkdev/include/uk/blkreq.h b/lib/ukblkdev/include/uk/blkreq.h index aa2cf9c4..8d499cf6 100644 --- a/lib/ukblkdev/include/uk/blkreq.h +++ b/lib/ukblkdev/include/uk/blkreq.h @@ -105,6 +105,42 @@ struct uk_blkreq {}; +/**+ * Initializes a request structure. + * + * @param req + * The request structure + * @param op + * The operation + * @param start + * The start sector + * @param nb_sectors + * Number of sectors + * @param cb + * Request callback + * @param cb_cookie + * Request callback parameters + * @param aio_buf + * Data buffer + **/ +static inline void uk_blkreq_init(struct uk_blkreq *req, + enum uk_blkreq_op op, __sector start, __sector nb_sectors, + uk_blkreq_event_t cb, void *cb_cookie, void *aio_buf) +{ + req->operation = op; + req->start_sector = start; + req->nb_sectors = nb_sectors; + uk_refcount_init(&req->state, UK_BLKDEV_REQ_UNFINISHED); Hum, I think you are not using this as a reference counter, so I would use the functions from `<uk/arch/atomic.h>` instead (not <uk/refcount.h>). ukarch_store_n(&req->state.counter, UK_BLKDEV_REQ_UNFINISHED); Please also make sure you include the correct header.Note that I noticed that the atomics API is a bit brokwn, this is why you need to handover the field for now. + req->cb = cb; + req->cb_cookie = cb_cookie; + req->aio_buf = aio_buf; +} + +/** + * Check if request is finished. + **/ +#define uk_blkreq_is_done(req) ((req)->state == UK_BLKDEV_REQ_FINISHED) I think you should use ukarch_load_n(): #define uk_blkreq_is_done(req) \ (ukarch_load_n(&(req)->state.counter) == UK_BLKDEV_REQ_FINISHED) Could you also provide a helper for drivers to blkdev_driver.h?: #define uk_blkreq_finished(req) \ (ukarch_store_n(&(req)->state.counter, UK_BLKDEV_REQ_FINISHED) + #ifdef __cplusplus } #endif _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |