async: aio_context_new(): Handle event_notifier_init failure
On a system with a low limit of open files the initialization of the event notifier could fail and QEMU exits without printing any error information to the user. The problem can be easily reproduced by enforcing a low limit of open files and start QEMU with enough I/O threads to hit this limit. The same problem raises, without the creation of I/O threads, while QEMU initializes the main event loop by enforcing an even lower limit of open files. This commit adds an error message on failure: # qemu [...] -object iothread,id=iothread0 -object iothread,id=iothread1 qemu: Failed to initialize event notifier: Too many open files in system Signed-off-by: Chrysostomos Nanakos <cnanakos@grnet.gr> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
e91a8b2fef
commit
2f78e491d7
16
async.c
16
async.c
@ -289,18 +289,24 @@ static void aio_rfifolock_cb(void *opaque)
|
|||||||
aio_notify(opaque);
|
aio_notify(opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
AioContext *aio_context_new(void)
|
AioContext *aio_context_new(Error **errp)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
AioContext *ctx;
|
AioContext *ctx;
|
||||||
ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
|
ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
|
||||||
|
ret = event_notifier_init(&ctx->notifier, false);
|
||||||
|
if (ret < 0) {
|
||||||
|
g_source_destroy(&ctx->source);
|
||||||
|
error_setg_errno(errp, -ret, "Failed to initialize event notifier");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
aio_set_event_notifier(ctx, &ctx->notifier,
|
||||||
|
(EventNotifierHandler *)
|
||||||
|
event_notifier_test_and_clear);
|
||||||
ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
|
ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
|
||||||
ctx->thread_pool = NULL;
|
ctx->thread_pool = NULL;
|
||||||
qemu_mutex_init(&ctx->bh_lock);
|
qemu_mutex_init(&ctx->bh_lock);
|
||||||
rfifolock_init(&ctx->lock, aio_rfifolock_cb, ctx);
|
rfifolock_init(&ctx->lock, aio_rfifolock_cb, ctx);
|
||||||
event_notifier_init(&ctx->notifier, false);
|
|
||||||
aio_set_event_notifier(ctx, &ctx->notifier,
|
|
||||||
(EventNotifierHandler *)
|
|
||||||
event_notifier_test_and_clear);
|
|
||||||
timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx);
|
timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx);
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
|
@ -102,7 +102,7 @@ void aio_set_dispatching(AioContext *ctx, bool dispatching);
|
|||||||
* They also provide bottom halves, a service to execute a piece of code
|
* They also provide bottom halves, a service to execute a piece of code
|
||||||
* as soon as possible.
|
* as soon as possible.
|
||||||
*/
|
*/
|
||||||
AioContext *aio_context_new(void);
|
AioContext *aio_context_new(Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* aio_context_ref:
|
* aio_context_ref:
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
*
|
*
|
||||||
* In the case of QEMU tools, this will also start/initialize timers.
|
* In the case of QEMU tools, this will also start/initialize timers.
|
||||||
*/
|
*/
|
||||||
int qemu_init_main_loop(void);
|
int qemu_init_main_loop(Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* main_loop_wait: Run one iteration of the main loop.
|
* main_loop_wait: Run one iteration of the main loop.
|
||||||
|
11
iothread.c
11
iothread.c
@ -17,6 +17,7 @@
|
|||||||
#include "block/aio.h"
|
#include "block/aio.h"
|
||||||
#include "sysemu/iothread.h"
|
#include "sysemu/iothread.h"
|
||||||
#include "qmp-commands.h"
|
#include "qmp-commands.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
#define IOTHREADS_PATH "/objects"
|
#define IOTHREADS_PATH "/objects"
|
||||||
|
|
||||||
@ -53,6 +54,9 @@ static void iothread_instance_finalize(Object *obj)
|
|||||||
{
|
{
|
||||||
IOThread *iothread = IOTHREAD(obj);
|
IOThread *iothread = IOTHREAD(obj);
|
||||||
|
|
||||||
|
if (!iothread->ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
iothread->stopping = true;
|
iothread->stopping = true;
|
||||||
aio_notify(iothread->ctx);
|
aio_notify(iothread->ctx);
|
||||||
qemu_thread_join(&iothread->thread);
|
qemu_thread_join(&iothread->thread);
|
||||||
@ -63,11 +67,16 @@ static void iothread_instance_finalize(Object *obj)
|
|||||||
|
|
||||||
static void iothread_complete(UserCreatable *obj, Error **errp)
|
static void iothread_complete(UserCreatable *obj, Error **errp)
|
||||||
{
|
{
|
||||||
|
Error *local_error = NULL;
|
||||||
IOThread *iothread = IOTHREAD(obj);
|
IOThread *iothread = IOTHREAD(obj);
|
||||||
|
|
||||||
iothread->stopping = false;
|
iothread->stopping = false;
|
||||||
iothread->ctx = aio_context_new();
|
|
||||||
iothread->thread_id = -1;
|
iothread->thread_id = -1;
|
||||||
|
iothread->ctx = aio_context_new(&local_error);
|
||||||
|
if (!iothread->ctx) {
|
||||||
|
error_propagate(errp, local_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qemu_mutex_init(&iothread->init_done_lock);
|
qemu_mutex_init(&iothread->init_done_lock);
|
||||||
qemu_cond_init(&iothread->init_done_cond);
|
qemu_cond_init(&iothread->init_done_cond);
|
||||||
|
@ -126,10 +126,11 @@ void qemu_notify_event(void)
|
|||||||
|
|
||||||
static GArray *gpollfds;
|
static GArray *gpollfds;
|
||||||
|
|
||||||
int qemu_init_main_loop(void)
|
int qemu_init_main_loop(Error **errp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
GSource *src;
|
GSource *src;
|
||||||
|
Error *local_error = NULL;
|
||||||
|
|
||||||
init_clocks();
|
init_clocks();
|
||||||
|
|
||||||
@ -138,8 +139,12 @@ int qemu_init_main_loop(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_aio_context = aio_context_new(&local_error);
|
||||||
|
if (!qemu_aio_context) {
|
||||||
|
error_propagate(errp, local_error);
|
||||||
|
return -EMFILE;
|
||||||
|
}
|
||||||
gpollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
|
gpollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
|
||||||
qemu_aio_context = aio_context_new();
|
|
||||||
src = aio_get_g_source(qemu_aio_context);
|
src = aio_get_g_source(qemu_aio_context);
|
||||||
g_source_attach(src, NULL);
|
g_source_attach(src, NULL);
|
||||||
g_source_unref(src);
|
g_source_unref(src);
|
||||||
|
@ -2879,6 +2879,7 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
const img_cmd_t *cmd;
|
const img_cmd_t *cmd;
|
||||||
const char *cmdname;
|
const char *cmdname;
|
||||||
|
Error *local_error = NULL;
|
||||||
int c;
|
int c;
|
||||||
static const struct option long_options[] = {
|
static const struct option long_options[] = {
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
@ -2893,7 +2894,12 @@ int main(int argc, char **argv)
|
|||||||
error_set_progname(argv[0]);
|
error_set_progname(argv[0]);
|
||||||
qemu_init_exec_dir(argv[0]);
|
qemu_init_exec_dir(argv[0]);
|
||||||
|
|
||||||
qemu_init_main_loop();
|
if (qemu_init_main_loop(&local_error)) {
|
||||||
|
error_report("%s", error_get_pretty(local_error));
|
||||||
|
error_free(local_error);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
bdrv_init();
|
bdrv_init();
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
error_exit("Not enough arguments");
|
error_exit("Not enough arguments");
|
||||||
|
@ -379,6 +379,7 @@ int main(int argc, char **argv)
|
|||||||
int c;
|
int c;
|
||||||
int opt_index = 0;
|
int opt_index = 0;
|
||||||
int flags = BDRV_O_UNMAP;
|
int flags = BDRV_O_UNMAP;
|
||||||
|
Error *local_error = NULL;
|
||||||
|
|
||||||
#ifdef CONFIG_POSIX
|
#ifdef CONFIG_POSIX
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
@ -444,7 +445,11 @@ int main(int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_init_main_loop();
|
if (qemu_init_main_loop(&local_error)) {
|
||||||
|
error_report("%s", error_get_pretty(local_error));
|
||||||
|
error_free(local_error);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
bdrv_init();
|
bdrv_init();
|
||||||
|
|
||||||
/* initialize commands */
|
/* initialize commands */
|
||||||
|
@ -674,7 +674,11 @@ int main(int argc, char **argv)
|
|||||||
snprintf(sockpath, 128, SOCKET_PATH, basename(device));
|
snprintf(sockpath, 128, SOCKET_PATH, basename(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_init_main_loop();
|
if (qemu_init_main_loop(&local_err)) {
|
||||||
|
error_report("%s", error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
bdrv_init();
|
bdrv_init();
|
||||||
atexit(bdrv_close_all);
|
atexit(bdrv_close_all);
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "block/aio.h"
|
#include "block/aio.h"
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
static AioContext *ctx;
|
static AioContext *ctx;
|
||||||
|
|
||||||
@ -810,11 +811,18 @@ static void test_source_timer_schedule(void)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
Error *local_error = NULL;
|
||||||
GSource *src;
|
GSource *src;
|
||||||
|
|
||||||
init_clocks();
|
init_clocks();
|
||||||
|
|
||||||
ctx = aio_context_new();
|
ctx = aio_context_new(&local_error);
|
||||||
|
if (!ctx) {
|
||||||
|
error_report("Failed to create AIO Context: '%s'",
|
||||||
|
error_get_pretty(local_error));
|
||||||
|
error_free(local_error);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
src = aio_get_g_source(ctx);
|
src = aio_get_g_source(ctx);
|
||||||
g_source_attach(src, NULL);
|
g_source_attach(src, NULL);
|
||||||
g_source_unref(src);
|
g_source_unref(src);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "block/thread-pool.h"
|
#include "block/thread-pool.h"
|
||||||
#include "block/block.h"
|
#include "block/block.h"
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
static AioContext *ctx;
|
static AioContext *ctx;
|
||||||
static ThreadPool *pool;
|
static ThreadPool *pool;
|
||||||
@ -222,10 +223,17 @@ static void test_cancel_async(void)
|
|||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
Error *local_error = NULL;
|
||||||
|
|
||||||
init_clocks();
|
init_clocks();
|
||||||
|
|
||||||
ctx = aio_context_new();
|
ctx = aio_context_new(&local_error);
|
||||||
|
if (!ctx) {
|
||||||
|
error_report("Failed to create AIO Context: '%s'",
|
||||||
|
error_get_pretty(local_error));
|
||||||
|
error_free(local_error);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
pool = aio_get_thread_pool(ctx);
|
pool = aio_get_thread_pool(ctx);
|
||||||
|
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "block/aio.h"
|
#include "block/aio.h"
|
||||||
#include "qemu/throttle.h"
|
#include "qemu/throttle.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
static AioContext *ctx;
|
static AioContext *ctx;
|
||||||
static LeakyBucket bkt;
|
static LeakyBucket bkt;
|
||||||
@ -492,10 +493,17 @@ static void test_accounting(void)
|
|||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
GSource *src;
|
GSource *src;
|
||||||
|
Error *local_error = NULL;
|
||||||
|
|
||||||
init_clocks();
|
init_clocks();
|
||||||
|
|
||||||
ctx = aio_context_new();
|
ctx = aio_context_new(&local_error);
|
||||||
|
if (!ctx) {
|
||||||
|
error_report("Failed to create AIO Context: '%s'",
|
||||||
|
error_get_pretty(local_error));
|
||||||
|
error_free(local_error);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
src = aio_get_g_source(ctx);
|
src = aio_get_g_source(ctx);
|
||||||
g_source_attach(src, NULL);
|
g_source_attach(src, NULL);
|
||||||
g_source_unref(src);
|
g_source_unref(src);
|
||||||
|
5
vl.c
5
vl.c
@ -2968,6 +2968,7 @@ int main(int argc, char **argv, char **envp)
|
|||||||
ram_addr_t maxram_size = default_ram_size;
|
ram_addr_t maxram_size = default_ram_size;
|
||||||
uint64_t ram_slots = 0;
|
uint64_t ram_slots = 0;
|
||||||
FILE *vmstate_dump_file = NULL;
|
FILE *vmstate_dump_file = NULL;
|
||||||
|
Error *main_loop_err = NULL;
|
||||||
|
|
||||||
atexit(qemu_run_exit_notifiers);
|
atexit(qemu_run_exit_notifiers);
|
||||||
error_set_progname(argv[0]);
|
error_set_progname(argv[0]);
|
||||||
@ -3998,8 +3999,8 @@ int main(int argc, char **argv, char **envp)
|
|||||||
|
|
||||||
os_daemonize();
|
os_daemonize();
|
||||||
|
|
||||||
if (qemu_init_main_loop()) {
|
if (qemu_init_main_loop(&main_loop_err)) {
|
||||||
fprintf(stderr, "qemu_init_main_loop failed\n");
|
error_report("%s", error_get_pretty(main_loop_err));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user