public inbox for qemu-devel@nongnu.org
 help / color / mirror / Atom feed
From: "Daniel P. Berrangé" <berrange@redhat.com>
To: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org
Subject: Re: [PATCH 46/60] ui/vnc: merge vnc_display_init() and vnc_display_open()
Date: Tue, 24 Mar 2026 14:51:32 +0000	[thread overview]
Message-ID: <acKk9CIbQMXGWbeu@redhat.com> (raw)
In-Reply-To: <20260317-qemu-vnc-v1-46-48eb1dcf7b76@redhat.com>

On Tue, Mar 17, 2026 at 12:51:00PM +0400, Marc-André Lureau wrote:
> Combine the two-step vnc_display_init()/vnc_display_open() sequence
> into a single vnc_display_new() function that returns VncDisplay*.
> This simplifies the API by making vnc_display_open() an
> internal detail and will allow further code simplification.
> 
> vnc_display_new() is moved to vnc.h, since it returns VncDisplay* now.
> Add vnc_display_free() for consistency, and it will be later used.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  include/ui/console.h |  2 --
>  ui/vnc.h             |  3 ++
>  ui/vnc.c             | 79 ++++++++++++++++++++++------------------------------
>  3 files changed, 37 insertions(+), 47 deletions(-)
> 
> diff --git a/include/ui/console.h b/include/ui/console.h
> index 152333d60fc..737ceba3890 100644
> --- a/include/ui/console.h
> +++ b/include/ui/console.h
> @@ -448,8 +448,6 @@ const char *qemu_display_get_vc(DisplayOptions *opts);
>  void qemu_display_help(void);
>  
>  /* vnc.c */
> -void vnc_display_init(const char *id, Error **errp);
> -void vnc_display_open(const char *id, Error **errp);
>  void vnc_display_add_client(const char *id, int csock, bool skipauth);
>  int vnc_display_password(const char *id, const char *password, Error **errp);
>  int vnc_display_pw_expire(const char *id, time_t expires);
> diff --git a/ui/vnc.h b/ui/vnc.h
> index c5d678ac31e..6afe0f16d12 100644
> --- a/ui/vnc.h
> +++ b/ui/vnc.h
> @@ -548,6 +548,9 @@ enum VncFeatures {
>  #define VNC_CLIPBOARD_NOTIFY   (1 << 27)
>  #define VNC_CLIPBOARD_PROVIDE  (1 << 28)
>  
> +VncDisplay *vnc_display_new(const char *id, Error **errp);
> +void vnc_display_free(VncDisplay *vd);

This re-inforces my comment from the previous patch, wrt stopping
the VNC worker thread. If we're exposing this as a "public" API,
then IMHO, we need to  keep around all the code for stopping the
worker thread, revert 09526058d0a501106dcac842a455e187f1413d98
and actually call vnc_stop_worker_thread in the right place(s).

> +
>  /*****************************************************************************
>   *
>   * Internal APIs
> diff --git a/ui/vnc.c b/ui/vnc.c
> index 115ff8a988e..03b99c9e590 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -3421,14 +3421,14 @@ static void vmstate_change_handler(void *opaque, bool running, RunState state)
>      update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
>  }
>  
> -static void vnc_display_free(VncDisplay *vd);
> +static bool vnc_display_open(VncDisplay *vd, Error **errp);
>  
> -void vnc_display_init(const char *id, Error **errp)
> +VncDisplay *vnc_display_new(const char *id, Error **errp)
>  {
>      VncDisplay *vd;
>  
>      if (vnc_display_find(id) != NULL) {
> -        return;
> +        return NULL;
>      }
>      vd = g_malloc0(sizeof(*vd));
>  
> @@ -3449,7 +3449,7 @@ void vnc_display_init(const char *id, Error **errp)
>  
>      if (!vd->kbd_layout) {
>          vnc_display_free(vd);
> -        return;
> +        return NULL;
>      }
>  
>      vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
> @@ -3462,7 +3462,13 @@ void vnc_display_init(const char *id, Error **errp)
>      vd->vmstate_handler_entry = qemu_add_vm_change_state_handler(
>          &vmstate_change_handler, vd);
>  
> +    if (!vnc_display_open(vd, errp)) {
> +        vnc_display_free(vd);
> +        return NULL;
> +    }
> +
>      QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
> +    return vd;
>  }
>  
>  static void vnc_display_close(VncDisplay *vd)
> @@ -3507,7 +3513,7 @@ static void vnc_display_close(VncDisplay *vd)
>  #endif
>  }
>  
> -static void vnc_display_free(VncDisplay *vd)
> +void vnc_display_free(VncDisplay *vd)
>  {
>      if (!vd) {
>          return;
> @@ -3525,7 +3531,6 @@ static void vnc_display_free(VncDisplay *vd)
>      g_free(vd);
>  }
>  
> -
>  int vnc_display_password(const char *id, const char *password, Error **errp)
>  {
>      VncDisplay *vd = vnc_display_find(id);
> @@ -4068,10 +4073,9 @@ bool vnc_display_update(DisplayUpdateOptionsVNC *arg, Error **errp)
>      return true;
>  }
>  
> -void vnc_display_open(const char *id, Error **errp)
> +static bool vnc_display_open(VncDisplay *vd, Error **errp)
>  {
> -    VncDisplay *vd = vnc_display_find(id);
> -    QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
> +    QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, vd->id);
>      g_autoptr(SocketAddressList) saddr_list = NULL;
>      g_autoptr(SocketAddressList) wsaddr_list = NULL;
>      const char *share, *device_id;
> @@ -4090,26 +4094,23 @@ void vnc_display_open(const char *id, Error **errp)
>      assert(vd);
>      assert(opts);
>  
> -    vnc_display_close(vd);
> -
>      reverse = qemu_opt_get_bool(opts, "reverse", false);
>      if (vnc_display_get_addresses(opts, reverse, &saddr_list, &wsaddr_list,
>                                    errp) < 0) {
> -        goto fail;
> +        return false;
>      }
>  
> -
>      passwordSecret = qemu_opt_get(opts, "password-secret");
>      if (passwordSecret) {
>          if (qemu_opt_get(opts, "password")) {
>              error_setg(errp,
>                         "'password' flag is redundant with 'password-secret'");
> -            goto fail;
> +            return false;
>          }
>          vd->password = qcrypto_secret_lookup_as_utf8(passwordSecret,
>                                                       errp);
>          if (!vd->password) {
> -            goto fail;
> +            return false;
>          }
>          password = true;
>      } else {
> @@ -4120,7 +4121,7 @@ void vnc_display_open(const char *id, Error **errp)
>                  QCRYPTO_CIPHER_ALGO_DES, QCRYPTO_CIPHER_MODE_ECB)) {
>              error_setg(errp,
>                         "Cipher backend does not support DES algorithm");
> -            goto fail;
> +            return false;
>          }
>      }
>  
> @@ -4130,7 +4131,7 @@ void vnc_display_open(const char *id, Error **errp)
>  #ifndef CONFIG_VNC_SASL
>      if (sasl) {
>          error_setg(errp, "VNC SASL auth requires cyrus-sasl support");
> -        goto fail;
> +        return false;
>      }
>  #endif /* CONFIG_VNC_SASL */
>      credid = qemu_opt_get(opts, "tls-creds");
> @@ -4141,7 +4142,7 @@ void vnc_display_open(const char *id, Error **errp)
>          if (!creds) {
>              error_setg(errp, "No TLS credentials with id '%s'",
>                         credid);
> -            goto fail;
> +            return false;
>          }
>          vd->tlscreds = (QCryptoTLSCreds *)
>              object_dynamic_cast(creds,
> @@ -4149,26 +4150,26 @@ void vnc_display_open(const char *id, Error **errp)
>          if (!vd->tlscreds) {
>              error_setg(errp, "Object with id '%s' is not TLS credentials",
>                         credid);
> -            goto fail;
> +            return false;
>          }
>          object_ref(OBJECT(vd->tlscreds));
>  
>          if (!qcrypto_tls_creds_check_endpoint(vd->tlscreds,
>                                                QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
>                                                errp)) {
> -            goto fail;
> +            return false;
>          }
>      }
>      tlsauthz = qemu_opt_get(opts, "tls-authz");
>      if (tlsauthz && !vd->tlscreds) {
>          error_setg(errp, "'tls-authz' provided but TLS is not enabled");
> -        goto fail;
> +        return false;
>      }
>  
>      saslauthz = qemu_opt_get(opts, "sasl-authz");
>      if (saslauthz && !sasl) {
>          error_setg(errp, "'sasl-authz' provided but SASL auth is not enabled");
> -        goto fail;
> +        return false;
>      }
>  
>      share = qemu_opt_get(opts, "share");
> @@ -4181,7 +4182,7 @@ void vnc_display_open(const char *id, Error **errp)
>              vd->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
>          } else {
>              error_setg(errp, "unknown vnc share= option");
> -            goto fail;
> +            return false;
>          }
>      } else {
>          vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
> @@ -4215,20 +4216,20 @@ void vnc_display_open(const char *id, Error **errp)
>      if (vnc_display_setup_auth(&vd->auth, &vd->subauth,
>                                 vd->tlscreds, password,
>                                 sasl, false, errp) < 0) {
> -        goto fail;
> +        return false;
>      }
>      trace_vnc_auth_init(vd, 0, vd->auth, vd->subauth);
>  
>      if (vnc_display_setup_auth(&vd->ws_auth, &vd->ws_subauth,
>                                 vd->tlscreds, password,
>                                 sasl, true, errp) < 0) {
> -        goto fail;
> +        return false;
>      }
>      trace_vnc_auth_init(vd, 1, vd->ws_auth, vd->ws_subauth);
>  
>  #ifdef CONFIG_VNC_SASL
>      if (sasl && !vnc_sasl_server_init(errp)) {
> -        goto fail;
> +        return false;
>      }
>  #endif
>      vd->lock_key_sync = lock_key_sync;
> @@ -4241,7 +4242,7 @@ void vnc_display_open(const char *id, Error **errp)
>      if (audiodev) {
>          vd->audio_be = audio_be_by_name(audiodev, errp);
>          if (!vd->audio_be) {
> -            goto fail;
> +            return false;
>          }
>      } else {
>          vd->audio_be = audio_get_default_audio_be(NULL);
> @@ -4255,7 +4256,7 @@ void vnc_display_open(const char *id, Error **errp)
>          con = qemu_console_lookup_by_device_name(device_id, head, &err);
>          if (err) {
>              error_propagate(errp, err);
> -            goto fail;
> +            return false;
>          }
>      } else {
>          con = qemu_console_lookup_default();
> @@ -4271,16 +4272,16 @@ void vnc_display_open(const char *id, Error **errp)
>      qkbd_state_set_delay(vd->kbd, key_delay_ms);
>  
>      if (saddr_list == NULL) {
> -        return;
> +        return true;
>      }
>  
>      if (reverse) {
>          if (vnc_display_connect(vd, saddr_list, wsaddr_list, errp) < 0) {
> -            goto fail;
> +            return false;
>          }
>      } else {
>          if (vnc_display_listen(vd, saddr_list, wsaddr_list, errp) < 0) {
> -            goto fail;
> +            return false;
>          }
>      }
>  
> @@ -4288,11 +4289,7 @@ void vnc_display_open(const char *id, Error **errp)
>          vnc_display_print_local_addr(vd);
>      }
>  
> -    /* Success */
> -    return;
> -
> -fail:
> -    vnc_display_close(vd);
> +    return true;
>  }

