monitor: convert from oneshot BH to persistent BH

Convert monitor_accept_input from a oneshot BH (aio_bh_schedule_oneshot)
to a persistent BH (aio_bh_new + qemu_bh_schedule).  Oneshot BHs cannot
be cancelled, so monitor_resume() racing with destruction would schedule
a callback against memory that monitor_qmp_destroy() is about to free.
A persistent BH can be deleted during destruction, cancelling any
pending schedule.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
[DB: extracted oneshot BH conversion from larger commit]
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20260706135824.2623960-25-berrange@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
Christian Brauner
2026-07-06 14:58:12 +01:00
committed by Markus Armbruster
parent 75f31e3a8a
commit 94c64bfb44
2 changed files with 15 additions and 12 deletions

View File

@@ -134,7 +134,7 @@ struct Monitor {
char *chardev_id;
CharFrontend chr;
int suspend_cnt; /* Needs to be accessed atomically */
QEMUBH *accept_input_bh; /* persistent BH for monitor_accept_input */
char *mon_cpu_path;
QTAILQ_ENTRY(Monitor) entry;

View File

@@ -83,6 +83,9 @@ static void monitor_finalize(Object *obj)
{
Monitor *mon = MONITOR(obj);
if (mon->accept_input_bh) {
qemu_bh_delete(mon->accept_input_bh);
}
g_free(mon->chardev_id);
g_free(mon->mon_cpu_path);
qemu_chr_fe_deinit(&mon->chr, false);
@@ -569,15 +572,7 @@ static void monitor_accept_input(void *opaque)
void monitor_resume(Monitor *mon)
{
if (qatomic_dec_fetch(&mon->suspend_cnt) == 0) {
AioContext *ctx;
if (monitor_requires_iothread(mon)) {
ctx = iothread_get_aio_context(mon_iothread);
} else {
ctx = qemu_get_aio_context();
}
aio_bh_schedule_oneshot(ctx, monitor_accept_input, mon);
qemu_bh_schedule(mon->accept_input_bh);
}
trace_monitor_suspend(mon, -1);
@@ -700,6 +695,7 @@ char *monitor_compat_id(void)
static void monitor_complete(UserCreatable *uc, Error **errp)
{
Monitor *mon = MONITOR(uc);
AioContext *ctx;
if (mon->chardev_id) {
Chardev *chr = qemu_chr_find(mon->chardev_id);
@@ -713,9 +709,16 @@ static void monitor_complete(UserCreatable *uc, Error **errp)
}
}
if (monitor_requires_iothread(mon) && !mon_iothread) {
mon_iothread = iothread_create("mon_iothread", &error_abort);
if (monitor_requires_iothread(mon)) {
if (!mon_iothread) {
mon_iothread = iothread_create("mon_iothread", &error_abort);
}
ctx = iothread_get_aio_context(mon_iothread);
} else {
ctx = qemu_get_aio_context();
}
mon->accept_input_bh = aio_bh_new(ctx, monitor_accept_input, mon);
}
int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)