From c6b183a4c3c63454dea39be26b0fb773ec04887e Mon Sep 17 00:00:00 2001 From: Chuan Zheng Date: Wed, 9 Feb 2022 14:13:05 +0800 Subject: [PATCH] monitor/qmp: drop inflight rsp if qmp client broken If libvirt restart while qemu is handle qmp message, libvirt will reconnect qemu monitor socket, and query status of qemu by qmp. But qemu may return last qmp respond to new connect socket, and libvirt recv unexpected respond, So libvirt think qemu is abnormal, and will kill qemu. This patch add qmp connect id, while reconnect id will change. While respond to libvirt, judge if id is same, if not, drop this respond. --- monitor/monitor-internal.h | 1 + monitor/qmp.c | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index 252de85681..d7842fa464 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -144,6 +144,7 @@ typedef struct { const QmpCommandList *commands; bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */ bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */ + uint64_t qmp_client_id; /*qmp client id, update if peer disconnect */ /* * Protects qmp request/response queue. * Take monitor_lock first when you need both. diff --git a/monitor/qmp.c b/monitor/qmp.c index 6eee450fe4..8f7671c5f1 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -149,18 +149,19 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp) * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP. * Nothing is emitted then. */ -static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp) +static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp, uint64_t req_client_id) { - if (rsp) { - qmp_send_response(mon, rsp); + if (!rsp || (mon->qmp_client_id != req_client_id)) { + return; } + qmp_send_response(mon, rsp); } /* * Runs outside of coroutine context for OOB commands, but in * coroutine context for everything else. */ -static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) +static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req, uint64_t req_client_id) { QDict *rsp; QDict *error; @@ -180,7 +181,7 @@ static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) } } - monitor_qmp_respond(mon, rsp); + monitor_qmp_respond(mon, rsp, req_client_id); qobject_unref(rsp); } @@ -340,13 +341,13 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data) trace_monitor_qmp_cmd_in_band(id_json->str); g_string_free(id_json, true); } - monitor_qmp_dispatch(mon, req_obj->req); + monitor_qmp_dispatch(mon, req_obj->req, mon->qmp_client_id); } else { assert(req_obj->err); trace_monitor_qmp_err_in_band(error_get_pretty(req_obj->err)); rsp = qmp_error_response(req_obj->err); req_obj->err = NULL; - monitor_qmp_respond(mon, rsp); + monitor_qmp_respond(mon, rsp, mon->qmp_client_id); qobject_unref(rsp); } @@ -402,7 +403,7 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err) trace_monitor_qmp_cmd_out_of_band(id_json->str); g_string_free(id_json, true); } - monitor_qmp_dispatch(mon, req); + monitor_qmp_dispatch(mon, req, mon->qmp_client_id); qobject_unref(req); return; } @@ -486,6 +487,7 @@ static void monitor_qmp_event(void *opaque, QEMUChrEvent event) mon_refcount++; break; case CHR_EVENT_CLOSED: + mon->qmp_client_id++; /* * Note: this is only useful when the output of the chardev * backend is still open. For example, when the backend is @@ -539,6 +541,7 @@ void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) } qemu_chr_fe_set_echo(&mon->common.chr, true); + mon->qmp_client_id = 1; /* Note: we run QMP monitor in I/O thread when @chr supports that */ monitor_data_init(&mon->common, true, false, qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT)); -- 2.27.0