Hi

On Mon, Mar 22, 2021 at 3:32 AM Lukas Straub <lukasstra...@web.de> wrote:

> When changing from chardev-socket (which supports yank) to
> chardev-socket again, it fails, because the new chardev attempts
> to register a new yank instance. This in turn fails, as there
> still is the yank instance from the current chardev. Also,
> the old chardev shouldn't unregister the yank instance when it
> is freed.
>
> To fix this, now the new chardev only registers a yank instance if
> the current chardev doesn't support yank and thus hasn't registered
> one already. Also, when the old chardev is freed, it now only
> unregisters the yank instance if the new chardev doesn't need it.
>
> s->registered_yank is always true here, as chardev-change only works
> on user-visible chardevs and those are guraranteed to register a
> yank instance as they are initialized via
> chardev_new()
>  qemu_char_open()
>   cc->open() (qmp_chardev_open_socket()).
>
> Signed-off-by: Lukas Straub <lukasstra...@web.de>
> ---
>  chardev/char-socket.c  | 20 +++++++++++++++++---
>  chardev/char.c         | 32 +++++++++++++++++++++++++-------
>  include/chardev/char.h |  4 ++++
>  3 files changed, 46 insertions(+), 10 deletions(-)
>
> diff --git a/chardev/char-socket.c b/chardev/char-socket.c
> index c8bced76b7..8186b6a205 100644
> --- a/chardev/char-socket.c
> +++ b/chardev/char-socket.c
> @@ -1119,7 +1119,13 @@ static void char_socket_finalize(Object *obj)
>      }
>      g_free(s->tls_authz);
>      if (s->registered_yank) {
> -        yank_unregister_instance(CHARDEV_YANK_INSTANCE(chr->label));
> +        /*
> +         * In the chardev-change special-case, we shouldn't unregister
> the yank
> +         * instance, as it still may be needed.
> +         */
> +        if (chr->yank_unregister_instance) {
> +            yank_unregister_instance(CHARDEV_YANK_INSTANCE(chr->label));
> +        }
>      }
>
>      qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
> @@ -1421,8 +1427,14 @@ static void qmp_chardev_open_socket(Chardev *chr,
>          qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
>      }
>
> -    if (!yank_register_instance(CHARDEV_YANK_INSTANCE(chr->label), errp))
> {
> -        return;
> +    /*
> +     * In the chardev-change special-case, we shouldn't register a new
> yank
> +     * instance, as there already may be one.
> +     */
> +    if (chr->yank_register_instance) {
> +        if (!yank_register_instance(CHARDEV_YANK_INSTANCE(chr->label),
> errp)) {
> +            return;
> +        }
>      }
>      s->registered_yank = true;
>
> @@ -1564,6 +1576,8 @@ static void char_socket_class_init(ObjectClass *oc,
> void *data)
>  {
>      ChardevClass *cc = CHARDEV_CLASS(oc);
>
> +    cc->supports_yank = true;
> +
>      cc->parse = qemu_chr_parse_socket;
>      cc->open = qmp_chardev_open_socket;
>      cc->chr_wait_connected = tcp_chr_wait_connected;
> diff --git a/chardev/char.c b/chardev/char.c
> index ad416c0714..245f8be201 100644
> --- a/chardev/char.c
> +++ b/chardev/char.c
> @@ -39,6 +39,7 @@
>  #include "qemu/option.h"
>  #include "qemu/id.h"
>  #include "qemu/coroutine.h"
> +#include "qemu/yank.h"
>
>  #include "chardev-internal.h"
>
> @@ -266,6 +267,8 @@ static void char_init(Object *obj)
>  {
>      Chardev *chr = CHARDEV(obj);
>
> +    chr->yank_register_instance = true;
> +    chr->yank_unregister_instance = true;
>      chr->logfd = -1;
>      qemu_mutex_init(&chr->chr_write_lock);
>
> @@ -956,6 +959,7 @@ void qemu_chr_set_feature(Chardev *chr,
>  static Chardev *chardev_new(const char *id, const char *typename,
>                              ChardevBackend *backend,
>                              GMainContext *gcontext,
> +                            bool yank_register_instance,
>                              Error **errp)
>  {
>      Object *obj;
> @@ -968,6 +972,7 @@ static Chardev *chardev_new(const char *id, const char
> *typename,
>
>      obj = object_new(typename);
>      chr = CHARDEV(obj);
> +    chr->yank_register_instance = yank_register_instance;
>      chr->label = g_strdup(id);
>      chr->gcontext = gcontext;
>
> @@ -1001,7 +1006,7 @@ Chardev *qemu_chardev_new(const char *id, const char
> *typename,
>          id = genid;
>      }
>
> -    chr = chardev_new(id, typename, backend, gcontext, errp);
> +    chr = chardev_new(id, typename, backend, gcontext, true, errp);
>      if (!chr) {
>          return NULL;
>      }
> @@ -1029,7 +1034,7 @@ ChardevReturn *qmp_chardev_add(const char *id,
> ChardevBackend *backend,
>      }
>
>      chr = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
> -                      backend, NULL, errp);
> +                      backend, NULL, true, errp);
>      if (!chr) {
>          return NULL;
>      }
> @@ -1054,7 +1059,7 @@ ChardevReturn *qmp_chardev_change(const char *id,
> ChardevBackend *backend,
>                                    Error **errp)
>  {
>      CharBackend *be;
> -    const ChardevClass *cc;
> +    const ChardevClass *cc, *cc_new;
>      Chardev *chr, *chr_new;
>      bool closed_sent = false;
>      ChardevReturn *ret;
> @@ -1088,13 +1093,20 @@ ChardevReturn *qmp_chardev_change(const char *id,
> ChardevBackend *backend,
>          return NULL;
>      }
>
> -    cc = char_get_class(ChardevBackendKind_str(backend->type), errp);
> -    if (!cc) {
> +    cc = CHARDEV_GET_CLASS(chr);
> +    cc_new = char_get_class(ChardevBackendKind_str(backend->type), errp);
> +    if (!cc_new) {
>          return NULL;
>      }
>
> -    chr_new = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
> -                          backend, chr->gcontext, errp);
> +    /*
> +     * Only register a yank instance if the current chardev hasn't
> registered
> +     * one already.
> +     */
> +    chr_new = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc_new)),
> +                          backend, chr->gcontext,
> +                          /* yank_register_instance = */
> !cc->supports_yank,
> +                          errp);
>      if (!chr_new) {
>          return NULL;
>      }
> @@ -1118,6 +1130,12 @@ ChardevReturn *qmp_chardev_change(const char *id,
> ChardevBackend *backend,
>          return NULL;
>      }
>
> +    /*
> +     * When the old chardev is freed, it should only unregister the yank
> +     * instance if the new chardev doesn't need it.
> +     */
> +    chr->yank_unregister_instance = !cc_new->supports_yank;
> +
>      object_unparent(OBJECT(chr));
>      object_property_add_child(get_chardevs_root(), chr_new->label,
>                                OBJECT(chr_new));
> diff --git a/include/chardev/char.h b/include/chardev/char.h
> index 4181a2784a..ff38bb3af0 100644
> --- a/include/chardev/char.h
> +++ b/include/chardev/char.h
> @@ -65,6 +65,9 @@ struct Chardev {
>      char *filename;
>      int logfd;
>      int be_open;
> +    /* used to coordinate the chardev-change special-case: */
> +    bool yank_register_instance;
> +    bool yank_unregister_instance;
>      GSource *gsource;
>      GMainContext *gcontext;
>      DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST);
> @@ -251,6 +254,7 @@ struct ChardevClass {
>      ObjectClass parent_class;
>
>      bool internal; /* TODO: eventually use TYPE_USER_CREATABLE */
> +    bool supports_yank;
>      void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
>
>      void (*open)(Chardev *chr, ChardevBackend *backend,
>


Not very pleased with the change, but I can't imagine anything
better/simpler atm. Maybe someone else. So
Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com>

-- 
Marc-André Lureau

Reply via email to