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…
Reference in New Issue
Block a user