For further vhost-user-blk backend-transfer migration realization we
want to give it (vhost-user-blk) a possibility (and responsibility) to
decide when do connect.
For incoming migration we'll need to postpone connect at least until
early stage of migrate-incoming command, when we already know all
migration parameters and can decide, are we going to do incoming
backend-transfer (and get chardev fd from incoming stream), or we
finally need to connect.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
chardev/char-fe.c | 32 ++++++++++++++++++++++++-----
hw/core/qdev-properties-system.c | 26 ++++++++++++++++++++---
include/chardev/char-fe.h | 8 ++++++--
include/hw/qdev-properties-system.h | 3 +++
4 files changed, 59 insertions(+), 10 deletions(-)
diff --git a/chardev/char-fe.c b/chardev/char-fe.c
index c67b4d640f..1132ec0501 100644
--- a/chardev/char-fe.c
+++ b/chardev/char-fe.c
@@ -189,15 +189,26 @@ bool qemu_chr_fe_backend_open(CharFrontend *c)
return c->chr && c->chr->be_open;
}
-bool qemu_chr_fe_init(CharFrontend *c, Chardev *s, Error **errp)
+bool qemu_chr_fe_init_ex(CharFrontend *c, Chardev *s, bool connect,
+ Error **errp)
{
unsigned int tag = 0;
- if (!qemu_chr_connect(s, errp)) {
- return false;
- }
-
if (s) {
+ if (connect) {
+ if (!qemu_chr_connect(s, errp)) {
+ return false;
+ }
+ } else {
+ /* DEFINE_PROP_CHR_NO_CONNECT */
+ if (!s->connect_postponed) {
+ error_setg(errp,
+ "Chardev %s does not support postponed connect",
+ s->label);
+ return false;
+ }
+ }
+
if (CHARDEV_IS_MUX(s)) {
MuxChardev *d = MUX_CHARDEV(s);
@@ -210,6 +221,12 @@ bool qemu_chr_fe_init(CharFrontend *c, Chardev *s, Error **errp)
} else {
s->fe = c;
}
+ } else {
+ /*
+ * connect=false comes only from DEFINE_PROP_CHR_NO_CONNECT,
+ * through do_set_chr, which provides chardev ptr.
+ */
+ assert(connect);
}
c->fe_is_open = false;
@@ -218,6 +235,11 @@ bool qemu_chr_fe_init(CharFrontend *c, Chardev *s, Error **errp)
return true;
}
+bool qemu_chr_fe_init(CharFrontend *c, Chardev *s, Error **errp)
+{
+ return qemu_chr_fe_init_ex(c, s, true, errp);
+}
+
void qemu_chr_fe_deinit(CharFrontend *c, bool del)
{
assert(c);
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 13cc91680b..00f4b19238 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -266,8 +266,8 @@ static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
g_free(p);
}
-static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
- Error **errp)
+static void do_set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
+ bool connect, Error **errp)
{
ERRP_GUARD();
const Property *prop = opaque;
@@ -297,13 +297,25 @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
if (s == NULL) {
error_setg(errp, "Property '%s.%s' can't find value '%s'",
object_get_typename(obj), name, str);
- } else if (!qemu_chr_fe_init(fe, s, errp)) {
+ } else if (!qemu_chr_fe_init_ex(fe, s, connect, errp)) {
error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
object_get_typename(obj), name, str);
}
g_free(str);
}
+static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
+ Error **errp)
+{
+ do_set_chr(obj, v, name, opaque, true, errp);
+}
+
+static void set_chr_no_connect(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ do_set_chr(obj, v, name, opaque, false, errp);
+}
+
static void release_chr(Object *obj, const char *name, void *opaque)
{
const Property *prop = opaque;
@@ -320,6 +332,14 @@ const PropertyInfo qdev_prop_chr = {
.release = release_chr,
};
+const PropertyInfo qdev_prop_chr_no_connect = {
+ .type = "str",
+ .description = "ID of a chardev to use as a backend",
+ .get = get_chr,
+ .set = set_chr_no_connect,
+ .release = release_chr,
+};
+
/* --- mac address --- */
/*
diff --git a/include/chardev/char-fe.h b/include/chardev/char-fe.h
index 5f8a6df17d..f3df57afa1 100644
--- a/include/chardev/char-fe.h
+++ b/include/chardev/char-fe.h
@@ -25,14 +25,18 @@ struct CharFrontend {
};
/**
- * qemu_chr_fe_init:
+ * qemu_chr_fe_init(_ex):
*
* Initializes the frontend @c for the given Chardev backend @s. Call
* qemu_chr_fe_deinit() to remove the association and release the backend.
+ * Call qemu_chr_connect(), except for the case when connect=false
+ * parameter set for _ex() version.
*
* Returns: false on error.
*/
-bool qemu_chr_fe_init(CharFrontend *c, Chardev *be, Error **errp);
+bool qemu_chr_fe_init(CharFrontend *c, Chardev *s, Error **errp);
+bool qemu_chr_fe_init_ex(CharFrontend *c, Chardev *s, bool connect,
+ Error **errp);
/**
* qemu_chr_fe_deinit:
diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properties-system.h
index 5c6cc5eae8..a0b14a2f77 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -7,6 +7,7 @@ bool qdev_prop_sanitize_s390x_loadparm(uint8_t *loadparm, const char *str,
Error **errp);
extern const PropertyInfo qdev_prop_chr;
+extern const PropertyInfo qdev_prop_chr_no_connect;
extern const PropertyInfo qdev_prop_macaddr;
extern const PropertyInfo qdev_prop_reserved_region;
extern const PropertyInfo qdev_prop_multifd_compression;
@@ -39,6 +40,8 @@ extern const PropertyInfo qdev_prop_virtio_gpu_output_list;
#define DEFINE_PROP_CHR(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharFrontend)
+#define DEFINE_PROP_CHR_NO_CONNECT(_n, _s, _f) \
+ DEFINE_PROP(_n, _s, _f, qdev_prop_chr_no_connect, CharFrontend)
#define DEFINE_PROP_NETDEV(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NICPeers)
#define DEFINE_PROP_DRIVE(_n, _s, _f) \
--
2.48.1
Hi
On Fri, Oct 31, 2025 at 7:59 PM Vladimir Sementsov-Ogievskiy <
vsementsov@yandex-team.ru> wrote:
> For further vhost-user-blk backend-transfer migration realization we
> want to give it (vhost-user-blk) a possibility (and responsibility) to
> decide when do connect.
>
> For incoming migration we'll need to postpone connect at least until
> early stage of migrate-incoming command, when we already know all
> migration parameters and can decide, are we going to do incoming
> backend-transfer (and get chardev fd from incoming stream), or we
> finally need to connect.
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> ---
> chardev/char-fe.c | 32 ++++++++++++++++++++++++-----
> hw/core/qdev-properties-system.c | 26 ++++++++++++++++++++---
> include/chardev/char-fe.h | 8 ++++++--
> include/hw/qdev-properties-system.h | 3 +++
> 4 files changed, 59 insertions(+), 10 deletions(-)
>
> diff --git a/chardev/char-fe.c b/chardev/char-fe.c
> index c67b4d640f..1132ec0501 100644
> --- a/chardev/char-fe.c
> +++ b/chardev/char-fe.c
> @@ -189,15 +189,26 @@ bool qemu_chr_fe_backend_open(CharFrontend *c)
> return c->chr && c->chr->be_open;
> }
>
> -bool qemu_chr_fe_init(CharFrontend *c, Chardev *s, Error **errp)
> +bool qemu_chr_fe_init_ex(CharFrontend *c, Chardev *s, bool connect,
> + Error **errp)
> {
> unsigned int tag = 0;
>
> - if (!qemu_chr_connect(s, errp)) {
> - return false;
> - }
> -
> if (s) {
> + if (connect) {
> + if (!qemu_chr_connect(s, errp)) {
> + return false;
> + }
> + } else {
> + /* DEFINE_PROP_CHR_NO_CONNECT */
> + if (!s->connect_postponed) {
> + error_setg(errp,
> + "Chardev %s does not support postponed
> connect",
> + s->label);
> + return false;
> + }
> + }
> +
> if (CHARDEV_IS_MUX(s)) {
> MuxChardev *d = MUX_CHARDEV(s);
>
> @@ -210,6 +221,12 @@ bool qemu_chr_fe_init(CharFrontend *c, Chardev *s,
> Error **errp)
> } else {
> s->fe = c;
> }
> + } else {
> + /*
> + * connect=false comes only from DEFINE_PROP_CHR_NO_CONNECT,
> + * through do_set_chr, which provides chardev ptr.
> + */
> + assert(connect);
>
Is this useful to assert?
> }
>
> c->fe_is_open = false;
> @@ -218,6 +235,11 @@ bool qemu_chr_fe_init(CharFrontend *c, Chardev *s,
> Error **errp)
> return true;
> }
>
> +bool qemu_chr_fe_init(CharFrontend *c, Chardev *s, Error **errp)
> +{
> + return qemu_chr_fe_init_ex(c, s, true, errp);
> +}
> +
> void qemu_chr_fe_deinit(CharFrontend *c, bool del)
> {
> assert(c);
> diff --git a/hw/core/qdev-properties-system.c
> b/hw/core/qdev-properties-system.c
> index 13cc91680b..00f4b19238 100644
> --- a/hw/core/qdev-properties-system.c
> +++ b/hw/core/qdev-properties-system.c
> @@ -266,8 +266,8 @@ static void get_chr(Object *obj, Visitor *v, const
> char *name, void *opaque,
> g_free(p);
> }
>
> -static void set_chr(Object *obj, Visitor *v, const char *name, void
> *opaque,
> - Error **errp)
> +static void do_set_chr(Object *obj, Visitor *v, const char *name, void
> *opaque,
> + bool connect, Error **errp)
> {
> ERRP_GUARD();
> const Property *prop = opaque;
> @@ -297,13 +297,25 @@ static void set_chr(Object *obj, Visitor *v, const
> char *name, void *opaque,
> if (s == NULL) {
> error_setg(errp, "Property '%s.%s' can't find value '%s'",
> object_get_typename(obj), name, str);
> - } else if (!qemu_chr_fe_init(fe, s, errp)) {
> + } else if (!qemu_chr_fe_init_ex(fe, s, connect, errp)) {
> error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
> object_get_typename(obj), name, str);
> }
> g_free(str);
> }
>
> +static void set_chr(Object *obj, Visitor *v, const char *name, void
> *opaque,
> + Error **errp)
> +{
> + do_set_chr(obj, v, name, opaque, true, errp);
> +}
> +
> +static void set_chr_no_connect(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + do_set_chr(obj, v, name, opaque, false, errp);
> +}
> +
> static void release_chr(Object *obj, const char *name, void *opaque)
> {
> const Property *prop = opaque;
> @@ -320,6 +332,14 @@ const PropertyInfo qdev_prop_chr = {
> .release = release_chr,
> };
>
> +const PropertyInfo qdev_prop_chr_no_connect = {
> + .type = "str",
> + .description = "ID of a chardev to use as a backend",
> + .get = get_chr,
> + .set = set_chr_no_connect,
> + .release = release_chr,
> +};
> +
> /* --- mac address --- */
>
> /*
> diff --git a/include/chardev/char-fe.h b/include/chardev/char-fe.h
> index 5f8a6df17d..f3df57afa1 100644
> --- a/include/chardev/char-fe.h
> +++ b/include/chardev/char-fe.h
> @@ -25,14 +25,18 @@ struct CharFrontend {
> };
>
> /**
> - * qemu_chr_fe_init:
> + * qemu_chr_fe_init(_ex):
> *
> * Initializes the frontend @c for the given Chardev backend @s. Call
> * qemu_chr_fe_deinit() to remove the association and release the backend.
> + * Call qemu_chr_connect(), except for the case when connect=false
> + * parameter set for _ex() version.
> *
> * Returns: false on error.
> */
> -bool qemu_chr_fe_init(CharFrontend *c, Chardev *be, Error **errp);
> +bool qemu_chr_fe_init(CharFrontend *c, Chardev *s, Error **errp);
> +bool qemu_chr_fe_init_ex(CharFrontend *c, Chardev *s, bool connect,
> + Error **errp);
>
> /**
> * qemu_chr_fe_deinit:
> diff --git a/include/hw/qdev-properties-system.h
> b/include/hw/qdev-properties-system.h
> index 5c6cc5eae8..a0b14a2f77 100644
> --- a/include/hw/qdev-properties-system.h
> +++ b/include/hw/qdev-properties-system.h
> @@ -7,6 +7,7 @@ bool qdev_prop_sanitize_s390x_loadparm(uint8_t *loadparm,
> const char *str,
> Error **errp);
>
> extern const PropertyInfo qdev_prop_chr;
> +extern const PropertyInfo qdev_prop_chr_no_connect;
> extern const PropertyInfo qdev_prop_macaddr;
> extern const PropertyInfo qdev_prop_reserved_region;
> extern const PropertyInfo qdev_prop_multifd_compression;
> @@ -39,6 +40,8 @@ extern const PropertyInfo
> qdev_prop_virtio_gpu_output_list;
>
> #define DEFINE_PROP_CHR(_n, _s, _f) \
> DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharFrontend)
> +#define DEFINE_PROP_CHR_NO_CONNECT(_n, _s, _f) \
> + DEFINE_PROP(_n, _s, _f, qdev_prop_chr_no_connect, CharFrontend)
> #define DEFINE_PROP_NETDEV(_n, _s, _f) \
> DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NICPeers)
> #define DEFINE_PROP_DRIVE(_n, _s, _f) \
> --
> 2.48.1
>
>
ok otherwise,
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
On 02.11.25 14:39, Marc-André Lureau wrote:
> Hi
>
> On Fri, Oct 31, 2025 at 7:59 PM Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru <mailto:vsementsov@yandex-team.ru>> wrote:
>
> For further vhost-user-blk backend-transfer migration realization we
> want to give it (vhost-user-blk) a possibility (and responsibility) to
> decide when do connect.
>
> For incoming migration we'll need to postpone connect at least until
> early stage of migrate-incoming command, when we already know all
> migration parameters and can decide, are we going to do incoming
> backend-transfer (and get chardev fd from incoming stream), or we
> finally need to connect.
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru <mailto:vsementsov@yandex-team.ru>>
> ---
> chardev/char-fe.c | 32 ++++++++++++++++++++++++-----
> hw/core/qdev-properties-system.c | 26 ++++++++++++++++++++---
> include/chardev/char-fe.h | 8 ++++++--
> include/hw/qdev-properties-system.h | 3 +++
> 4 files changed, 59 insertions(+), 10 deletions(-)
>
> diff --git a/chardev/char-fe.c b/chardev/char-fe.c
> index c67b4d640f..1132ec0501 100644
> --- a/chardev/char-fe.c
> +++ b/chardev/char-fe.c
> @@ -189,15 +189,26 @@ bool qemu_chr_fe_backend_open(CharFrontend *c)
> return c->chr && c->chr->be_open;
> }
>
> -bool qemu_chr_fe_init(CharFrontend *c, Chardev *s, Error **errp)
> +bool qemu_chr_fe_init_ex(CharFrontend *c, Chardev *s, bool connect,
> + Error **errp)
> {
> unsigned int tag = 0;
>
> - if (!qemu_chr_connect(s, errp)) {
> - return false;
> - }
> -
> if (s) {
> + if (connect) {
> + if (!qemu_chr_connect(s, errp)) {
> + return false;
> + }
> + } else {
> + /* DEFINE_PROP_CHR_NO_CONNECT */
> + if (!s->connect_postponed) {
> + error_setg(errp,
> + "Chardev %s does not support postponed connect",
> + s->label);
> + return false;
> + }
> + }
> +
> if (CHARDEV_IS_MUX(s)) {
> MuxChardev *d = MUX_CHARDEV(s);
>
> @@ -210,6 +221,12 @@ bool qemu_chr_fe_init(CharFrontend *c, Chardev *s, Error **errp)
> } else {
> s->fe = c;
> }
> + } else {
> + /*
> + * connect=false comes only from DEFINE_PROP_CHR_NO_CONNECT,
> + * through do_set_chr, which provides chardev ptr.
> + */
> + assert(connect);
>
>
> Is this useful to assert?
Hmm. I started to write "yes, because, if in future we introduce code path, which will
somehow pass s=NULL and connect=false, we'll do a wrong thing.."
But looking more closely at semantics of s=0, looks like connect could be just ignored:
no backend, nothing to connect.. So connect=true with s=0 looks maybe more wrong
than connect=false.
I'll drop the assertion, and add not into qemu_chr_fe_init_ex(), that @connect is ignored
for s=NULL case.
--
Best regards,
Vladimir
© 2016 - 2025 Red Hat, Inc.