linux-aio: implement io plug, unplug and flush io queue
This patch implements .bdrv_io_plug, .bdrv_io_unplug and .bdrv_flush_io_queue callbacks for linux-aio Block Drivers, so that submitting I/O as a batch can be supported on linux-aio. [Unprocessed requests are completed with -EIO instead of a bogus ret value. --Stefan] Signed-off-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
		
							parent
							
								
									448ad91db4
								
							
						
					
					
						commit
						1b3abdcccf
					
				@ -25,6 +25,8 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
#define MAX_EVENTS 128
 | 
					#define MAX_EVENTS 128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_QUEUED_IO  128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct qemu_laiocb {
 | 
					struct qemu_laiocb {
 | 
				
			||||||
    BlockDriverAIOCB common;
 | 
					    BlockDriverAIOCB common;
 | 
				
			||||||
    struct qemu_laio_state *ctx;
 | 
					    struct qemu_laio_state *ctx;
 | 
				
			||||||
@ -36,9 +38,19 @@ struct qemu_laiocb {
 | 
				
			|||||||
    QLIST_ENTRY(qemu_laiocb) node;
 | 
					    QLIST_ENTRY(qemu_laiocb) node;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    struct iocb *iocbs[MAX_QUEUED_IO];
 | 
				
			||||||
 | 
					    int plugged;
 | 
				
			||||||
 | 
					    unsigned int size;
 | 
				
			||||||
 | 
					    unsigned int idx;
 | 
				
			||||||
 | 
					} LaioQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct qemu_laio_state {
 | 
					struct qemu_laio_state {
 | 
				
			||||||
    io_context_t ctx;
 | 
					    io_context_t ctx;
 | 
				
			||||||
    EventNotifier e;
 | 
					    EventNotifier e;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* io queue for submit at batch */
 | 
				
			||||||
 | 
					    LaioQueue io_q;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline ssize_t io_event_ret(struct io_event *ev)
 | 
					static inline ssize_t io_event_ret(struct io_event *ev)
 | 
				
			||||||
@ -135,6 +147,79 @@ static const AIOCBInfo laio_aiocb_info = {
 | 
				
			|||||||
    .cancel             = laio_cancel,
 | 
					    .cancel             = laio_cancel,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ioq_init(LaioQueue *io_q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    io_q->size = MAX_QUEUED_IO;
 | 
				
			||||||
 | 
					    io_q->idx = 0;
 | 
				
			||||||
 | 
					    io_q->plugged = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ioq_submit(struct qemu_laio_state *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret, i = 0;
 | 
				
			||||||
 | 
					    int len = s->io_q.idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        ret = io_submit(s->ctx, len, s->io_q.iocbs);
 | 
				
			||||||
 | 
					    } while (i++ < 3 && ret == -EAGAIN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* empty io queue */
 | 
				
			||||||
 | 
					    s->io_q.idx = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        i = 0;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        i = ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (; i < len; i++) {
 | 
				
			||||||
 | 
					        struct qemu_laiocb *laiocb =
 | 
				
			||||||
 | 
					            container_of(s->io_q.iocbs[i], struct qemu_laiocb, iocb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        laiocb->ret = (ret < 0) ? ret : -EIO;
 | 
				
			||||||
 | 
					        qemu_laio_process_completion(s, laiocb);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ioq_enqueue(struct qemu_laio_state *s, struct iocb *iocb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    unsigned int idx = s->io_q.idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->io_q.iocbs[idx++] = iocb;
 | 
				
			||||||
 | 
					    s->io_q.idx = idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* submit immediately if queue is full */
 | 
				
			||||||
 | 
					    if (idx == s->io_q.size) {
 | 
				
			||||||
 | 
					        ioq_submit(s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void laio_io_plug(BlockDriverState *bs, void *aio_ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct qemu_laio_state *s = aio_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->io_q.plugged++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct qemu_laio_state *s = aio_ctx;
 | 
				
			||||||
 | 
					    int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(s->io_q.plugged > 0 || !unplug);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (unplug && --s->io_q.plugged > 0) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->io_q.idx > 0) {
 | 
				
			||||||
 | 
					        ret = ioq_submit(s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
 | 
					BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
 | 
				
			||||||
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
					        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
				
			||||||
        BlockDriverCompletionFunc *cb, void *opaque, int type)
 | 
					        BlockDriverCompletionFunc *cb, void *opaque, int type)
 | 
				
			||||||
@ -168,8 +253,13 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e));
 | 
					    io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (io_submit(s->ctx, 1, &iocbs) < 0)
 | 
					    if (!s->io_q.plugged) {
 | 
				
			||||||
 | 
					        if (io_submit(s->ctx, 1, &iocbs) < 0) {
 | 
				
			||||||
            goto out_free_aiocb;
 | 
					            goto out_free_aiocb;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        ioq_enqueue(s, iocbs);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return &laiocb->common;
 | 
					    return &laiocb->common;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_free_aiocb:
 | 
					out_free_aiocb:
 | 
				
			||||||
@ -204,6 +294,8 @@ void *laio_init(void)
 | 
				
			|||||||
        goto out_close_efd;
 | 
					        goto out_close_efd;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ioq_init(&s->io_q);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return s;
 | 
					    return s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_close_efd:
 | 
					out_close_efd:
 | 
				
			||||||
 | 
				
			|||||||
@ -40,6 +40,8 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
 | 
				
			|||||||
        BlockDriverCompletionFunc *cb, void *opaque, int type);
 | 
					        BlockDriverCompletionFunc *cb, void *opaque, int type);
 | 
				
			||||||
void laio_detach_aio_context(void *s, AioContext *old_context);
 | 
					void laio_detach_aio_context(void *s, AioContext *old_context);
 | 
				
			||||||
void laio_attach_aio_context(void *s, AioContext *new_context);
 | 
					void laio_attach_aio_context(void *s, AioContext *new_context);
 | 
				
			||||||
 | 
					void laio_io_plug(BlockDriverState *bs, void *aio_ctx);
 | 
				
			||||||
 | 
					int laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
				
			|||||||
@ -1057,6 +1057,36 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
 | 
				
			|||||||
                       cb, opaque, type);
 | 
					                       cb, opaque, type);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void raw_aio_plug(BlockDriverState *bs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_LINUX_AIO
 | 
				
			||||||
 | 
					    BDRVRawState *s = bs->opaque;
 | 
				
			||||||
 | 
					    if (s->use_aio) {
 | 
				
			||||||
 | 
					        laio_io_plug(bs, s->aio_ctx);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void raw_aio_unplug(BlockDriverState *bs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_LINUX_AIO
 | 
				
			||||||
 | 
					    BDRVRawState *s = bs->opaque;
 | 
				
			||||||
 | 
					    if (s->use_aio) {
 | 
				
			||||||
 | 
					        laio_io_unplug(bs, s->aio_ctx, true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void raw_aio_flush_io_queue(BlockDriverState *bs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_LINUX_AIO
 | 
				
			||||||
 | 
					    BDRVRawState *s = bs->opaque;
 | 
				
			||||||
 | 
					    if (s->use_aio) {
 | 
				
			||||||
 | 
					        laio_io_unplug(bs, s->aio_ctx, false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
 | 
					static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
 | 
				
			||||||
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
					        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
				
			||||||
        BlockDriverCompletionFunc *cb, void *opaque)
 | 
					        BlockDriverCompletionFunc *cb, void *opaque)
 | 
				
			||||||
@ -1544,6 +1574,9 @@ static BlockDriver bdrv_file = {
 | 
				
			|||||||
    .bdrv_aio_flush = raw_aio_flush,
 | 
					    .bdrv_aio_flush = raw_aio_flush,
 | 
				
			||||||
    .bdrv_aio_discard = raw_aio_discard,
 | 
					    .bdrv_aio_discard = raw_aio_discard,
 | 
				
			||||||
    .bdrv_refresh_limits = raw_refresh_limits,
 | 
					    .bdrv_refresh_limits = raw_refresh_limits,
 | 
				
			||||||
 | 
					    .bdrv_io_plug = raw_aio_plug,
 | 
				
			||||||
 | 
					    .bdrv_io_unplug = raw_aio_unplug,
 | 
				
			||||||
 | 
					    .bdrv_flush_io_queue = raw_aio_flush_io_queue,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_truncate = raw_truncate,
 | 
					    .bdrv_truncate = raw_truncate,
 | 
				
			||||||
    .bdrv_getlength = raw_getlength,
 | 
					    .bdrv_getlength = raw_getlength,
 | 
				
			||||||
@ -1943,6 +1976,9 @@ static BlockDriver bdrv_host_device = {
 | 
				
			|||||||
    .bdrv_aio_flush	= raw_aio_flush,
 | 
					    .bdrv_aio_flush	= raw_aio_flush,
 | 
				
			||||||
    .bdrv_aio_discard   = hdev_aio_discard,
 | 
					    .bdrv_aio_discard   = hdev_aio_discard,
 | 
				
			||||||
    .bdrv_refresh_limits = raw_refresh_limits,
 | 
					    .bdrv_refresh_limits = raw_refresh_limits,
 | 
				
			||||||
 | 
					    .bdrv_io_plug = raw_aio_plug,
 | 
				
			||||||
 | 
					    .bdrv_io_unplug = raw_aio_unplug,
 | 
				
			||||||
 | 
					    .bdrv_flush_io_queue = raw_aio_flush_io_queue,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_truncate      = raw_truncate,
 | 
					    .bdrv_truncate      = raw_truncate,
 | 
				
			||||||
    .bdrv_getlength	= raw_getlength,
 | 
					    .bdrv_getlength	= raw_getlength,
 | 
				
			||||||
@ -2088,6 +2124,9 @@ static BlockDriver bdrv_host_floppy = {
 | 
				
			|||||||
    .bdrv_aio_writev    = raw_aio_writev,
 | 
					    .bdrv_aio_writev    = raw_aio_writev,
 | 
				
			||||||
    .bdrv_aio_flush	= raw_aio_flush,
 | 
					    .bdrv_aio_flush	= raw_aio_flush,
 | 
				
			||||||
    .bdrv_refresh_limits = raw_refresh_limits,
 | 
					    .bdrv_refresh_limits = raw_refresh_limits,
 | 
				
			||||||
 | 
					    .bdrv_io_plug = raw_aio_plug,
 | 
				
			||||||
 | 
					    .bdrv_io_unplug = raw_aio_unplug,
 | 
				
			||||||
 | 
					    .bdrv_flush_io_queue = raw_aio_flush_io_queue,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_truncate      = raw_truncate,
 | 
					    .bdrv_truncate      = raw_truncate,
 | 
				
			||||||
    .bdrv_getlength      = raw_getlength,
 | 
					    .bdrv_getlength      = raw_getlength,
 | 
				
			||||||
@ -2216,6 +2255,9 @@ static BlockDriver bdrv_host_cdrom = {
 | 
				
			|||||||
    .bdrv_aio_writev    = raw_aio_writev,
 | 
					    .bdrv_aio_writev    = raw_aio_writev,
 | 
				
			||||||
    .bdrv_aio_flush	= raw_aio_flush,
 | 
					    .bdrv_aio_flush	= raw_aio_flush,
 | 
				
			||||||
    .bdrv_refresh_limits = raw_refresh_limits,
 | 
					    .bdrv_refresh_limits = raw_refresh_limits,
 | 
				
			||||||
 | 
					    .bdrv_io_plug = raw_aio_plug,
 | 
				
			||||||
 | 
					    .bdrv_io_unplug = raw_aio_unplug,
 | 
				
			||||||
 | 
					    .bdrv_flush_io_queue = raw_aio_flush_io_queue,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_truncate      = raw_truncate,
 | 
					    .bdrv_truncate      = raw_truncate,
 | 
				
			||||||
    .bdrv_getlength      = raw_getlength,
 | 
					    .bdrv_getlength      = raw_getlength,
 | 
				
			||||||
@ -2350,6 +2392,9 @@ static BlockDriver bdrv_host_cdrom = {
 | 
				
			|||||||
    .bdrv_aio_writev    = raw_aio_writev,
 | 
					    .bdrv_aio_writev    = raw_aio_writev,
 | 
				
			||||||
    .bdrv_aio_flush	= raw_aio_flush,
 | 
					    .bdrv_aio_flush	= raw_aio_flush,
 | 
				
			||||||
    .bdrv_refresh_limits = raw_refresh_limits,
 | 
					    .bdrv_refresh_limits = raw_refresh_limits,
 | 
				
			||||||
 | 
					    .bdrv_io_plug = raw_aio_plug,
 | 
				
			||||||
 | 
					    .bdrv_io_unplug = raw_aio_unplug,
 | 
				
			||||||
 | 
					    .bdrv_flush_io_queue = raw_aio_flush_io_queue,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_truncate      = raw_truncate,
 | 
					    .bdrv_truncate      = raw_truncate,
 | 
				
			||||||
    .bdrv_getlength      = raw_getlength,
 | 
					    .bdrv_getlength      = raw_getlength,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user