From nobody Sat Apr 11 18:35:49 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1775719203; cv=none; d=zohomail.com; s=zohoarc; b=T2QNPTSiM18vk06gjPPEy2WER4Y14EGoA+0FmaWt2Fdf7zytBYbu0qvqsDHYi54egtvfVZuX95iUTveqQ6bv39M6c4z7yacc0OEaZfNAt/xuiuEIl71BzQtDzvtgOJfHhFJiNszqxgPff/4FPIJJS9n8whvYEi9oO7M5Gz9erbU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775719203; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=a5uZGIlriM4UJ2YCjCXNpAnlM2tGtC747ss/XcQktXE=; b=MRn/h+YO8ZeMqNSgk4VUCgR7RdqdKoyAKAQyfAxUHtyartz3zsi0c9lh8ljWi1Nv2eBHy67895fmamaSbOQIWgZM4BmxUAcU6UYgC13gMIipaF3UAPHz9DqUmMwgW8kY+N7b0sIyYJHVYj6M421JoaXghGEj0F/XD+H64XXSDE4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775719203460832.0946515748791; Thu, 9 Apr 2026 00:20:03 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wAjf8-0007LC-9d; Thu, 09 Apr 2026 03:18:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wAjf3-0007KR-F5 for qemu-devel@nongnu.org; Thu, 09 Apr 2026 03:18:45 -0400 Received: from sea.source.kernel.org ([172.234.252.31]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wAjf1-0000Yq-GH for qemu-devel@nongnu.org; Thu, 09 Apr 2026 03:18:45 -0400 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sea.source.kernel.org (Postfix) with ESMTP id 013D943A90; Thu, 9 Apr 2026 07:18:35 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 97F9FC4CEF7; Thu, 9 Apr 2026 07:18:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775719114; bh=UUlm8e38M0cU+sF8CtorJzdeLsTyxHdaQbX9fCniErs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=W95FoXUCMXa1JBrkxNP6NTKMLmsElXzScxBksdQixMLBO2vMLudtmpI3huMkdienc YRrk6m6pv2n/9jAO+qREHxaj/0IeF3NaAA9Dp0svnqFjvmikoxD/jtiG0Os/8jOmYv YmuoK4LZf0VwxgkNwp7y/PD6Um1hCoR7S7cv6NCrtGonM27wlTVBW85G76whvgycjO 7oIw4JGs+oPQJ7Od15rPRvUotPPfoBcUIN66VQX9hHahHpW/dd0vRGmAp4wEpRj8Z8 pdvfs8IqVDe7vuRDKCqtvRIVSPDLhq35J7YzAHgsnI36xXMDUZEJr0ES8FoaRRJe7/ aVEC65BMsdPdw== From: Christian Brauner Date: Thu, 09 Apr 2026 09:18:18 +0200 Subject: [PATCH v4 1/5] monitor: store monitor id in Monitor struct MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260409-work-qmp-monitor-hotplug-v4-1-89c4fdf69df1@kernel.org> References: <20260409-work-qmp-monitor-hotplug-v4-0-89c4fdf69df1@kernel.org> In-Reply-To: <20260409-work-qmp-monitor-hotplug-v4-0-89c4fdf69df1@kernel.org> To: qemu-devel@nongnu.org Cc: Markus Armbruster , Eric Blake , Fabiano Rosas , Laurent Vivier , Paolo Bonzini , Thomas Huth , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Christian Brauner X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=7163; i=brauner@kernel.org; h=from:subject:message-id; bh=UUlm8e38M0cU+sF8CtorJzdeLsTyxHdaQbX9fCniErs=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWReDzpq7DWn5f3W3yXX3G5ecmOcuMjP8N9CZR/pxVVn+ mUnplov6ShlYRDjYpAVU2RxaDcJl1vOU7HZKFMDZg4rE8gQBi5OAZjIVl2G/zWLE10+bF56armg e7mVpOLPPVd5FKNOLa52UZ77p1qf3ZPhv5PMRZEk+UsK64SYxM3FNslG8lZvjOKSf9znsW/xs8M eHAA= X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=172.234.252.31; envelope-from=brauner@kernel.org; helo=sea.source.kernel.org X-Spam_score_int: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @kernel.org) X-ZM-MESSAGEID: 1775719205643158500 Add an 'id' field to struct Monitor. The id field stores the monitor identifier from MonitorOptions which was previously parsed but discarded. Auto-generate a unique id ("mon0", "mon1", ...) for QMP monitors created via CLI without an explicit id, so that every QMP monitor is addressable by monitor-remove and always appears with an id in query-monitors output. Extend monitor_init_qmp() to accept an id parameter so it is set before the monitor is added to mon_list. For iothread monitors, move monitor_list_append() from the setup BH to the caller so monitor_find_by_id() can detect duplicates immediately. Without this, two concurrent monitor-add calls could both pass the duplicate check before either BH runs. This means the monitor is now visible in mon_list before its chardev handlers are set up, which was not the case before. This is safe because the request queue is still empty (no chardev handlers means no monitor_qmp_read(), so the dispatcher finds nothing to dispatch) and event broadcast is handled below. This requires initializing mon->commands =3D &qmp_cap_negotiation_commands before monitor_list_append(). Without it, commands is NULL (from g_new0) and monitor_qapi_event_emit() would not skip the monitor during event broadcast -- its check is specifically for the qmp_cap_negotiation_commands pointer, so a NULL falls through to qmp_send_response() on an uninitialized monitor. CHR_EVENT_OPENED sets commands to the same value again later. Add monitor_find_by_id() to look up monitors by identifier. The lookup takes monitor_lock to serialize with the I/O thread BH that modifies mon_list, but releases it before returning. The caller must hold the BQL to ensure the returned pointer remains valid since only BQL holders can destroy monitors. Free the id string in monitor_data_destroy(). Signed-off-by: Christian Brauner (Amutable) --- include/monitor/monitor.h | 3 ++- monitor/monitor-internal.h | 4 +++- monitor/monitor.c | 21 ++++++++++++++++++++- monitor/qmp.c | 15 ++++++++++++--- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index 296690e1f1..a4e6aaa97f 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -19,7 +19,8 @@ bool monitor_cur_is_qmp(void); =20 void monitor_init_globals(void); void monitor_init_globals_core(void); -void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp); +void monitor_init_qmp(Chardev *chr, bool pretty, const char *id, + Error **errp); void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp); int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp); int monitor_init_opts(QemuOpts *opts, Error **errp); diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index feca111ae3..24d3b1900e 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -98,7 +98,7 @@ struct Monitor { bool is_qmp; bool skip_flush; bool use_io_thread; - + char *id; char *mon_cpu_path; QTAILQ_ENTRY(Monitor) entry; =20 @@ -181,6 +181,8 @@ void monitor_data_destroy_qmp(MonitorQMP *mon); void coroutine_fn monitor_qmp_dispatcher_co(void *data); void qmp_dispatcher_co_wake(void); =20 +Monitor *monitor_find_by_id(const char *id); + int get_monitor_def(Monitor *mon, int64_t *pval, const char *name); void handle_hmp_command(MonitorHMP *mon, const char *cmdline); int hmp_compare_cmd(const char *name, const char *list); diff --git a/monitor/monitor.c b/monitor/monitor.c index 00b93ed612..10a32150e9 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -622,6 +622,7 @@ void monitor_data_init(Monitor *mon, bool is_qmp, bool = skip_flush, =20 void monitor_data_destroy(Monitor *mon) { + g_free(mon->id); g_free(mon->mon_cpu_path); qemu_chr_fe_deinit(&mon->chr, false); if (monitor_is_qmp(mon)) { @@ -633,6 +634,24 @@ void monitor_data_destroy(Monitor *mon) qemu_mutex_destroy(&mon->mon_lock); } =20 +/* + * Look up a monitor by its id. The monitor_lock is released before + * returning, so the caller must hold the BQL to ensure the returned + * pointer remains valid (only BQL holders can destroy monitors). + */ +Monitor *monitor_find_by_id(const char *id) +{ + Monitor *mon; + + QEMU_LOCK_GUARD(&monitor_lock); + QTAILQ_FOREACH(mon, &mon_list, entry) { + if (mon->id && strcmp(mon->id, id) =3D=3D 0) { + return mon; + } + } + return NULL; +} + void monitor_cleanup(void) { /* @@ -732,7 +751,7 @@ int monitor_init(MonitorOptions *opts, bool allow_hmp, = Error **errp) =20 switch (opts->mode) { case MONITOR_MODE_CONTROL: - monitor_init_qmp(chr, opts->pretty, errp); + monitor_init_qmp(chr, opts->pretty, opts->id, errp); break; case MONITOR_MODE_READLINE: if (!allow_hmp) { diff --git a/monitor/qmp.c b/monitor/qmp.c index 687019811f..bba69a3a40 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -510,10 +510,10 @@ static void monitor_qmp_setup_handlers_bh(void *opaqu= e) qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_qmp_read, monitor_qmp_event, NULL, &mon->common, context, true); - monitor_list_append(&mon->common); } =20 -void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) +void monitor_init_qmp(Chardev *chr, bool pretty, const char *id, + Error **errp) { MonitorQMP *mon =3D g_new0(MonitorQMP, 1); =20 @@ -527,12 +527,20 @@ void monitor_init_qmp(Chardev *chr, bool pretty, Erro= r **errp) monitor_data_init(&mon->common, true, false, qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT= )); =20 + if (id) { + mon->common.id =3D g_strdup(id); + } else { + static unsigned int qmp_monitor_id_counter; + mon->common.id =3D g_strdup_printf("mon%u", qmp_monitor_id_counter= ++); + } mon->pretty =3D pretty; =20 qemu_mutex_init(&mon->qmp_queue_lock); mon->qmp_requests =3D g_queue_new(); =20 json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL); + /* Prevent event broadcast to an uninitialized monitor. */ + mon->commands =3D &qmp_cap_negotiation_commands; if (mon->common.use_io_thread) { /* * Make sure the old iowatch is gone. It's possible when @@ -551,7 +559,8 @@ void monitor_init_qmp(Chardev *chr, bool pretty, Error = **errp) */ aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread), monitor_qmp_setup_handlers_bh, mon); - /* The bottom half will add @mon to @mon_list */ + /* Synchronous insert for immediate duplicate detection. */ + monitor_list_append(&mon->common); } else { qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_qmp_read, monitor_qmp_event, --=20 2.47.3