Skip to content

Commit ed6e216

Browse files
naccstefanhaRH
authored andcommitted
linux-aio: properly bubble up errors from initialization
laio_init() can fail for a couple of reasons, which will lead to a NULL pointer dereference in laio_attach_aio_context(). To solve this, add a aio_setup_linux_aio() function which is called early in raw_open_common. If this fails, propagate the error up. The signature of aio_get_linux_aio() was not modified, because it seems preferable to return the actual errno from the possible failing initialization calls. Additionally, when the AioContext changes, we need to associate a LinuxAioState with the new AioContext. Use the bdrv_attach_aio_context callback and call the new aio_setup_linux_aio(), which will allocate a new AioContext if needed, and return errors on failures. If it fails for any reason, fallback to threaded AIO with an error message, as the device is already in-use by the guest. Add an assert that aio_get_linux_aio() cannot return NULL. Signed-off-by: Nishanth Aravamudan <[email protected]> Message-id: [email protected] Signed-off-by: Stefan Hajnoczi <[email protected]>
1 parent f18793b commit ed6e216

File tree

6 files changed

+53
-13
lines changed

6 files changed

+53
-13
lines changed

block/file-posix.c

+28-5
Original file line numberDiff line numberDiff line change
@@ -545,11 +545,17 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
545545

546546
#ifdef CONFIG_LINUX_AIO
547547
/* Currently Linux does AIO only for files opened with O_DIRECT */
548-
if (s->use_linux_aio && !(s->open_flags & O_DIRECT)) {
549-
error_setg(errp, "aio=native was specified, but it requires "
550-
"cache.direct=on, which was not specified.");
551-
ret = -EINVAL;
552-
goto fail;
548+
if (s->use_linux_aio) {
549+
if (!(s->open_flags & O_DIRECT)) {
550+
error_setg(errp, "aio=native was specified, but it requires "
551+
"cache.direct=on, which was not specified.");
552+
ret = -EINVAL;
553+
goto fail;
554+
}
555+
if (!aio_setup_linux_aio(bdrv_get_aio_context(bs), errp)) {
556+
error_prepend(errp, "Unable to use native AIO: ");
557+
goto fail;
558+
}
553559
}
554560
#else
555561
if (s->use_linux_aio) {
@@ -1723,6 +1729,22 @@ static BlockAIOCB *raw_aio_flush(BlockDriverState *bs,
17231729
return paio_submit(bs, s->fd, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
17241730
}
17251731

1732+
static void raw_aio_attach_aio_context(BlockDriverState *bs,
1733+
AioContext *new_context)
1734+
{
1735+
#ifdef CONFIG_LINUX_AIO
1736+
BDRVRawState *s = bs->opaque;
1737+
if (s->use_linux_aio) {
1738+
Error *local_err;
1739+
if (!aio_setup_linux_aio(new_context, &local_err)) {
1740+
error_reportf_err(local_err, "Unable to use native AIO, "
1741+
"falling back to thread pool: ");
1742+
s->use_linux_aio = false;
1743+
}
1744+
}
1745+
#endif
1746+
}
1747+
17261748
static void raw_close(BlockDriverState *bs)
17271749
{
17281750
BDRVRawState *s = bs->opaque;
@@ -2601,6 +2623,7 @@ BlockDriver bdrv_file = {
26012623
.bdrv_refresh_limits = raw_refresh_limits,
26022624
.bdrv_io_plug = raw_aio_plug,
26032625
.bdrv_io_unplug = raw_aio_unplug,
2626+
.bdrv_attach_aio_context = raw_aio_attach_aio_context,
26042627

26052628
.bdrv_truncate = raw_truncate,
26062629
.bdrv_getlength = raw_getlength,

block/linux-aio.c

+9-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "block/raw-aio.h"
1616
#include "qemu/event_notifier.h"
1717
#include "qemu/coroutine.h"
18+
#include "qapi/error.h"
1819

1920
#include <libaio.h>
2021

@@ -470,16 +471,21 @@ void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context)
470471
qemu_laio_poll_cb);
471472
}
472473

473-
LinuxAioState *laio_init(void)
474+
LinuxAioState *laio_init(Error **errp)
474475
{
476+
int rc;
475477
LinuxAioState *s;
476478

477479
s = g_malloc0(sizeof(*s));
478-
if (event_notifier_init(&s->e, false) < 0) {
480+
rc = event_notifier_init(&s->e, false);
481+
if (rc < 0) {
482+
error_setg_errno(errp, -rc, "failed to to initialize event notifier");
479483
goto out_free_state;
480484
}
481485

482-
if (io_setup(MAX_EVENTS, &s->ctx) != 0) {
486+
rc = io_setup(MAX_EVENTS, &s->ctx);
487+
if (rc < 0) {
488+
error_setg_errno(errp, -rc, "failed to create linux AIO context");
483489
goto out_close_efd;
484490
}
485491

include/block/aio.h

+3
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,9 @@ GSource *aio_get_g_source(AioContext *ctx);
381381
/* Return the ThreadPool bound to this AioContext */
382382
struct ThreadPool *aio_get_thread_pool(AioContext *ctx);
383383

384+
/* Setup the LinuxAioState bound to this AioContext */
385+
struct LinuxAioState *aio_setup_linux_aio(AioContext *ctx, Error **errp);
386+
384387
/* Return the LinuxAioState bound to this AioContext */
385388
struct LinuxAioState *aio_get_linux_aio(AioContext *ctx);
386389

include/block/raw-aio.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
/* linux-aio.c - Linux native implementation */
4444
#ifdef CONFIG_LINUX_AIO
4545
typedef struct LinuxAioState LinuxAioState;
46-
LinuxAioState *laio_init(void);
46+
LinuxAioState *laio_init(Error **errp);
4747
void laio_cleanup(LinuxAioState *s);
4848
int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
4949
uint64_t offset, QEMUIOVector *qiov, int type);

stubs/linux-aio.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context)
2121
abort();
2222
}
2323

24-
LinuxAioState *laio_init(void)
24+
LinuxAioState *laio_init(Error **errp)
2525
{
2626
abort();
2727
}

util/async.c

+11-3
Original file line numberDiff line numberDiff line change
@@ -323,14 +323,22 @@ ThreadPool *aio_get_thread_pool(AioContext *ctx)
323323
}
324324

325325
#ifdef CONFIG_LINUX_AIO
326-
LinuxAioState *aio_get_linux_aio(AioContext *ctx)
326+
LinuxAioState *aio_setup_linux_aio(AioContext *ctx, Error **errp)
327327
{
328328
if (!ctx->linux_aio) {
329-
ctx->linux_aio = laio_init();
330-
laio_attach_aio_context(ctx->linux_aio, ctx);
329+
ctx->linux_aio = laio_init(errp);
330+
if (ctx->linux_aio) {
331+
laio_attach_aio_context(ctx->linux_aio, ctx);
332+
}
331333
}
332334
return ctx->linux_aio;
333335
}
336+
337+
LinuxAioState *aio_get_linux_aio(AioContext *ctx)
338+
{
339+
assert(ctx->linux_aio);
340+
return ctx->linux_aio;
341+
}
334342
#endif
335343

336344
void aio_notify(AioContext *ctx)

0 commit comments

Comments
 (0)