From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Stefan Reiter Date: Mon, 22 Mar 2021 15:20:04 +0100 Subject: [PATCH] monitor/qmp: fix race on CHR_EVENT_CLOSED without OOB The QMP dispatcher coroutine holds the qmp_queue_lock over a yield point, where it expects to be rescheduled from the main context. If a CHR_EVENT_CLOSED event is received just then, it can race and block the main thread on the mutex in monitor_qmp_cleanup_queue_and_resume. Calculate need_resume immediately after we pop a request from the queue, so that we can release the mutex before yielding. Suggested-by: Wolfgang Bumiller Signed-off-by: Stefan Reiter --- monitor/qmp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/monitor/qmp.c b/monitor/qmp.c index 2e37d11bd3..2aff833f7a 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -252,6 +252,12 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data) } } + mon = req_obj->mon; + /* qmp_oob_enabled() might change after "qmp_capabilities" */ + need_resume = !qmp_oob_enabled(mon) || + mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1; + qemu_mutex_unlock(&mon->qmp_queue_lock); + if (qatomic_xchg(&qmp_dispatcher_co_busy, true) == true) { /* * Someone rescheduled us (probably because a new requests @@ -270,11 +276,6 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data) aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co); qemu_coroutine_yield(); - mon = req_obj->mon; - /* qmp_oob_enabled() might change after "qmp_capabilities" */ - need_resume = !qmp_oob_enabled(mon) || - mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1; - qemu_mutex_unlock(&mon->qmp_queue_lock); if (req_obj->req) { QDict *qdict = qobject_to(QDict, req_obj->req); QObject *id = qdict ? qdict_get(qdict, "id") : NULL;