I think it would be helpful for clarity if we changed vnc_display_init
and vnc_display_open to have a 'bool' return value in an earlier patch,
then let this patch just focus on the merge without the large
refactoring of return vaules.


>  
>  void vnc_display_add_client(const char *id, int csock, bool skipauth)
> @@ -4348,15 +4345,7 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
>          id = vnc_auto_assign_id(opts);
>      }
>  
> -    vnc_display_init(id, errp);
> -    if (*errp) {
> -        return -1;
> -    }
> -    vnc_display_open(id, errp);
> -    if (*errp) {
> -        return -1;
> -    }
> -    return 0;
> +    return vnc_display_new(id, errp) != NULL ? 0 : -1;
>  }
>  
>  static void vnc_register_config(void)
> 
> -- 
> 2.53.0
> 
> 

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



  reply	other threads:[~2026-03-24 14:52 UTC|newest]

Thread overview: 105+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-17  8:50 [PATCH 00/60] ui: add standalone VNC server over D-Bus Marc-André Lureau
2026-03-17  8:50 ` [PATCH 01/60] ui/vnc-jobs: fix VncRectEntry leak on job cleanup Marc-André Lureau
2026-03-24 13:43   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 02/60] ui/vnc-jobs: clear source tag Marc-André Lureau
2026-03-24 13:44   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 03/60] ui/vnc-jobs: remove needless buffer_reset() before end Marc-André Lureau
2026-03-24 13:45   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 04/60] ui/vnc: clarify intent using buffer_empty() function Marc-André Lureau
2026-03-24 13:45   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 05/60] ui/vnc-jobs: vnc_has_job_locked() argument cannot be NULL Marc-André Lureau
2026-03-24 13:46   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 06/60] ui/vnc-jobs: remove dead VncJobQueue.exit Marc-André Lureau
2026-03-24 13:49   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 07/60] ui/vnc-jobs: remove vnc_queue_clear() Marc-André Lureau
2026-03-24 13:51   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 08/60] ui/vnc-jobs: narrow taking the lock when pushing empty jobs Marc-André Lureau
2026-03-24 13:53   ` Daniel P. Berrangé
2026-03-24 14:04     ` Marc-André Lureau
2026-03-17  8:50 ` [PATCH 09/60] ui/vnc-jobs: drop redundant (and needless) qemu_thread_get_self() Marc-André Lureau
2026-03-24 14:00   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 10/60] ui/console-vc: fix off-by-one in CSI J 2 (clear entire screen) Marc-André Lureau
2026-03-24 14:03   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 11/60] ui/console-vc: add UTF-8 input decoding with CP437 rendering Marc-André Lureau
2026-03-24 14:07   ` Daniel P. Berrangé
2026-03-24 14:17     ` Marc-André Lureau
2026-03-24 15:42       ` Daniel P. Berrangé
2026-03-25  5:35   ` Markus Armbruster
2026-03-25  6:48     ` Marc-André Lureau
2026-03-17  8:50 ` [PATCH 12/60] ui/console-vc: ignore string-type escape sequences Marc-André Lureau
2026-03-17  8:50 ` [PATCH 13/60] ui/console-vc: fix comment shift-out/in comments Marc-André Lureau
2026-03-24 14:11   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 14/60] ui/console: dispatch get_label() through QOM virtual method Marc-André Lureau
2026-03-24 14:14   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 15/60] ui/console-vc: introduce QemuVT100 Marc-André Lureau
2026-03-17  8:50 ` [PATCH 16/60] ui/console-vc: set vt100 associated pixman image Marc-André Lureau
2026-03-17  8:50 ` [PATCH 17/60] ui/console-vc: vga_putcharxy()->vt100_putcharxy() Marc-André Lureau
2026-03-17  8:50 ` [PATCH 18/60] ui/console-vc: make invalidate_xy() take vt100 Marc-André Lureau
2026-03-17  8:50 ` [PATCH 19/60] ui/console-vc: make show_cursor() " Marc-André Lureau
2026-03-17  8:50 ` [PATCH 20/60] ui/console-vc: decouple VT100 display updates via function pointer Marc-André Lureau
2026-03-17  8:50 ` [PATCH 21/60] ui/console-vc: console_refresh() -> vt100_refresh() Marc-André Lureau
2026-03-17  8:50 ` [PATCH 22/60] ui/console-vc: move cursor blinking logic into VT100 layer Marc-André Lureau
2026-03-17  8:50 ` [PATCH 23/60] ui/console-vc: console_scroll() -> vt100_scroll() Marc-André Lureau
2026-03-17  8:50 ` [PATCH 24/60] ui/console-vc: refactor text_console_resize() into vt100_set_image() Marc-André Lureau
2026-03-17  8:50 ` [PATCH 25/60] ui/console-vc: move vc_put_lf() to VT100 layer as vt100_put_lf() Marc-André Lureau
2026-03-17  8:50 ` [PATCH 26/60] ui/console-vc: unify the write path Marc-André Lureau
2026-03-17  8:50 ` [PATCH 27/60] ui/console-vc: move VT100 state machine and output FIFO into QemuVT100 Marc-André Lureau
2026-03-17  8:50 ` [PATCH 28/60] ui/console-vc: extract vt100_input() from vc_chr_write() Marc-André Lureau
2026-03-17  8:50 ` [PATCH 29/60] ui/console-vc: extract vt100_keysym() from qemu_text_console_handle_keysym() Marc-André Lureau
2026-03-17  8:50 ` [PATCH 30/60] ui/console-vc: extract vt100_init() and vt100_fini() Marc-André Lureau
2026-03-17  8:50 ` [PATCH 31/60] ui/console: remove console_ch_t typedef and console_write_ch() Marc-André Lureau
2026-03-17  8:50 ` [PATCH 32/60] ui: avoid duplicating vgafont16 in each translation unit Marc-André Lureau
2026-03-24 14:22   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 33/60] ui/vgafont: add SPDX license header Marc-André Lureau
2026-03-24 14:24   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 34/60] ui: move FONT_WIDTH/HEIGHT to vgafont.h Marc-André Lureau
2026-03-24 14:25   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 35/60] ui/console-vc: move VT100 emulation into separate unit Marc-André Lureau
2026-03-17  8:50 ` [PATCH 36/60] util: move datadir.c from system/ Marc-André Lureau
2026-03-24 14:27   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 37/60] ui: move DisplaySurface functions to display-surface.c Marc-André Lureau
2026-03-17  8:50 ` [PATCH 38/60] ui: make qemu_default_pixelformat() static inline Marc-André Lureau
2026-03-24 14:28   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 39/60] ui: make unregister_displaychangelistener() skip unregistered Marc-André Lureau
2026-03-24 14:28   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 40/60] ui: minor code simplification Marc-André Lureau
2026-03-24 14:30   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 41/60] system: make qemu_del_vm_change_state_handler accept NULL Marc-André Lureau
2026-03-24 14:31   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 42/60] ui/vnc: assert preconditions instead of silently returning Marc-André Lureau
2026-03-24 14:31   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 43/60] ui/vnc: simplify vnc_init_func error handling Marc-André Lureau
2026-03-24 14:38   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 44/60] ui/vnc: VncDisplay.id is not const Marc-André Lureau
2026-03-24 14:39   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 45/60] ui/vnc: fix vnc_display_init() leak on failure Marc-André Lureau
2026-03-24 14:47   ` Daniel P. Berrangé
2026-03-17  8:51 ` [PATCH 46/60] ui/vnc: merge vnc_display_init() and vnc_display_open() Marc-André Lureau
2026-03-24 14:51   ` Daniel P. Berrangé [this message]
2026-03-17  8:51 ` [PATCH 47/60] ui/vnc: report an error for duplicate display id Marc-André Lureau
2026-03-24 14:52   ` Daniel P. Berrangé
2026-03-17  8:51 ` [PATCH 48/60] ui/vnc: defer listener registration until the console is known Marc-André Lureau
2026-03-24 14:53   ` Daniel P. Berrangé
2026-03-17  8:51 ` [PATCH 49/60] ui/vnc: explicitly link with png Marc-André Lureau
2026-03-24 14:56   ` Daniel P. Berrangé
2026-03-17  8:51 ` [PATCH 50/60] ui/vnc: add vnc-system unit, to allow different implementations Marc-André Lureau
2026-03-17  8:51 ` [PATCH 51/60] ui/console: remove qemu_console_is_visible() Marc-André Lureau
2026-03-24 14:57   ` Daniel P. Berrangé
2026-03-17  8:51 ` [PATCH 52/60] ui/console: simplify registering display/console change listener Marc-André Lureau
2026-03-17  8:51 ` [PATCH 53/60] ui/console: return completion status from gfx_update callback Marc-André Lureau
2026-03-17 11:43   ` BALATON Zoltan
2026-03-17  8:51 ` [PATCH 54/60] ui/console: rename public API to use consistent qemu_console_ prefix Marc-André Lureau
2026-03-17 11:46   ` BALATON Zoltan
2026-03-17  8:51 ` [PATCH 55/60] ui/console: move console_handle_touch_event() to input Marc-André Lureau
2026-03-17  8:51 ` [PATCH 56/60] ui: extract common sources into a static library Marc-André Lureau
2026-03-17  8:51 ` [PATCH 57/60] tests: rename the dbus-daemon helper script Marc-André Lureau
2026-03-24 15:05   ` Daniel P. Berrangé
2026-03-17  8:51 ` [PATCH 58/60] tests/qtest: fix dbus-vmstate-test compilation Marc-André Lureau
2026-03-17 12:28   ` Fabiano Rosas
2026-03-17 12:39     ` Marc-André Lureau
2026-03-17  8:51 ` [PATCH 59/60] tests/qtest: drop DBUS_VMSTATE_TEST_TMPDIR Marc-André Lureau
2026-03-17  8:51 ` [PATCH 60/60] contrib/qemu-vnc: add standalone VNC server over D-Bus Marc-André Lureau
2026-03-24 15:24   ` Daniel P. Berrangé
2026-03-24 15:44     ` Peter Maydell
2026-03-25  8:32     ` Marc-André Lureau
2026-03-24 17:36 ` [PATCH 00/60] ui: " Daniel P. Berrangé

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=acKk9CIbQMXGWbeu@redhat.com \
    --to=berrange@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox