Signed-off-by: Zhi Yong Wu <wuzhy@xxxxxxxxxxxxxxxxxx> --- Makefile.objs | 2 +- block/blk-queue.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++++ block/blk-queue.h | 63 +++++++++++++++ 3 files changed, 290 insertions(+), 1 deletions(-) create mode 100644 block/blk-queue.c create mode 100644 block/blk-queue.h diff --git a/Makefile.objs b/Makefile.objs index d1f3e5d..96a7323 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -33,7 +33,7 @@ block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vv block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o block-nested-y += qed-check.o -block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o +block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o blk-queue.o block-nested-$(CONFIG_WIN32) += raw-win32.o block-nested-$(CONFIG_POSIX) += raw-posix.o block-nested-$(CONFIG_CURL) += curl.o diff --git a/block/blk-queue.c b/block/blk-queue.c new file mode 100644 index 0000000..eac824c --- /dev/null +++ b/block/blk-queue.c @@ -0,0 +1,226 @@ +/* + * QEMU System Emulator queue definition for block layer + * + * Copyright (c) IBM, Corp. 2011 + * + * Authors: + * Zhi Yong Wu <zwu.kernel@xxxxxxxxx> + * Stefan Hajnoczi <stefanha@xxxxxxxxx> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "block_int.h" +#include "block/blk-queue.h" +#include "qemu-common.h" + +/* The APIs for block request queue on qemu block layer. + */ + +struct BlockIORequest { + QTAILQ_ENTRY(BlockIORequest) entry; + BlockDriverState *bs; + BlockRequestHandler *handler; + int64_t sector_num; + QEMUIOVector *qiov; + int nb_sectors; + BlockDriverCompletionFunc *cb; + void *opaque; + BlockDriverAIOCB *acb; +}; + +struct BlockQueue { + QTAILQ_HEAD(requests, BlockIORequest) requests; + BlockIORequest *request; + bool flushing; +}; + +struct BlockQueueAIOCB { + BlockDriverAIOCB common; + BlockDriverCompletionFunc *real_cb; + BlockDriverAIOCB *real_acb; + void *opaque; + BlockIORequest *request; +}; + +static void qemu_block_queue_dequeue(BlockQueue *queue, BlockIORequest *request) +{ + BlockIORequest *req; + + while (!QTAILQ_EMPTY(&queue->requests)) { + req = QTAILQ_FIRST(&queue->requests); + if (req == request) { + QTAILQ_REMOVE(&queue->requests, req, entry); + break; + } + } +} + +static void qemu_block_queue_cancel(BlockDriverAIOCB *acb) +{ + BlockQueueAIOCB *blkacb = container_of(acb, BlockQueueAIOCB, common); + if (blkacb->real_acb) { + bdrv_aio_cancel(blkacb->real_acb); + } else { + assert(blkacb->common.bs->block_queue); + qemu_block_queue_dequeue(blkacb->common.bs->block_queue, + blkacb->request); + } + + qemu_aio_release(blkacb); +} + +static AIOPool block_queue_pool = { + .aiocb_size = sizeof(struct BlockQueueAIOCB), + .cancel = qemu_block_queue_cancel, +}; + +static void qemu_block_queue_callback(void *opaque, int ret) +{ + BlockQueueAIOCB *acb = opaque; + + if (acb->real_cb) { + acb->real_cb(acb->opaque, ret); + } + + qemu_aio_release(acb); +} + +BlockQueue *qemu_new_block_queue(void) +{ + BlockQueue *queue; + + queue = g_malloc0(sizeof(BlockQueue)); + + QTAILQ_INIT(&queue->requests); + + queue->flushing = false; + queue->request = NULL; + + return queue; +} + +void qemu_del_block_queue(BlockQueue *queue) +{ + BlockIORequest *request, *next; + + QTAILQ_FOREACH_SAFE(request, &queue->requests, entry, next) { + QTAILQ_REMOVE(&queue->requests, request, entry); + g_free(request); + } + + g_free(queue); +} + +BlockDriverAIOCB *qemu_block_queue_enqueue(BlockQueue *queue, + BlockDriverState *bs, + BlockRequestHandler *handler, + int64_t sector_num, + QEMUIOVector *qiov, + int nb_sectors, + BlockDriverCompletionFunc *cb, + void *opaque) +{ + BlockIORequest *request; + BlockDriverAIOCB *acb; + BlockQueueAIOCB *blkacb; + + if (queue->request) { + request = queue->request; + assert(request->acb); + acb = request->acb; + QTAILQ_INSERT_TAIL(&queue->requests, request, entry); + queue->request = NULL; + } else { + request = g_malloc0(sizeof(BlockIORequest)); + request->bs = bs; + request->handler = handler; + request->sector_num = sector_num; + request->qiov = qiov; + request->nb_sectors = nb_sectors; + request->cb = qemu_block_queue_callback; + QTAILQ_INSERT_TAIL(&queue->requests, request, entry); + + acb = qemu_aio_get(&block_queue_pool, bs, + qemu_block_queue_callback, opaque); + blkacb = container_of(acb, BlockQueueAIOCB, common); + blkacb->real_cb = cb; + blkacb->real_acb = NULL; + blkacb->opaque = opaque; + blkacb->request = request; + + request->acb = acb; + request->opaque = (void *)blkacb; + } + + return acb; +} + +static int qemu_block_queue_handler(BlockIORequest *request) +{ + int ret; + BlockDriverAIOCB *res; + + res = request->handler(request->bs, request->sector_num, + request->qiov, request->nb_sectors, + request->cb, request->opaque); + if (res) { + BlockQueueAIOCB *blkacb = + container_of(request->acb, BlockQueueAIOCB, common); + blkacb->real_acb = res; + } + + ret = (res == NULL) ? 0 : 1; + + return ret; +} + +void qemu_block_queue_flush(BlockQueue *queue) +{ + queue->flushing = true; + while (!QTAILQ_EMPTY(&queue->requests)) { + BlockIORequest *request = NULL; + int ret = 0; + + request = QTAILQ_FIRST(&queue->requests); + QTAILQ_REMOVE(&queue->requests, request, entry); + + queue->request = request; + ret = qemu_block_queue_handler(request); + + if (ret == 0) { + QTAILQ_INSERT_HEAD(&queue->requests, request, entry); + queue->request = NULL; + break; + } + + if (queue->request) { + g_free(request); + } + + queue->request = NULL; + } + + queue->flushing = false; +} + +bool qemu_block_queue_has_pending(BlockQueue *queue) +{ + return !queue->flushing && !QTAILQ_EMPTY(&queue->requests); +} diff --git a/block/blk-queue.h b/block/blk-queue.h new file mode 100644 index 0000000..84c2407 --- /dev/null +++ b/block/blk-queue.h @@ -0,0 +1,63 @@ +/* + * QEMU System Emulator queue declaration for block layer + * + * Copyright (c) IBM, Corp. 2011 + * + * Authors: + * Zhi Yong Wu <zwu.kernel@xxxxxxxxx> + * Stefan Hajnoczi <stefanha@xxxxxxxxx> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef QEMU_BLOCK_QUEUE_H +#define QEMU_BLOCK_QUEUE_H + +#include "block.h" +#include "qemu-queue.h" + +typedef BlockDriverAIOCB* (BlockRequestHandler) (BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, + int nb_sectors, BlockDriverCompletionFunc *cb, + void *opaque); + +typedef struct BlockIORequest BlockIORequest; + +typedef struct BlockQueue BlockQueue; + +typedef struct BlockQueueAIOCB BlockQueueAIOCB; + +BlockQueue *qemu_new_block_queue(void); + +void qemu_del_block_queue(BlockQueue *queue); + +BlockDriverAIOCB *qemu_block_queue_enqueue(BlockQueue *queue, + BlockDriverState *bs, + BlockRequestHandler *handler, + int64_t sector_num, + QEMUIOVector *qiov, + int nb_sectors, + BlockDriverCompletionFunc *cb, + void *opaque); + +void qemu_block_queue_flush(BlockQueue *queue); + +bool qemu_block_queue_has_pending(BlockQueue *queue); + +#endif /* QEMU_BLOCK_QUEUE_H */ -- 1.7.6 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html