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_QUEUED_IO 128
|
||||
|
||||
struct qemu_laiocb {
|
||||
BlockDriverAIOCB common;
|
||||
struct qemu_laio_state *ctx;
|
||||
@ -36,9 +38,19 @@ struct qemu_laiocb {
|
||||
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 {
|
||||
io_context_t ctx;
|
||||
EventNotifier e;
|
||||
|
||||
/* io queue for submit at batch */
|
||||
LaioQueue io_q;
|
||||
};
|
||||
|
||||
static inline ssize_t io_event_ret(struct io_event *ev)
|
||||
@ -135,6 +147,79 @@ static const AIOCBInfo laio_aiocb_info = {
|
||||
.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,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
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));
|
||||
|
||||
if (io_submit(s->ctx, 1, &iocbs) < 0)
|
||||
goto out_free_aiocb;
|
||||
if (!s->io_q.plugged) {
|
||||
if (io_submit(s->ctx, 1, &iocbs) < 0) {
|
||||
goto out_free_aiocb;
|
||||
}
|
||||
} else {
|
||||
ioq_enqueue(s, iocbs);
|
||||
}
|
||||
return &laiocb->common;
|
||||
|
||||
out_free_aiocb:
|
||||
@ -204,6 +294,8 @@ void *laio_init(void)
|
||||
goto out_close_efd;
|
||||
}
|
||||
|
||||
ioq_init(&s->io_q);
|
||||
|
||||
return s;
|
||||
|
||||
out_close_efd:
|
||||
|
@ -40,6 +40,8 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type);
|
||||
void laio_detach_aio_context(void *s, AioContext *old_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
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -1057,6 +1057,36 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
|
||||
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,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
@ -1544,6 +1574,9 @@ static BlockDriver bdrv_file = {
|
||||
.bdrv_aio_flush = raw_aio_flush,
|
||||
.bdrv_aio_discard = raw_aio_discard,
|
||||
.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_getlength = raw_getlength,
|
||||
@ -1943,6 +1976,9 @@ static BlockDriver bdrv_host_device = {
|
||||
.bdrv_aio_flush = raw_aio_flush,
|
||||
.bdrv_aio_discard = hdev_aio_discard,
|
||||
.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_getlength = raw_getlength,
|
||||
@ -2088,6 +2124,9 @@ static BlockDriver bdrv_host_floppy = {
|
||||
.bdrv_aio_writev = raw_aio_writev,
|
||||
.bdrv_aio_flush = raw_aio_flush,
|
||||
.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_getlength = raw_getlength,
|
||||
@ -2216,6 +2255,9 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
.bdrv_aio_writev = raw_aio_writev,
|
||||
.bdrv_aio_flush = raw_aio_flush,
|
||||
.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_getlength = raw_getlength,
|
||||
@ -2350,6 +2392,9 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
.bdrv_aio_writev = raw_aio_writev,
|
||||
.bdrv_aio_flush = raw_aio_flush,
|
||||
.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_getlength = raw_getlength,
|
||||
|
Loading…
Reference in New Issue
Block a user