@@ -1126,7 +1126,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->handover_yank_instance) {
+ yank_unregister_instance(CHARDEV_YANK_INSTANCE(chr->label));
+ }
}
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
@@ -1424,8 +1430,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->handover_yank_instance) {
+ if (!yank_register_instance(CHARDEV_YANK_INSTANCE(chr->label), errp)) {
+ return;
+ }
}
s->registered_yank = true;
@@ -1567,6 +1579,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;
@@ -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,7 @@ static void char_init(Object *obj)
{
Chardev *chr = CHARDEV(obj);
+ chr->handover_yank_instance = false;
chr->logfd = -1;
qemu_mutex_init(&chr->chr_write_lock);
@@ -959,6 +961,7 @@ void qemu_chr_set_feature(Chardev *chr,
static Chardev *chardev_new(const char *id, const char *typename,
ChardevBackend *backend,
GMainContext *gcontext,
+ bool handover_yank_instance,
Error **errp)
{
Object *obj;
@@ -971,6 +974,7 @@ static Chardev *chardev_new(const char *id, const char *typename,
obj = object_new(typename);
chr = CHARDEV(obj);
+ chr->handover_yank_instance = handover_yank_instance;
chr->label = g_strdup(id);
chr->gcontext = gcontext;
@@ -1004,7 +1008,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, false, errp);
if (!chr) {
return NULL;
}
@@ -1032,7 +1036,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, false, errp);
if (!chr) {
return NULL;
}
@@ -1057,9 +1061,10 @@ 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;
+ bool handover_yank_instance;
ChardevReturn *ret;
chr = qemu_chr_find(id);
@@ -1091,13 +1096,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);
+ /*
+ * The new chardev should not register a yank instance if the current
+ * chardev has registered one already.
+ */
+ handover_yank_instance = cc->supports_yank && cc_new->supports_yank;
+
+ chr_new = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc_new)),
+ backend, chr->gcontext, handover_yank_instance, errp);
if (!chr_new) {
return NULL;
}
@@ -1121,6 +1133,15 @@ ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend,
return NULL;
}
+ /* change successfull, clean up */
+ chr_new->handover_yank_instance = false;
+
+ /*
+ * When the old chardev is freed, it should not unregister the yank
+ * instance if the new chardev needs it.
+ */
+ chr->handover_yank_instance = handover_yank_instance;
+
object_unparent(OBJECT(chr));
object_property_add_child(get_chardevs_root(), chr_new->label,
OBJECT(chr_new));
@@ -65,6 +65,8 @@ struct Chardev {
char *filename;
int logfd;
int be_open;
+ /* used to coordinate the chardev-change special-case: */
+ bool handover_yank_instance;
GSource *gsource;
GMainContext *gcontext;
DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST);
@@ -251,6 +253,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,