* [PATCH v2 00/24] migration: Unify capabilities and parameters
@ 2025-06-30 19:58 Fabiano Rosas
2025-06-30 19:58 ` [PATCH v2 01/24] migration: Fix leak of block_bitmap_mapping Fabiano Rosas
` (23 more replies)
0 siblings, 24 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:58 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
Merge migration capabilities and parameters in MigrationState and
deprecate migration capabilities QMP commands.
v2:
- TLS options:
- Normalize to "abc"|"" during parameter handling.
- Normalize to "abc"|NULL when exposing to rest of migration
code.
- Reverted block_bitmap_mapping to truly optional in
query-migrate-parameters. It's an API break to make it
non-optional. Fortunately it doesn't get in the way of the rest of
the series.
- Haven't made s->parameters a pointer. It breaks qdev properties,
which need to use offsetof.
CI run: https://gitlab.com/farosas/qemu/-/pipelines/1898505234
v1:
https://lore.kernel.org/r/20250603013810.4772-1-farosas@suse.de
RFC:
https://lore.kernel.org/r/20250411191443.22565-1-farosas@suse.de
Fabiano Rosas (24):
migration: Fix leak of block_bitmap_mapping
migration: Add a qdev property for StrOrNull
migration: Normalize tls arguments
migration: Remove MigrateSetParameters
qapi/migration: Don't document MigrationParameter
migration: Run a post update routine after setting parameters
migration: Add a flag to track block-bitmap-mapping input
migration: Remove checks for s->parameters has_* fields
migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE
migration: Extract code to mark all parameters as present
migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters
migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply
migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply
migration: Use visitors in migrate_params_test_apply
migration: Cleanup hmp_info_migrate_parameters
migration: Add capabilities into MigrationParameters
migration: Remove s->capabilities
qapi/migration: Deprecate capabilities commands
migration: Store the initial values used for s->parameters
migration: Allow migrate commands to provide the migration config
tests/qtest/migration: Take reference when passing %p to qtest_qmp
tests/qtest/migration: Adapt the capabilities helper to take a config
tests/qtest/migration: Adapt convergence routines to config
tests/qtest/migration: Pass the migration config to file tests
docs/about/deprecated.rst | 12 +
migration/migration-hmp-cmds.c | 490 ++++++++---
migration/migration.c | 49 +-
migration/migration.h | 14 +-
migration/options.c | 1154 ++++++++++++-------------
migration/options.h | 30 +-
migration/page_cache.c | 6 +-
migration/ram.c | 5 +-
migration/savevm.c | 8 +-
migration/tls.c | 2 +-
qapi/migration.json | 558 ++++--------
qapi/pragma.json | 1 +
system/vl.c | 3 +-
tests/qtest/migration/file-tests.c | 68 +-
tests/qtest/migration/framework.c | 50 +-
tests/qtest/migration/framework.h | 1 +
tests/qtest/migration/migration-qmp.c | 30 +-
tests/qtest/migration/migration-qmp.h | 4 +-
tests/qtest/migration/misc-tests.c | 4 +-
tests/qtest/migration/precopy-tests.c | 23 +-
20 files changed, 1315 insertions(+), 1197 deletions(-)
--
2.35.3
^ permalink raw reply [flat|nested] 73+ messages in thread
* [PATCH v2 01/24] migration: Fix leak of block_bitmap_mapping
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
@ 2025-06-30 19:58 ` Fabiano Rosas
2025-07-01 6:12 ` Markus Armbruster
2025-06-30 19:58 ` [PATCH v2 02/24] migration: Add a qdev property for StrOrNull Fabiano Rosas
` (22 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:58 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
Caught by inspection, but ASAN also reports:
Direct leak of 16 byte(s) in 1 object(s) allocated from:
#0 in malloc
#1 in g_malloc
#2 in g_memdup
#3 in qapi_clone_start_struct ../qapi/qapi-clone-visitor.c:40:12
#4 in qapi_clone_start_list ../qapi/qapi-clone-visitor.c:59:12
#5 in visit_start_list ../qapi/qapi-visit-core.c:80:10
#6 in visit_type_BitmapMigrationNodeAliasList qapi/qapi-visit-migration.c:639:10
#7 in migrate_params_apply ../migration/options.c:1407:13
#8 in qmp_migrate_set_parameters ../migration/options.c:1463:5
#9 in qmp_marshal_migrate_set_parameters qapi/qapi-commands-migration.c:214:5
#10 in do_qmp_dispatch_bh ../qapi/qmp-dispatch.c:128:5
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/migration/migration.c b/migration/migration.c
index 4098870bce..7ec60d97f9 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -4050,6 +4050,7 @@ static void migration_instance_finalize(Object *obj)
{
MigrationState *ms = MIGRATION_OBJ(obj);
+ qapi_free_BitmapMigrationNodeAliasList(ms->parameters.block_bitmap_mapping);
qemu_mutex_destroy(&ms->error_mutex);
qemu_mutex_destroy(&ms->qemu_file_lock);
qemu_sem_destroy(&ms->wait_unplug_sem);
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 02/24] migration: Add a qdev property for StrOrNull
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
2025-06-30 19:58 ` [PATCH v2 01/24] migration: Fix leak of block_bitmap_mapping Fabiano Rosas
@ 2025-06-30 19:58 ` Fabiano Rosas
2025-07-01 6:38 ` Markus Armbruster
2025-06-30 19:58 ` [PATCH v2 03/24] migration: Normalize tls arguments Fabiano Rosas
` (21 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:58 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
The MigrationState is a QOM object with TYPE_DEVICE as a parent. This
was done about eight years ago so the migration code could make use of
qdev properties to define the defaults for the migration parameters
and to be able to expose migration knobs for debugging via the
'-global migration' command line option.
Due to unrelated historical reasons, three of the migration parameters
(TLS options) received different types when used via the
query-migrate-parameters QMP command than with the
migrate-set-parameters command. This has created a lot of duplication
in the migration code and in the QAPI documentation because the whole
of MigrationParameters had to be duplicated as well.
The migration code is now being fixed to remove the duplication and
for that to happen the offending fields need to be reconciled into a
single type. The StrOrNull type is going to be used.
To keep the command line compatibility, the parameters need to
continue being exposed via qdev properties accessible from the command
line. Introduce a qdev property StrOrNull just for that.
Note that this code is being kept in migration/options.c because this
version of StrOrNull doesn't need to handle QNULL because it was never
a valid option in the previous command line, which took a string.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/options.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/migration/options.c b/migration/options.c
index 162c72cda4..384ef9e421 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -83,6 +83,11 @@
#define DEFINE_PROP_MIG_CAP(name, x) \
DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)
+const PropertyInfo qdev_prop_StrOrNull;
+#define DEFINE_PROP_STR_OR_NULL(_name, _state, _field) \
+ DEFINE_PROP(_name, _state, _field, qdev_prop_StrOrNull, StrOrNull *, \
+ .set_default = true)
+
#define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD 1000 /* milliseconds */
#define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT 1 /* MB/s */
@@ -204,6 +209,48 @@ const Property migration_properties[] = {
};
const size_t migration_properties_count = ARRAY_SIZE(migration_properties);
+/*
+ * qdev property for TLS options handling via '-global migration'
+ * command line.
+ */
+static void set_StrOrNull(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ const Property *prop = opaque;
+ StrOrNull **ptr = object_field_prop_ptr(obj, prop);
+ StrOrNull *str_or_null = g_new0(StrOrNull, 1);
+
+ /*
+ * Only str to keep compatibility, QNULL was never used via
+ * command line.
+ */
+ str_or_null->type = QTYPE_QSTRING;
+ if (!visit_type_str(v, name, &str_or_null->u.s, errp)) {
+ return;
+ }
+
+ qapi_free_StrOrNull(*ptr);
+ *ptr = str_or_null;
+}
+
+static void release_StrOrNull(Object *obj, const char *name, void *opaque)
+{
+ const Property *prop = opaque;
+ qapi_free_StrOrNull(*(StrOrNull **)object_field_prop_ptr(obj, prop));
+}
+
+static void set_default_value_tls_opt(ObjectProperty *op, const Property *prop)
+{
+ object_property_set_default_str(op, "");
+}
+
+const PropertyInfo qdev_prop_StrOrNull = {
+ .type = "StrOrNull",
+ .set = set_StrOrNull,
+ .release = release_StrOrNull,
+ .set_default_value = set_default_value_tls_opt,
+};
+
bool migrate_auto_converge(void)
{
MigrationState *s = migrate_get_current();
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 03/24] migration: Normalize tls arguments
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
2025-06-30 19:58 ` [PATCH v2 01/24] migration: Fix leak of block_bitmap_mapping Fabiano Rosas
2025-06-30 19:58 ` [PATCH v2 02/24] migration: Add a qdev property for StrOrNull Fabiano Rosas
@ 2025-06-30 19:58 ` Fabiano Rosas
2025-07-01 7:46 ` Markus Armbruster
2025-06-30 19:58 ` [PATCH v2 04/24] migration: Remove MigrateSetParameters Fabiano Rosas
` (20 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:58 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Eric Blake
The migration parameters tls_creds, tls_authz and tls_hostname
currently have a non-uniform handling. When used as arguments to
migrate-set-parameters, their type is StrOrNull and when used as
return value from query-migrate-parameters their type is a plain
string.
Not only having to convert between the types is cumbersome, but it
also creates the issue of requiring two different QAPI types to be
used, one for each command. MigrateSetParameters is used for
migrate-set-parameters with the TLS arguments as StrOrNull while
MigrationParameters is used for query-migrate-parameters with the TLS
arguments as str.
Since StrOrNull could be considered a superset of str, change the type
of the TLS arguments in MigrationParameters to StrOrNull. Also ensure
that QTYPE_QNULL is never used.
1) migrate-set-parameters will always write QTYPE_QSTRING to
s->parameters, either an empty or non-empty string.
2) query-migrate-parameters will always return a QTYPE_QSTRING, either
empty or non-empty.
3) the migrate_tls_* helpers will always return a non-empty string or
NULL, for the internal migration code's consumption.
Points (1) and (2) above help simplify the parameters validation and
the query command handling because s->parameters is already kept in
the format that query-migrate-parameters (and info migrate_paramters)
expect. Point (3) is so people don't need to care about StrOrNull in
migration code.
This will allow the type duplication to be removed in the next
patches.
Note that the type of @tls_creds, @tls-hostname, @tls-authz changes
from str to StrOrNull in introspection of the query-migrate-parameters
command. We accept this imprecision to enable de-duplication.
There's no need to free the TLS options in
migration_instance_finalize() because they're freed by the qdev
properties .release method.
Temporary in this patch:
migrate_params_test_apply() copies s->parameters into a temporary
structure, so it's necessary to drop the references to the TLS options
if they were not set by the user to avoid double-free. This is fixed
in the next patches.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration-hmp-cmds.c | 7 +-
migration/options.c | 156 ++++++++++++++++++++-------------
migration/options.h | 1 +
migration/tls.c | 2 +-
qapi/migration.json | 6 +-
5 files changed, 106 insertions(+), 66 deletions(-)
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index e8a563c7d8..547384edb5 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -279,11 +279,11 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
assert(params->tls_creds);
monitor_printf(mon, "%s: '%s'\n",
MigrationParameter_str(MIGRATION_PARAMETER_TLS_CREDS),
- params->tls_creds);
+ params->tls_creds->u.s);
assert(params->tls_hostname);
monitor_printf(mon, "%s: '%s'\n",
MigrationParameter_str(MIGRATION_PARAMETER_TLS_HOSTNAME),
- params->tls_hostname);
+ params->tls_hostname->u.s);
assert(params->has_max_bandwidth);
monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n",
MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH),
@@ -317,9 +317,10 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "%s: %" PRIu64 "\n",
MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH),
params->max_postcopy_bandwidth);
+ assert(params->tls_authz);
monitor_printf(mon, "%s: '%s'\n",
MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ),
- params->tls_authz);
+ params->tls_authz->u.s);
if (params->has_block_bitmap_mapping) {
const BitmapMigrationNodeAliasList *bmnal;
diff --git a/migration/options.c b/migration/options.c
index 384ef9e421..f7bbdba5fc 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -167,9 +167,10 @@ const Property migration_properties[] = {
DEFINE_PROP_SIZE("announce-step", MigrationState,
parameters.announce_step,
DEFAULT_MIGRATE_ANNOUNCE_STEP),
- DEFINE_PROP_STRING("tls-creds", MigrationState, parameters.tls_creds),
- DEFINE_PROP_STRING("tls-hostname", MigrationState, parameters.tls_hostname),
- DEFINE_PROP_STRING("tls-authz", MigrationState, parameters.tls_authz),
+ DEFINE_PROP_STR_OR_NULL("tls-creds", MigrationState, parameters.tls_creds),
+ DEFINE_PROP_STR_OR_NULL("tls-hostname", MigrationState,
+ parameters.tls_hostname),
+ DEFINE_PROP_STR_OR_NULL("tls-authz", MigrationState, parameters.tls_authz),
DEFINE_PROP_UINT64("x-vcpu-dirty-limit-period", MigrationState,
parameters.x_vcpu_dirty_limit_period,
DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD),
@@ -241,6 +242,11 @@ static void release_StrOrNull(Object *obj, const char *name, void *opaque)
static void set_default_value_tls_opt(ObjectProperty *op, const Property *prop)
{
+ /*
+ * Initialization to the empty string here is important so
+ * query-migrate-parameters doesn't need to deal with a NULL value
+ * when it's called before any TLS option has been set.
+ */
object_property_set_default_str(op, "");
}
@@ -426,13 +432,6 @@ bool migrate_rdma(void)
return s->rdma_migration;
}
-bool migrate_tls(void)
-{
- MigrationState *s = migrate_get_current();
-
- return s->parameters.tls_creds && *s->parameters.tls_creds;
-}
-
typedef enum WriteTrackingSupport {
WT_SUPPORT_UNKNOWN = 0,
WT_SUPPORT_ABSENT,
@@ -881,21 +880,38 @@ const char *migrate_tls_authz(void)
{
MigrationState *s = migrate_get_current();
- return s->parameters.tls_authz;
+ if (*s->parameters.tls_authz->u.s) {
+ return s->parameters.tls_authz->u.s;
+ }
+
+ return NULL;
}
const char *migrate_tls_creds(void)
{
MigrationState *s = migrate_get_current();
- return s->parameters.tls_creds;
+ if (*s->parameters.tls_creds->u.s) {
+ return s->parameters.tls_creds->u.s;
+ }
+
+ return NULL;
}
const char *migrate_tls_hostname(void)
{
MigrationState *s = migrate_get_current();
- return s->parameters.tls_hostname;
+ if (*s->parameters.tls_hostname->u.s) {
+ return s->parameters.tls_hostname->u.s;
+ }
+
+ return NULL;
+}
+
+bool migrate_tls(void)
+{
+ return !!migrate_tls_creds();
}
uint64_t migrate_vcpu_dirty_limit_period(void)
@@ -935,6 +951,37 @@ AnnounceParameters *migrate_announce_params(void)
return ≈
}
+void migrate_tls_opts_free(MigrationParameters *params)
+{
+ qapi_free_StrOrNull(params->tls_creds);
+ qapi_free_StrOrNull(params->tls_hostname);
+ qapi_free_StrOrNull(params->tls_authz);
+}
+
+/* either non-empty or empty string */
+static void tls_opt_to_str(StrOrNull **tls_opt)
+{
+ StrOrNull *opt = *tls_opt;
+
+ if (!opt) {
+ return;
+ }
+
+ switch (opt->type) {
+ case QTYPE_QSTRING:
+ return;
+ case QTYPE_QNULL:
+ qobject_unref(opt->u.n);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ opt->type = QTYPE_QSTRING;
+ opt->u.s = g_strdup("");
+ *tls_opt = opt;
+}
+
MigrationParameters *qmp_query_migrate_parameters(Error **errp)
{
MigrationParameters *params;
@@ -950,10 +997,9 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
params->has_cpu_throttle_tailslow = true;
params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow;
- params->tls_creds = g_strdup(s->parameters.tls_creds);
- params->tls_hostname = g_strdup(s->parameters.tls_hostname);
- params->tls_authz = g_strdup(s->parameters.tls_authz ?
- s->parameters.tls_authz : "");
+ params->tls_creds = QAPI_CLONE(StrOrNull, s->parameters.tls_creds);
+ params->tls_hostname = QAPI_CLONE(StrOrNull, s->parameters.tls_hostname);
+ params->tls_authz = QAPI_CLONE(StrOrNull, s->parameters.tls_authz);
params->has_max_bandwidth = true;
params->max_bandwidth = s->parameters.max_bandwidth;
params->has_avail_switchover_bandwidth = true;
@@ -1010,9 +1056,6 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
void migrate_params_init(MigrationParameters *params)
{
- params->tls_hostname = g_strdup("");
- params->tls_creds = g_strdup("");
-
/* Set has_* up only for parameter checks */
params->has_throttle_trigger_threshold = true;
params->has_cpu_throttle_initial = true;
@@ -1189,7 +1232,7 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
#ifdef CONFIG_LINUX
if (migrate_zero_copy_send() &&
((params->has_multifd_compression && params->multifd_compression) ||
- (params->tls_creds && *params->tls_creds))) {
+ *params->tls_creds->u.s)) {
error_setg(errp,
"Zero copy only available for non-compressed non-TLS multifd migration");
return false;
@@ -1251,18 +1294,24 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
}
if (params->tls_creds) {
- assert(params->tls_creds->type == QTYPE_QSTRING);
- dest->tls_creds = params->tls_creds->u.s;
+ dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
+ } else {
+ /* drop the reference, it's owned by s->parameters */
+ dest->tls_creds = NULL;
}
if (params->tls_hostname) {
- assert(params->tls_hostname->type == QTYPE_QSTRING);
- dest->tls_hostname = params->tls_hostname->u.s;
+ dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
+ } else {
+ /* drop the reference, it's owned by s->parameters */
+ dest->tls_hostname = NULL;
}
if (params->tls_authz) {
- assert(params->tls_authz->type == QTYPE_QSTRING);
- dest->tls_authz = params->tls_authz->u.s;
+ dest->tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
+ } else {
+ /* drop the reference, it's owned by s->parameters */
+ dest->tls_authz = NULL;
}
if (params->has_max_bandwidth) {
@@ -1367,21 +1416,19 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
}
if (params->tls_creds) {
- g_free(s->parameters.tls_creds);
- assert(params->tls_creds->type == QTYPE_QSTRING);
- s->parameters.tls_creds = g_strdup(params->tls_creds->u.s);
+ qapi_free_StrOrNull(s->parameters.tls_creds);
+ s->parameters.tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
}
if (params->tls_hostname) {
- g_free(s->parameters.tls_hostname);
- assert(params->tls_hostname->type == QTYPE_QSTRING);
- s->parameters.tls_hostname = g_strdup(params->tls_hostname->u.s);
+ qapi_free_StrOrNull(s->parameters.tls_hostname);
+ s->parameters.tls_hostname = QAPI_CLONE(StrOrNull,
+ params->tls_hostname);
}
if (params->tls_authz) {
- g_free(s->parameters.tls_authz);
- assert(params->tls_authz->type == QTYPE_QSTRING);
- s->parameters.tls_authz = g_strdup(params->tls_authz->u.s);
+ qapi_free_StrOrNull(s->parameters.tls_authz);
+ s->parameters.tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
}
if (params->has_max_bandwidth) {
@@ -1480,32 +1527,23 @@ void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
{
MigrationParameters tmp;
- /* TODO Rewrite "" to null instead for all three tls_* parameters */
- if (params->tls_creds
- && params->tls_creds->type == QTYPE_QNULL) {
- qobject_unref(params->tls_creds->u.n);
- params->tls_creds->type = QTYPE_QSTRING;
- params->tls_creds->u.s = strdup("");
- }
- if (params->tls_hostname
- && params->tls_hostname->type == QTYPE_QNULL) {
- qobject_unref(params->tls_hostname->u.n);
- params->tls_hostname->type = QTYPE_QSTRING;
- params->tls_hostname->u.s = strdup("");
- }
- if (params->tls_authz
- && params->tls_authz->type == QTYPE_QNULL) {
- qobject_unref(params->tls_authz->u.n);
- params->tls_authz->type = QTYPE_QSTRING;
- params->tls_authz->u.s = strdup("");
- }
+ /*
+ * Convert QTYPE_QNULL and NULL to the empty string (""). Even
+ * though NULL is cleaner to deal with in C code, that would force
+ * query-migrate-parameters to convert it once more to the empty
+ * string, so avoid that. The migrate_tls_*() helpers that expose
+ * the options to the rest of the migration code already use
+ * return NULL when the empty string is found.
+ */
+ tls_opt_to_str(¶ms->tls_creds);
+ tls_opt_to_str(¶ms->tls_hostname);
+ tls_opt_to_str(¶ms->tls_authz);
migrate_params_test_apply(params, &tmp);
- if (!migrate_params_check(&tmp, errp)) {
- /* Invalid parameter */
- return;
+ if (migrate_params_check(&tmp, errp)) {
+ migrate_params_apply(params, errp);
}
- migrate_params_apply(params, errp);
+ migrate_tls_opts_free(&tmp);
}
diff --git a/migration/options.h b/migration/options.h
index 82d839709e..999eee6f3b 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -91,4 +91,5 @@ ZeroPageDetection migrate_zero_page_detection(void);
bool migrate_params_check(MigrationParameters *params, Error **errp);
void migrate_params_init(MigrationParameters *params);
+void migrate_tls_opts_free(MigrationParameters *params);
#endif
diff --git a/migration/tls.c b/migration/tls.c
index 5cbf952383..8a89d3f767 100644
--- a/migration/tls.c
+++ b/migration/tls.c
@@ -126,7 +126,7 @@ QIOChannelTLS *migration_tls_client_create(QIOChannel *ioc,
}
const char *tls_hostname = migrate_tls_hostname();
- if (tls_hostname && *tls_hostname) {
+ if (tls_hostname) {
hostname = tls_hostname;
}
diff --git a/qapi/migration.json b/qapi/migration.json
index 4963f6ca12..97bb022c45 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1293,9 +1293,9 @@
'*cpu-throttle-initial': 'uint8',
'*cpu-throttle-increment': 'uint8',
'*cpu-throttle-tailslow': 'bool',
- '*tls-creds': 'str',
- '*tls-hostname': 'str',
- '*tls-authz': 'str',
+ '*tls-creds': 'StrOrNull',
+ '*tls-hostname': 'StrOrNull',
+ '*tls-authz': 'StrOrNull',
'*max-bandwidth': 'size',
'*avail-switchover-bandwidth': 'size',
'*downtime-limit': 'uint64',
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 04/24] migration: Remove MigrateSetParameters
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (2 preceding siblings ...)
2025-06-30 19:58 ` [PATCH v2 03/24] migration: Normalize tls arguments Fabiano Rosas
@ 2025-06-30 19:58 ` Fabiano Rosas
2025-07-01 8:00 ` Markus Armbruster
2025-07-04 15:39 ` Peter Xu
2025-06-30 19:58 ` [PATCH v2 05/24] qapi/migration: Don't document MigrationParameter Fabiano Rosas
` (19 subsequent siblings)
23 siblings, 2 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:58 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Eric Blake
Now that the TLS options have been made the same between
migrate-set-parameters and query-migrate-parameters, a single type can
be used. Remove MigrateSetParameters.
The TLS options documentation from MigrationParameters were replaced
with the ones from MigrateSetParameters which was more complete.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration-hmp-cmds.c | 4 +-
migration/options.c | 6 +-
qapi/migration.json | 232 +++------------------------------
3 files changed, 24 insertions(+), 218 deletions(-)
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 547384edb5..82cd2dcb8e 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -493,7 +493,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
const char *param = qdict_get_str(qdict, "parameter");
const char *valuestr = qdict_get_str(qdict, "value");
Visitor *v = string_input_visitor_new(valuestr);
- MigrateSetParameters *p = g_new0(MigrateSetParameters, 1);
+ MigrationParameters *p = g_new0(MigrationParameters, 1);
uint64_t valuebw = 0;
uint64_t cache_size;
Error *err = NULL;
@@ -659,7 +659,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
qmp_migrate_set_parameters(p, &err);
cleanup:
- qapi_free_MigrateSetParameters(p);
+ qapi_free_MigrationParameters(p);
visit_free(v);
hmp_handle_error(mon, err);
}
diff --git a/migration/options.c b/migration/options.c
index f7bbdba5fc..295367ce92 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1270,7 +1270,7 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
return true;
}
-static void migrate_params_test_apply(MigrateSetParameters *params,
+static void migrate_params_test_apply(MigrationParameters *params,
MigrationParameters *dest)
{
*dest = migrate_get_current()->parameters;
@@ -1393,7 +1393,7 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
}
}
-static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
+static void migrate_params_apply(MigrationParameters *params, Error **errp)
{
MigrationState *s = migrate_get_current();
@@ -1523,7 +1523,7 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
}
}
-void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
+void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
{
MigrationParameters tmp;
diff --git a/qapi/migration.json b/qapi/migration.json
index 97bb022c45..3788c39857 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -914,206 +914,10 @@
'zero-page-detection',
'direct-io'] }
-##
-# @MigrateSetParameters:
-#
-# @announce-initial: Initial delay (in milliseconds) before sending
-# the first announce (Since 4.0)
-#
-# @announce-max: Maximum delay (in milliseconds) between packets in
-# the announcement (Since 4.0)
-#
-# @announce-rounds: Number of self-announce packets sent after
-# migration (Since 4.0)
-#
-# @announce-step: Increase in delay (in milliseconds) between
-# subsequent packets in the announcement (Since 4.0)
-#
-# @throttle-trigger-threshold: The ratio of bytes_dirty_period and
-# bytes_xfer_period to trigger throttling. It is expressed as
-# percentage. The default value is 50. (Since 5.0)
-#
-# @cpu-throttle-initial: Initial percentage of time guest cpus are
-# throttled when migration auto-converge is activated. The
-# default value is 20. (Since 2.7)
-#
-# @cpu-throttle-increment: throttle percentage increase each time
-# auto-converge detects that migration is not making progress.
-# The default value is 10. (Since 2.7)
-#
-# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage.
-# At the tail stage of throttling, the Guest is very sensitive to
-# CPU percentage while the @cpu-throttle -increment is excessive
-# usually at tail stage. If this parameter is true, we will
-# compute the ideal CPU percentage used by the Guest, which may
-# exactly make the dirty rate match the dirty rate threshold.
-# Then we will choose a smaller throttle increment between the one
-# specified by @cpu-throttle-increment and the one generated by
-# ideal CPU percentage. Therefore, it is compatible to
-# traditional throttling, meanwhile the throttle increment won't
-# be excessive at tail stage. The default value is false.
-# (Since 5.1)
-#
-# @tls-creds: ID of the 'tls-creds' object that provides credentials
-# for establishing a TLS connection over the migration data
-# channel. On the outgoing side of the migration, the credentials
-# must be for a 'client' endpoint, while for the incoming side the
-# credentials must be for a 'server' endpoint. Setting this to a
-# non-empty string enables TLS for all migrations. An empty
-# string means that QEMU will use plain text mode for migration,
-# rather than TLS. This is the default. (Since 2.7)
-#
-# @tls-hostname: migration target's hostname for validating the
-# server's x509 certificate identity. If empty, QEMU will use the
-# hostname from the migration URI, if any. A non-empty value is
-# required when using x509 based TLS credentials and the migration
-# URI does not include a hostname, such as fd: or exec: based
-# migration. (Since 2.7)
-#
-# Note: empty value works only since 2.9.
-#
-# @tls-authz: ID of the 'authz' object subclass that provides access
-# control checking of the TLS x509 certificate distinguished name.
-# This object is only resolved at time of use, so can be deleted
-# and recreated on the fly while the migration server is active.
-# If missing, it will default to denying access (Since 4.0)
-#
-# @max-bandwidth: maximum speed for migration, in bytes per second.
-# (Since 2.8)
-#
-# @avail-switchover-bandwidth: to set the available bandwidth that
-# migration can use during switchover phase. **Note:** this does
-# not limit the bandwidth during switchover, but only for
-# calculations when making decisions to switchover. By default,
-# this value is zero, which means QEMU will estimate the bandwidth
-# automatically. This can be set when the estimated value is not
-# accurate, while the user is able to guarantee such bandwidth is
-# available when switching over. When specified correctly, this
-# can make the switchover decision much more accurate.
-# (Since 8.2)
-#
-# @downtime-limit: set maximum tolerated downtime for migration.
-# maximum downtime in milliseconds (Since 2.8)
-#
-# @x-checkpoint-delay: The delay time (in ms) between two COLO
-# checkpoints in periodic mode. (Since 2.8)
-#
-# @multifd-channels: Number of channels used to migrate data in
-# parallel. This is the same number that the number of sockets
-# used for migration. The default value is 2 (since 4.0)
-#
-# @xbzrle-cache-size: cache size to be used by XBZRLE migration. It
-# needs to be a multiple of the target page size and a power of 2
-# (Since 2.11)
-#
-# @max-postcopy-bandwidth: Background transfer bandwidth during
-# postcopy. Defaults to 0 (unlimited). In bytes per second.
-# (Since 3.0)
-#
-# @max-cpu-throttle: maximum cpu throttle percentage. Defaults to 99.
-# (Since 3.1)
-#
-# @multifd-compression: Which compression method to use. Defaults to
-# none. (Since 5.0)
-#
-# @multifd-zlib-level: Set the compression level to be used in live
-# migration, the compression level is an integer between 0 and 9,
-# where 0 means no compression, 1 means the best compression
-# speed, and 9 means best compression ratio which will consume
-# more CPU. Defaults to 1. (Since 5.0)
-#
-# @multifd-qatzip-level: Set the compression level to be used in live
-# migration. The level is an integer between 1 and 9, where 1 means
-# the best compression speed, and 9 means the best compression
-# ratio which will consume more CPU. Defaults to 1. (Since 9.2)
-#
-# @multifd-zstd-level: Set the compression level to be used in live
-# migration, the compression level is an integer between 0 and 20,
-# where 0 means no compression, 1 means the best compression
-# speed, and 20 means best compression ratio which will consume
-# more CPU. Defaults to 1. (Since 5.0)
-#
-# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
-# aliases for the purpose of dirty bitmap migration. Such aliases
-# may for example be the corresponding names on the opposite site.
-# The mapping must be one-to-one, but not necessarily complete: On
-# the source, unmapped bitmaps and all bitmaps on unmapped nodes
-# will be ignored. On the destination, encountering an unmapped
-# alias in the incoming migration stream will result in a report,
-# and all further bitmap migration data will then be discarded.
-# Note that the destination does not know about bitmaps it does
-# not receive, so there is no limitation or requirement regarding
-# the number of bitmaps received, or how they are named, or on
-# which nodes they are placed. By default (when this parameter
-# has never been set), bitmap names are mapped to themselves.
-# Nodes are mapped to their block device name if there is one, and
-# to their node name otherwise. (Since 5.2)
-#
-# @x-vcpu-dirty-limit-period: Periodic time (in milliseconds) of dirty
-# limit during live migration. Should be in the range 1 to
-# 1000ms. Defaults to 1000ms. (Since 8.1)
-#
-# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
-# Defaults to 1. (Since 8.1)
-#
-# @mode: Migration mode. See description in @MigMode. Default is
-# 'normal'. (Since 8.2)
-#
-# @zero-page-detection: Whether and how to detect zero pages.
-# See description in @ZeroPageDetection. Default is 'multifd'.
-# (since 9.0)
-#
-# @direct-io: Open migration files with O_DIRECT when possible. This
-# only has effect if the @mapped-ram capability is enabled.
-# (Since 9.1)
-#
-# Features:
-#
-# @unstable: Members @x-checkpoint-delay and
-# @x-vcpu-dirty-limit-period are experimental.
-#
-# TODO: either fuse back into MigrationParameters, or make
-# MigrationParameters members mandatory
-#
-# Since: 2.4
-##
-{ 'struct': 'MigrateSetParameters',
- 'data': { '*announce-initial': 'size',
- '*announce-max': 'size',
- '*announce-rounds': 'size',
- '*announce-step': 'size',
- '*throttle-trigger-threshold': 'uint8',
- '*cpu-throttle-initial': 'uint8',
- '*cpu-throttle-increment': 'uint8',
- '*cpu-throttle-tailslow': 'bool',
- '*tls-creds': 'StrOrNull',
- '*tls-hostname': 'StrOrNull',
- '*tls-authz': 'StrOrNull',
- '*max-bandwidth': 'size',
- '*avail-switchover-bandwidth': 'size',
- '*downtime-limit': 'uint64',
- '*x-checkpoint-delay': { 'type': 'uint32',
- 'features': [ 'unstable' ] },
- '*multifd-channels': 'uint8',
- '*xbzrle-cache-size': 'size',
- '*max-postcopy-bandwidth': 'size',
- '*max-cpu-throttle': 'uint8',
- '*multifd-compression': 'MultiFDCompression',
- '*multifd-zlib-level': 'uint8',
- '*multifd-qatzip-level': 'uint8',
- '*multifd-zstd-level': 'uint8',
- '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ],
- '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
- 'features': [ 'unstable' ] },
- '*vcpu-dirty-limit': 'uint64',
- '*mode': 'MigMode',
- '*zero-page-detection': 'ZeroPageDetection',
- '*direct-io': 'bool' } }
-
##
# @migrate-set-parameters:
#
-# Set various migration parameters.
+# Set migration parameters. All fields are optional.
#
# Since: 2.4
#
@@ -1124,13 +928,11 @@
# <- { "return": {} }
##
{ 'command': 'migrate-set-parameters', 'boxed': true,
- 'data': 'MigrateSetParameters' }
+ 'data': 'MigrationParameters' }
##
# @MigrationParameters:
#
-# The optional members aren't actually optional.
-#
# @announce-initial: Initial delay (in milliseconds) before sending
# the first announce (Since 4.0)
#
@@ -1148,12 +950,12 @@
# percentage. The default value is 50. (Since 5.0)
#
# @cpu-throttle-initial: Initial percentage of time guest cpus are
-# throttled when migration auto-converge is activated.
-# (Since 2.7)
+# throttled when migration auto-converge is activated. The
+# default value is 20. (Since 2.7)
#
# @cpu-throttle-increment: throttle percentage increase each time
# auto-converge detects that migration is not making progress.
-# (Since 2.7)
+# The default value is 10. (Since 2.7)
#
# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage.
# At the tail stage of throttling, the Guest is very sensitive to
@@ -1172,21 +974,25 @@
# for establishing a TLS connection over the migration data
# channel. On the outgoing side of the migration, the credentials
# must be for a 'client' endpoint, while for the incoming side the
-# credentials must be for a 'server' endpoint. An empty string
-# means that QEMU will use plain text mode for migration, rather
-# than TLS. (Since 2.7)
-#
-# Note: 2.8 omits empty @tls-creds instead.
+# credentials must be for a 'server' endpoint. Setting this to a
+# non-empty string enables TLS for all migrations. An empty
+# string means that QEMU will use plain text mode for migration,
+# rather than TLS. This is the default. (Since 2.7)
#
# @tls-hostname: migration target's hostname for validating the
# server's x509 certificate identity. If empty, QEMU will use the
-# hostname from the migration URI, if any. (Since 2.7)
+# hostname from the migration URI, if any. A non-empty value is
+# required when using x509 based TLS credentials and the migration
+# URI does not include a hostname, such as fd: or exec: based
+# migration. (Since 2.7)
#
-# Note: 2.8 omits empty @tls-hostname instead.
+# Note: empty value works only since 2.9.
#
# @tls-authz: ID of the 'authz' object subclass that provides access
# control checking of the TLS x509 certificate distinguished name.
-# (Since 4.0)
+# This object is only resolved at time of use, so can be deleted
+# and recreated on the fly while the migration server is active.
+# If missing, it will default to denying access (Since 4.0)
#
# @max-bandwidth: maximum speed for migration, in bytes per second.
# (Since 2.8)
@@ -1205,8 +1011,8 @@
# @downtime-limit: set maximum tolerated downtime for migration.
# maximum downtime in milliseconds (Since 2.8)
#
-# @x-checkpoint-delay: the delay time between two COLO checkpoints.
-# (Since 2.8)
+# @x-checkpoint-delay: the delay time between two COLO checkpoints in
+# periodic mode. (Since 2.8)
#
# @multifd-channels: Number of channels used to migrate data in
# parallel. This is the same number that the number of sockets
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 05/24] qapi/migration: Don't document MigrationParameter
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (3 preceding siblings ...)
2025-06-30 19:58 ` [PATCH v2 04/24] migration: Remove MigrateSetParameters Fabiano Rosas
@ 2025-06-30 19:58 ` Fabiano Rosas
2025-07-01 8:04 ` Markus Armbruster
2025-07-04 15:40 ` Peter Xu
2025-06-30 19:58 ` [PATCH v2 06/24] migration: Run a post update routine after setting parameters Fabiano Rosas
` (18 subsequent siblings)
23 siblings, 2 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:58 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Eric Blake
The MigrationParameter (singular) enumeration is not part of the
migration QMP API, it's only used for nicely converting HMP strings
into MigrationParameters (plural) members and for providing readline
completion.
Documenting this enum only serves to duplicate documentation between
MigrationParameter and MigrationParameters.
Add an exception to QAPIs pragma.json and stop documenting it.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
qapi/migration.json | 153 +-------------------------------------------
qapi/pragma.json | 1 +
2 files changed, 3 insertions(+), 151 deletions(-)
diff --git a/qapi/migration.json b/qapi/migration.json
index 3788c39857..40e00fb86e 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -734,157 +734,8 @@
##
# @MigrationParameter:
#
-# Migration parameters enumeration
-#
-# @announce-initial: Initial delay (in milliseconds) before sending
-# the first announce (Since 4.0)
-#
-# @announce-max: Maximum delay (in milliseconds) between packets in
-# the announcement (Since 4.0)
-#
-# @announce-rounds: Number of self-announce packets sent after
-# migration (Since 4.0)
-#
-# @announce-step: Increase in delay (in milliseconds) between
-# subsequent packets in the announcement (Since 4.0)
-#
-# @throttle-trigger-threshold: The ratio of bytes_dirty_period and
-# bytes_xfer_period to trigger throttling. It is expressed as
-# percentage. The default value is 50. (Since 5.0)
-#
-# @cpu-throttle-initial: Initial percentage of time guest cpus are
-# throttled when migration auto-converge is activated. The
-# default value is 20. (Since 2.7)
-#
-# @cpu-throttle-increment: throttle percentage increase each time
-# auto-converge detects that migration is not making progress.
-# The default value is 10. (Since 2.7)
-#
-# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage.
-# At the tail stage of throttling, the Guest is very sensitive to
-# CPU percentage while the @cpu-throttle -increment is excessive
-# usually at tail stage. If this parameter is true, we will
-# compute the ideal CPU percentage used by the Guest, which may
-# exactly make the dirty rate match the dirty rate threshold.
-# Then we will choose a smaller throttle increment between the one
-# specified by @cpu-throttle-increment and the one generated by
-# ideal CPU percentage. Therefore, it is compatible to
-# traditional throttling, meanwhile the throttle increment won't
-# be excessive at tail stage. The default value is false.
-# (Since 5.1)
-#
-# @tls-creds: ID of the 'tls-creds' object that provides credentials
-# for establishing a TLS connection over the migration data
-# channel. On the outgoing side of the migration, the credentials
-# must be for a 'client' endpoint, while for the incoming side the
-# credentials must be for a 'server' endpoint. Setting this to a
-# non-empty string enables TLS for all migrations. An empty
-# string means that QEMU will use plain text mode for migration,
-# rather than TLS. (Since 2.7)
-#
-# @tls-hostname: migration target's hostname for validating the
-# server's x509 certificate identity. If empty, QEMU will use the
-# hostname from the migration URI, if any. A non-empty value is
-# required when using x509 based TLS credentials and the migration
-# URI does not include a hostname, such as fd: or exec: based
-# migration. (Since 2.7)
-#
-# Note: empty value works only since 2.9.
-#
-# @tls-authz: ID of the 'authz' object subclass that provides access
-# control checking of the TLS x509 certificate distinguished name.
-# This object is only resolved at time of use, so can be deleted
-# and recreated on the fly while the migration server is active.
-# If missing, it will default to denying access (Since 4.0)
-#
-# @max-bandwidth: maximum speed for migration, in bytes per second.
-# (Since 2.8)
-#
-# @avail-switchover-bandwidth: to set the available bandwidth that
-# migration can use during switchover phase. **Note:** this does
-# not limit the bandwidth during switchover, but only for
-# calculations when making decisions to switchover. By default,
-# this value is zero, which means QEMU will estimate the bandwidth
-# automatically. This can be set when the estimated value is not
-# accurate, while the user is able to guarantee such bandwidth is
-# available when switching over. When specified correctly, this
-# can make the switchover decision much more accurate.
-# (Since 8.2)
-#
-# @downtime-limit: set maximum tolerated downtime for migration.
-# maximum downtime in milliseconds (Since 2.8)
-#
-# @x-checkpoint-delay: The delay time (in ms) between two COLO
-# checkpoints in periodic mode. (Since 2.8)
-#
-# @multifd-channels: Number of channels used to migrate data in
-# parallel. This is the same number that the number of sockets
-# used for migration. The default value is 2 (since 4.0)
-#
-# @xbzrle-cache-size: cache size to be used by XBZRLE migration. It
-# needs to be a multiple of the target page size and a power of 2
-# (Since 2.11)
-#
-# @max-postcopy-bandwidth: Background transfer bandwidth during
-# postcopy. Defaults to 0 (unlimited). In bytes per second.
-# (Since 3.0)
-#
-# @max-cpu-throttle: maximum cpu throttle percentage. Defaults to 99.
-# (Since 3.1)
-#
-# @multifd-compression: Which compression method to use. Defaults to
-# none. (Since 5.0)
-#
-# @multifd-zlib-level: Set the compression level to be used in live
-# migration, the compression level is an integer between 0 and 9,
-# where 0 means no compression, 1 means the best compression
-# speed, and 9 means best compression ratio which will consume
-# more CPU. Defaults to 1. (Since 5.0)
-#
-# @multifd-qatzip-level: Set the compression level to be used in live
-# migration. The level is an integer between 1 and 9, where 1 means
-# the best compression speed, and 9 means the best compression
-# ratio which will consume more CPU. Defaults to 1. (Since 9.2)
-#
-# @multifd-zstd-level: Set the compression level to be used in live
-# migration, the compression level is an integer between 0 and 20,
-# where 0 means no compression, 1 means the best compression
-# speed, and 20 means best compression ratio which will consume
-# more CPU. Defaults to 1. (Since 5.0)
-#
-# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
-# aliases for the purpose of dirty bitmap migration. Such aliases
-# may for example be the corresponding names on the opposite site.
-# The mapping must be one-to-one, but not necessarily complete: On
-# the source, unmapped bitmaps and all bitmaps on unmapped nodes
-# will be ignored. On the destination, encountering an unmapped
-# alias in the incoming migration stream will result in a report,
-# and all further bitmap migration data will then be discarded.
-# Note that the destination does not know about bitmaps it does
-# not receive, so there is no limitation or requirement regarding
-# the number of bitmaps received, or how they are named, or on
-# which nodes they are placed. By default (when this parameter
-# has never been set), bitmap names are mapped to themselves.
-# Nodes are mapped to their block device name if there is one, and
-# to their node name otherwise. (Since 5.2)
-#
-# @x-vcpu-dirty-limit-period: Periodic time (in milliseconds) of dirty
-# limit during live migration. Should be in the range 1 to
-# 1000ms. Defaults to 1000ms. (Since 8.1)
-#
-# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
-# Defaults to 1. (Since 8.1)
-#
-# @mode: Migration mode. See description in @MigMode. Default is
-# 'normal'. (Since 8.2)
-#
-# @zero-page-detection: Whether and how to detect zero pages.
-# See description in @ZeroPageDetection. Default is 'multifd'.
-# (since 9.0)
-#
-# @direct-io: Open migration files with O_DIRECT when possible. This
-# only has effect if the @mapped-ram capability is enabled.
-# (Since 9.1)
+# Migration parameters enumeration. The enumeration values mirror the
+# members of @MigrationParameters.
#
# Features:
#
diff --git a/qapi/pragma.json b/qapi/pragma.json
index 023a2ef7bc..193bc39059 100644
--- a/qapi/pragma.json
+++ b/qapi/pragma.json
@@ -59,6 +59,7 @@
'IscsiTransport',
'KeyValueKind',
'MemoryDeviceInfoKind',
+ 'MigrationParameter',
'NetClientDriver',
'ObjectType',
'QKeyCode',
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 06/24] migration: Run a post update routine after setting parameters
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (4 preceding siblings ...)
2025-06-30 19:58 ` [PATCH v2 05/24] qapi/migration: Don't document MigrationParameter Fabiano Rosas
@ 2025-06-30 19:58 ` Fabiano Rosas
2025-06-30 19:58 ` [PATCH v2 07/24] migration: Add a flag to track block-bitmap-mapping input Fabiano Rosas
` (17 subsequent siblings)
23 siblings, 0 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:58 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
Some migration parameters are updated immediately once they are set
via migrate-set-parameters. Move that work outside of
migrate_params_apply() and leave that function with the single
responsibility of setting s->parameters and not doing any
side-effects.
Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/options.c | 38 ++++++++++++++++++++++++++++----------
migration/ram.c | 2 +-
2 files changed, 29 insertions(+), 11 deletions(-)
diff --git a/migration/options.c b/migration/options.c
index 295367ce92..1f8a977865 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1083,6 +1083,31 @@ void migrate_params_init(MigrationParameters *params)
params->has_direct_io = true;
}
+static void migrate_post_update_params(MigrationParameters *new, Error **errp)
+{
+ MigrationState *s = migrate_get_current();
+
+ if (new->has_max_bandwidth) {
+ if (s->to_dst_file && !migration_in_postcopy()) {
+ migration_rate_set(new->max_bandwidth);
+ }
+ }
+
+ if (new->has_x_checkpoint_delay) {
+ colo_checkpoint_delay_set();
+ }
+
+ if (new->has_xbzrle_cache_size) {
+ xbzrle_cache_resize(new->xbzrle_cache_size, errp);
+ }
+
+ if (new->has_max_postcopy_bandwidth) {
+ if (s->to_dst_file && migration_in_postcopy()) {
+ migration_rate_set(new->max_postcopy_bandwidth);
+ }
+ }
+}
+
/*
* Check whether the parameters are valid. Error will be put into errp
* (if provided). Return true if valid, otherwise false.
@@ -1393,7 +1418,7 @@ static void migrate_params_test_apply(MigrationParameters *params,
}
}
-static void migrate_params_apply(MigrationParameters *params, Error **errp)
+static void migrate_params_apply(MigrationParameters *params)
{
MigrationState *s = migrate_get_current();
@@ -1433,9 +1458,6 @@ static void migrate_params_apply(MigrationParameters *params, Error **errp)
if (params->has_max_bandwidth) {
s->parameters.max_bandwidth = params->max_bandwidth;
- if (s->to_dst_file && !migration_in_postcopy()) {
- migration_rate_set(s->parameters.max_bandwidth);
- }
}
if (params->has_avail_switchover_bandwidth) {
@@ -1448,7 +1470,6 @@ static void migrate_params_apply(MigrationParameters *params, Error **errp)
if (params->has_x_checkpoint_delay) {
s->parameters.x_checkpoint_delay = params->x_checkpoint_delay;
- colo_checkpoint_delay_set();
}
if (params->has_multifd_channels) {
@@ -1468,13 +1489,9 @@ static void migrate_params_apply(MigrationParameters *params, Error **errp)
}
if (params->has_xbzrle_cache_size) {
s->parameters.xbzrle_cache_size = params->xbzrle_cache_size;
- xbzrle_cache_resize(params->xbzrle_cache_size, errp);
}
if (params->has_max_postcopy_bandwidth) {
s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
- if (s->to_dst_file && migration_in_postcopy()) {
- migration_rate_set(s->parameters.max_postcopy_bandwidth);
- }
}
if (params->has_max_cpu_throttle) {
s->parameters.max_cpu_throttle = params->max_cpu_throttle;
@@ -1542,7 +1559,8 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
migrate_params_test_apply(params, &tmp);
if (migrate_params_check(&tmp, errp)) {
- migrate_params_apply(params, errp);
+ migrate_params_apply(params);
+ migrate_post_update_params(params, errp);
}
migrate_tls_opts_free(&tmp);
diff --git a/migration/ram.c b/migration/ram.c
index 2140785a05..7432f82bdd 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -174,7 +174,7 @@ static void XBZRLE_cache_unlock(void)
/**
* xbzrle_cache_resize: resize the xbzrle cache
*
- * This function is called from migrate_params_apply in main
+ * This function is called from migrate_post_update_config in main
* thread, possibly while a migration is in progress. A running
* migration may be using the cache and might finish during this call,
* hence changes to the cache are protected by XBZRLE.lock().
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 07/24] migration: Add a flag to track block-bitmap-mapping input
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (5 preceding siblings ...)
2025-06-30 19:58 ` [PATCH v2 06/24] migration: Run a post update routine after setting parameters Fabiano Rosas
@ 2025-06-30 19:58 ` Fabiano Rosas
2025-07-04 15:42 ` Peter Xu
2025-06-30 19:58 ` [PATCH v2 08/24] migration: Remove checks for s->parameters has_* fields Fabiano Rosas
` (16 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:58 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Kevin Wolf
The QAPI converts an empty list on the block-bitmap-mapping input into
a NULL BitmapMigrationNodeAliasList. The empty list is a valid input
for the block-bitmap-mapping option, so commit 3cba22c9ad ("migration:
Fix block_bitmap_mapping migration") started using the
s->parameters.has_block_bitmap_mapping field to tell when the user has
passed in an empty list vs. when no list has been passed at all.
Using s->parameters.has_block_bitmap_mapping field is only possible
because MigrationParameters has had its members made optional due to
historical reasons.
In order to make improvements to the way configuration options are set
for a migration, we'd like to reduce the open-coded usage of the has_*
fields of the global configuration object (s->parameters).
Add a separate boolean to track the status of the block_bitmap_mapping
option.
No functional change intended.
(this was verified to not regress iotest 300, which is the test that
3cba22c9ad refers to)
CC: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration-hmp-cmds.c | 3 ++-
migration/migration.h | 7 +++++++
migration/options.c | 6 +++---
3 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 82cd2dcb8e..f29bdc12a8 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -240,6 +240,7 @@ void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict)
void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
{
MigrationParameters *params;
+ MigrationState *s = migrate_get_current();
params = qmp_query_migrate_parameters(NULL);
@@ -322,7 +323,7 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ),
params->tls_authz->u.s);
- if (params->has_block_bitmap_mapping) {
+ if (s->has_block_bitmap_mapping) {
const BitmapMigrationNodeAliasList *bmnal;
monitor_printf(mon, "%s:\n",
diff --git a/migration/migration.h b/migration/migration.h
index 739289de93..84c3007ab8 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -510,6 +510,13 @@ struct MigrationState {
bool rdma_migration;
GSource *hup_source;
+
+ /*
+ * The block-bitmap-mapping option is allowed to be an emtpy list,
+ * therefore we need a way to know whether the user has given
+ * anything as input.
+ */
+ bool has_block_bitmap_mapping;
};
void migrate_set_state(MigrationStatus *state, MigrationStatus old_state,
diff --git a/migration/options.c b/migration/options.c
index 1f8a977865..cb5855303a 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -736,7 +736,7 @@ bool migrate_has_block_bitmap_mapping(void)
{
MigrationState *s = migrate_get_current();
- return s->parameters.has_block_bitmap_mapping;
+ return s->has_block_bitmap_mapping;
}
uint32_t migrate_checkpoint_delay(void)
@@ -1033,7 +1033,7 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
params->has_announce_step = true;
params->announce_step = s->parameters.announce_step;
- if (s->parameters.has_block_bitmap_mapping) {
+ if (s->has_block_bitmap_mapping) {
params->has_block_bitmap_mapping = true;
params->block_bitmap_mapping =
QAPI_CLONE(BitmapMigrationNodeAliasList,
@@ -1513,7 +1513,7 @@ static void migrate_params_apply(MigrationParameters *params)
qapi_free_BitmapMigrationNodeAliasList(
s->parameters.block_bitmap_mapping);
- s->parameters.has_block_bitmap_mapping = true;
+ s->has_block_bitmap_mapping = true;
s->parameters.block_bitmap_mapping =
QAPI_CLONE(BitmapMigrationNodeAliasList,
params->block_bitmap_mapping);
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 08/24] migration: Remove checks for s->parameters has_* fields
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (6 preceding siblings ...)
2025-06-30 19:58 ` [PATCH v2 07/24] migration: Add a flag to track block-bitmap-mapping input Fabiano Rosas
@ 2025-06-30 19:58 ` Fabiano Rosas
2025-06-30 19:58 ` [PATCH v2 09/24] migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE Fabiano Rosas
` (15 subsequent siblings)
23 siblings, 0 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:58 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
The migration parameters validation produces a temporary structure
which is the merge of the current parameter values (s->parameters,
MigrationParameters) with the new parameters set by the user
(former MigrateSetParameters).
When copying the values from s->parameters into the temporary
structure, the has_* fields are copied along, but when merging the
user-input values they are not.
During migrate_params_check(), only the parameters that have the
corresponding has_* field will be checked, so only the parameters that
were initialized in migrate_params_init() will be validated.
This causes (almost) all of the migration parameters to be validated
every time a parameter is set, regardless of which fields the user
touched, but it also skips validation of any values that are not set
in migrate_params_init().
It's not clear what was the intention of the original code, whether to
validate all fields always, or only validate what the user input
changed. Since the current situation is closer to the former option,
make the choice of validating all parameters by removing the checks
for the has_* fields when validating.
Note that bringing the user input into the temporary structure for
validation still needs to look at the has_* fields, otherwise any
parameters not set by the user (i.e. 0) would override the
corresponding value in s->parameters.
The empty migrate_params_init() will be kept because subsequent
patches will add code to it.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/options.c | 101 +++++++++++++-------------------------------
1 file changed, 29 insertions(+), 72 deletions(-)
diff --git a/migration/options.c b/migration/options.c
index cb5855303a..af19c8f2e0 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1056,31 +1056,6 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
void migrate_params_init(MigrationParameters *params)
{
- /* Set has_* up only for parameter checks */
- params->has_throttle_trigger_threshold = true;
- params->has_cpu_throttle_initial = true;
- params->has_cpu_throttle_increment = true;
- params->has_cpu_throttle_tailslow = true;
- params->has_max_bandwidth = true;
- params->has_downtime_limit = true;
- params->has_x_checkpoint_delay = true;
- params->has_multifd_channels = true;
- params->has_multifd_compression = true;
- params->has_multifd_zlib_level = true;
- params->has_multifd_qatzip_level = true;
- params->has_multifd_zstd_level = true;
- params->has_xbzrle_cache_size = true;
- params->has_max_postcopy_bandwidth = true;
- params->has_max_cpu_throttle = true;
- params->has_announce_initial = true;
- params->has_announce_max = true;
- params->has_announce_rounds = true;
- params->has_announce_step = true;
- params->has_x_vcpu_dirty_limit_period = true;
- params->has_vcpu_dirty_limit = true;
- params->has_mode = true;
- params->has_zero_page_detection = true;
- params->has_direct_io = true;
}
static void migrate_post_update_params(MigrationParameters *new, Error **errp)
@@ -1116,34 +1091,31 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
{
ERRP_GUARD();
- if (params->has_throttle_trigger_threshold &&
- (params->throttle_trigger_threshold < 1 ||
- params->throttle_trigger_threshold > 100)) {
+ if (params->throttle_trigger_threshold < 1 ||
+ params->throttle_trigger_threshold > 100) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"throttle_trigger_threshold",
"an integer in the range of 1 to 100");
return false;
}
- if (params->has_cpu_throttle_initial &&
- (params->cpu_throttle_initial < 1 ||
- params->cpu_throttle_initial > 99)) {
+ if (params->cpu_throttle_initial < 1 ||
+ params->cpu_throttle_initial > 99) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"cpu_throttle_initial",
"an integer in the range of 1 to 99");
return false;
}
- if (params->has_cpu_throttle_increment &&
- (params->cpu_throttle_increment < 1 ||
- params->cpu_throttle_increment > 99)) {
+ if (params->cpu_throttle_increment < 1 ||
+ params->cpu_throttle_increment > 99) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"cpu_throttle_increment",
"an integer in the range of 1 to 99");
return false;
}
- if (params->has_max_bandwidth && (params->max_bandwidth > SIZE_MAX)) {
+ if (params->max_bandwidth > SIZE_MAX) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"max_bandwidth",
"an integer in the range of 0 to "stringify(SIZE_MAX)
@@ -1151,8 +1123,7 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
return false;
}
- if (params->has_avail_switchover_bandwidth &&
- (params->avail_switchover_bandwidth > SIZE_MAX)) {
+ if (params->avail_switchover_bandwidth > SIZE_MAX) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"avail_switchover_bandwidth",
"an integer in the range of 0 to "stringify(SIZE_MAX)
@@ -1160,8 +1131,7 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
return false;
}
- if (params->has_downtime_limit &&
- (params->downtime_limit > MAX_MIGRATE_DOWNTIME)) {
+ if (params->downtime_limit > MAX_MIGRATE_DOWNTIME) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"downtime_limit",
"an integer in the range of 0 to "
@@ -1171,93 +1141,82 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
/* x_checkpoint_delay is now always positive */
- if (params->has_multifd_channels && (params->multifd_channels < 1)) {
+ if (params->multifd_channels < 1) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"multifd_channels",
"a value between 1 and 255");
return false;
}
- if (params->has_multifd_zlib_level &&
- (params->multifd_zlib_level > 9)) {
+ if (params->multifd_zlib_level > 9) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zlib_level",
"a value between 0 and 9");
return false;
}
- if (params->has_multifd_qatzip_level &&
- ((params->multifd_qatzip_level > 9) ||
- (params->multifd_qatzip_level < 1))) {
+ if (params->multifd_qatzip_level > 9 ||
+ params->multifd_qatzip_level < 1) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_qatzip_level",
"a value between 1 and 9");
return false;
}
- if (params->has_multifd_zstd_level &&
- (params->multifd_zstd_level > 20)) {
+ if (params->multifd_zstd_level > 20) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zstd_level",
"a value between 0 and 20");
return false;
}
- if (params->has_xbzrle_cache_size &&
- (params->xbzrle_cache_size < qemu_target_page_size() ||
- !is_power_of_2(params->xbzrle_cache_size))) {
+ if (params->xbzrle_cache_size < qemu_target_page_size() ||
+ !is_power_of_2(params->xbzrle_cache_size)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"xbzrle_cache_size",
"a power of two no less than the target page size");
return false;
}
- if (params->has_max_cpu_throttle &&
- (params->max_cpu_throttle < params->cpu_throttle_initial ||
- params->max_cpu_throttle > 99)) {
+ if (params->max_cpu_throttle < params->cpu_throttle_initial ||
+ params->max_cpu_throttle > 99) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"max_cpu_throttle",
"an integer in the range of cpu_throttle_initial to 99");
return false;
}
- if (params->has_announce_initial &&
- params->announce_initial > 100000) {
+ if (params->announce_initial > 100000) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"announce_initial",
"a value between 0 and 100000");
return false;
}
- if (params->has_announce_max &&
- params->announce_max > 100000) {
+ if (params->announce_max > 100000) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"announce_max",
"a value between 0 and 100000");
return false;
}
- if (params->has_announce_rounds &&
- params->announce_rounds > 1000) {
+ if (params->announce_rounds > 1000) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"announce_rounds",
"a value between 0 and 1000");
return false;
}
- if (params->has_announce_step &&
- (params->announce_step < 1 ||
- params->announce_step > 10000)) {
+ if (params->announce_step < 1 ||
+ params->announce_step > 10000) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"announce_step",
"a value between 0 and 10000");
return false;
}
- if (params->has_block_bitmap_mapping &&
- !check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) {
+ if (!check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) {
error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: ");
return false;
}
#ifdef CONFIG_LINUX
if (migrate_zero_copy_send() &&
- ((params->has_multifd_compression && params->multifd_compression) ||
- *params->tls_creds->u.s)) {
+ (params->multifd_compression || *params->tls_creds->u.s)) {
error_setg(errp,
"Zero copy only available for non-compressed non-TLS multifd migration");
return false;
@@ -1271,23 +1230,21 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
return false;
}
- if (params->has_x_vcpu_dirty_limit_period &&
- (params->x_vcpu_dirty_limit_period < 1 ||
- params->x_vcpu_dirty_limit_period > 1000)) {
+ if (params->x_vcpu_dirty_limit_period < 1 ||
+ params->x_vcpu_dirty_limit_period > 1000) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"x-vcpu-dirty-limit-period",
"a value between 1 and 1000");
return false;
}
- if (params->has_vcpu_dirty_limit &&
- (params->vcpu_dirty_limit < 1)) {
+ if (params->vcpu_dirty_limit < 1) {
error_setg(errp,
"Parameter 'vcpu_dirty_limit' must be greater than 1 MB/s");
return false;
}
- if (params->has_direct_io && params->direct_io && !qemu_has_direct_io()) {
+ if (params->direct_io && !qemu_has_direct_io()) {
error_setg(errp, "No build-time support for direct-io");
return false;
}
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 09/24] migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (7 preceding siblings ...)
2025-06-30 19:58 ` [PATCH v2 08/24] migration: Remove checks for s->parameters has_* fields Fabiano Rosas
@ 2025-06-30 19:58 ` Fabiano Rosas
2025-07-04 16:04 ` Peter Xu
2025-06-30 19:58 ` [PATCH v2 10/24] migration: Extract code to mark all parameters as present Fabiano Rosas
` (14 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:58 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
The QERR_INVALID_PARAMETER_VALUE macro is documented as not to be used
in new code. Remove the usage from migration/options.c.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration.c | 3 +--
migration/options.c | 56 +++++++++++++++---------------------------
migration/page_cache.c | 6 ++---
migration/ram.c | 3 +--
4 files changed, 24 insertions(+), 44 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index 7ec60d97f9..487019dc69 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2302,8 +2302,7 @@ static void qmp_migrate_finish(MigrationAddress *addr, bool resume_requested,
} else if (addr->transport == MIGRATION_ADDRESS_TYPE_FILE) {
file_start_outgoing_migration(s, &addr->u.file, &local_err);
} else {
- error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "uri",
- "a valid migration protocol");
+ error_setg(&local_err, "uri is not a valid migration protocol");
migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
MIGRATION_STATUS_FAILED);
}
diff --git a/migration/options.c b/migration/options.c
index af19c8f2e0..7a6a7d4ee5 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1093,120 +1093,105 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
if (params->throttle_trigger_threshold < 1 ||
params->throttle_trigger_threshold > 100) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "throttle_trigger_threshold",
+ error_setg(errp, "Option throttle_trigger_threshold expects "
"an integer in the range of 1 to 100");
return false;
}
if (params->cpu_throttle_initial < 1 ||
params->cpu_throttle_initial > 99) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "cpu_throttle_initial",
+ error_setg(errp, "Option cpu_throttle_initial expects "
"an integer in the range of 1 to 99");
return false;
}
if (params->cpu_throttle_increment < 1 ||
params->cpu_throttle_increment > 99) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "cpu_throttle_increment",
+ error_setg(errp, "Option cpu_throttle_increment expects "
"an integer in the range of 1 to 99");
return false;
}
if (params->max_bandwidth > SIZE_MAX) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "max_bandwidth",
+ error_setg(errp, "Option max_bandwidth expects "
"an integer in the range of 0 to "stringify(SIZE_MAX)
" bytes/second");
return false;
}
if (params->avail_switchover_bandwidth > SIZE_MAX) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "avail_switchover_bandwidth",
+ error_setg(errp, "Option avail_switchover_bandwidth expects "
"an integer in the range of 0 to "stringify(SIZE_MAX)
" bytes/second");
return false;
}
if (params->downtime_limit > MAX_MIGRATE_DOWNTIME) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "downtime_limit",
+ error_setg(errp, "Option downtime_limit expects "
"an integer in the range of 0 to "
stringify(MAX_MIGRATE_DOWNTIME)" ms");
return false;
}
- /* x_checkpoint_delay is now always positive */
-
if (params->multifd_channels < 1) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "multifd_channels",
+ error_setg(errp, "Option multifd_channels expects "
"a value between 1 and 255");
return false;
}
if (params->multifd_zlib_level > 9) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zlib_level",
+ error_setg(errp, "Option multifd_zlib_level expects "
"a value between 0 and 9");
return false;
}
if (params->multifd_qatzip_level > 9 ||
params->multifd_qatzip_level < 1) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_qatzip_level",
+ error_setg(errp, "Option multifd_qatzip_level expects "
"a value between 1 and 9");
return false;
}
if (params->multifd_zstd_level > 20) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zstd_level",
+ error_setg(errp, "Option multifd_zstd_level expects "
"a value between 0 and 20");
return false;
}
if (params->xbzrle_cache_size < qemu_target_page_size() ||
!is_power_of_2(params->xbzrle_cache_size)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "xbzrle_cache_size",
+ error_setg(errp, "Option xbzrle_cache_size expects "
"a power of two no less than the target page size");
return false;
}
if (params->max_cpu_throttle < params->cpu_throttle_initial ||
params->max_cpu_throttle > 99) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "max_cpu_throttle",
+ error_setg(errp, "max_Option cpu_throttle expects "
"an integer in the range of cpu_throttle_initial to 99");
return false;
}
if (params->announce_initial > 100000) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "announce_initial",
+ error_setg(errp, "Option announce_initial expects "
"a value between 0 and 100000");
return false;
}
if (params->announce_max > 100000) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "announce_max",
+ error_setg(errp, "Option announce_max expects "
"a value between 0 and 100000");
- return false;
+ return false;
}
if (params->announce_rounds > 1000) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "announce_rounds",
+ error_setg(errp, "Option announce_rounds expects "
"a value between 0 and 1000");
- return false;
+ return false;
}
if (params->announce_step < 1 ||
params->announce_step > 10000) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "announce_step",
+ error_setg(errp, "Option announce_step expects "
"a value between 0 and 10000");
- return false;
+ return false;
}
if (!check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) {
@@ -1232,8 +1217,7 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
if (params->x_vcpu_dirty_limit_period < 1 ||
params->x_vcpu_dirty_limit_period > 1000) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "x-vcpu-dirty-limit-period",
+ error_setg(errp, "Option x-vcpu-dirty-limit-period expects "
"a value between 1 and 1000");
return false;
}
diff --git a/migration/page_cache.c b/migration/page_cache.c
index 6d4f7a9bbc..650b15e48c 100644
--- a/migration/page_cache.c
+++ b/migration/page_cache.c
@@ -45,15 +45,13 @@ PageCache *cache_init(uint64_t new_size, size_t page_size, Error **errp)
PageCache *cache;
if (new_size < page_size) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
- "is smaller than one target page size");
+ error_setg(errp, "cache size is smaller than target page size");
return NULL;
}
/* round down to the nearest power of 2 */
if (!is_power_of_2(num_pages)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
- "is not a power of two number of pages");
+ error_setg(errp, "number of pages is not a power of two");
return NULL;
}
diff --git a/migration/ram.c b/migration/ram.c
index 7432f82bdd..bb86a91db1 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -191,8 +191,7 @@ int xbzrle_cache_resize(uint64_t new_size, Error **errp)
/* Check for truncation */
if (new_size != (size_t)new_size) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
- "exceeding address space");
+ error_setg(errp, "xbzrle cache size integer overflow");
return -1;
}
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 10/24] migration: Extract code to mark all parameters as present
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (8 preceding siblings ...)
2025-06-30 19:58 ` [PATCH v2 09/24] migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE Fabiano Rosas
@ 2025-06-30 19:58 ` Fabiano Rosas
2025-06-30 19:59 ` [PATCH v2 11/24] migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters Fabiano Rosas
` (13 subsequent siblings)
23 siblings, 0 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:58 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Kevin Wolf
MigrationParameters needs to have all of its has_* fields marked as
true when used as the return of query_migrate_parameters because the
corresponding QMP command has all of its members non-optional by
design, despite them being marked as optional in migration.json.
Extract this code into a function and make it assert if any field is
missing. With this we ensure future changes will not inadvertently
leave any parameters missing.
Note that the block-bitmap-mapping is a special case because the empty
list is considered a valid value, so it has historically not been
present in the command's output if it has never been set.
CC: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/options.c | 87 ++++++++++++++++++++++++++++-----------------
1 file changed, 54 insertions(+), 33 deletions(-)
diff --git a/migration/options.c b/migration/options.c
index 7a6a7d4ee5..df9f0bd812 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -982,6 +982,43 @@ static void tls_opt_to_str(StrOrNull **tls_opt)
*tls_opt = opt;
}
+/*
+ * query-migrate-parameters expects all members of MigrationParameters
+ * to be present, but we cannot mark them non-optional in QAPI because
+ * the structure is also used for migrate-set-parameters, which needs
+ * the optionality. Force all parameters to be seen as present
+ * now. Note that this depends on some form of default being set for
+ * every member of MigrationParameters, currently done during qdev
+ * init using migration_properties defined in this file. The TLS
+ * options are a special case because they don't have a default and
+ * need to be normalized before use.
+ */
+static void migrate_mark_all_params_present(MigrationParameters *p)
+{
+ int len, n_str_args = 3; /* tls-creds, tls-hostname, tls-authz */
+ bool *has_fields[] = {
+ &p->has_throttle_trigger_threshold, &p->has_cpu_throttle_initial,
+ &p->has_cpu_throttle_increment, &p->has_cpu_throttle_tailslow,
+ &p->has_max_bandwidth, &p->has_avail_switchover_bandwidth,
+ &p->has_downtime_limit, &p->has_x_checkpoint_delay,
+ &p->has_multifd_channels, &p->has_multifd_compression,
+ &p->has_multifd_zlib_level, &p->has_multifd_qatzip_level,
+ &p->has_multifd_zstd_level, &p->has_xbzrle_cache_size,
+ &p->has_max_postcopy_bandwidth, &p->has_max_cpu_throttle,
+ &p->has_announce_initial, &p->has_announce_max, &p->has_announce_rounds,
+ &p->has_announce_step, &p->has_block_bitmap_mapping,
+ &p->has_x_vcpu_dirty_limit_period, &p->has_vcpu_dirty_limit,
+ &p->has_mode, &p->has_zero_page_detection, &p->has_direct_io,
+ };
+
+ len = ARRAY_SIZE(has_fields);
+ assert(len + n_str_args == MIGRATION_PARAMETER__MAX);
+
+ for (int i = 0; i < len; i++) {
+ *has_fields[i] = true;
+ }
+}
+
MigrationParameters *qmp_query_migrate_parameters(Error **errp)
{
MigrationParameters *params;
@@ -989,67 +1026,51 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
/* TODO use QAPI_CLONE() instead of duplicating it inline */
params = g_malloc0(sizeof(*params));
- params->has_throttle_trigger_threshold = true;
+
params->throttle_trigger_threshold = s->parameters.throttle_trigger_threshold;
- params->has_cpu_throttle_initial = true;
params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
- params->has_cpu_throttle_increment = true;
params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
- params->has_cpu_throttle_tailslow = true;
params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow;
params->tls_creds = QAPI_CLONE(StrOrNull, s->parameters.tls_creds);
params->tls_hostname = QAPI_CLONE(StrOrNull, s->parameters.tls_hostname);
params->tls_authz = QAPI_CLONE(StrOrNull, s->parameters.tls_authz);
- params->has_max_bandwidth = true;
params->max_bandwidth = s->parameters.max_bandwidth;
- params->has_avail_switchover_bandwidth = true;
params->avail_switchover_bandwidth = s->parameters.avail_switchover_bandwidth;
- params->has_downtime_limit = true;
params->downtime_limit = s->parameters.downtime_limit;
- params->has_x_checkpoint_delay = true;
params->x_checkpoint_delay = s->parameters.x_checkpoint_delay;
- params->has_multifd_channels = true;
params->multifd_channels = s->parameters.multifd_channels;
- params->has_multifd_compression = true;
params->multifd_compression = s->parameters.multifd_compression;
- params->has_multifd_zlib_level = true;
params->multifd_zlib_level = s->parameters.multifd_zlib_level;
- params->has_multifd_qatzip_level = true;
params->multifd_qatzip_level = s->parameters.multifd_qatzip_level;
- params->has_multifd_zstd_level = true;
params->multifd_zstd_level = s->parameters.multifd_zstd_level;
- params->has_xbzrle_cache_size = true;
params->xbzrle_cache_size = s->parameters.xbzrle_cache_size;
- params->has_max_postcopy_bandwidth = true;
params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth;
- params->has_max_cpu_throttle = true;
params->max_cpu_throttle = s->parameters.max_cpu_throttle;
- params->has_announce_initial = true;
params->announce_initial = s->parameters.announce_initial;
- params->has_announce_max = true;
params->announce_max = s->parameters.announce_max;
- params->has_announce_rounds = true;
params->announce_rounds = s->parameters.announce_rounds;
- params->has_announce_step = true;
params->announce_step = s->parameters.announce_step;
-
- if (s->has_block_bitmap_mapping) {
- params->has_block_bitmap_mapping = true;
- params->block_bitmap_mapping =
- QAPI_CLONE(BitmapMigrationNodeAliasList,
- s->parameters.block_bitmap_mapping);
- }
-
- params->has_x_vcpu_dirty_limit_period = true;
params->x_vcpu_dirty_limit_period = s->parameters.x_vcpu_dirty_limit_period;
- params->has_vcpu_dirty_limit = true;
params->vcpu_dirty_limit = s->parameters.vcpu_dirty_limit;
- params->has_mode = true;
params->mode = s->parameters.mode;
- params->has_zero_page_detection = true;
params->zero_page_detection = s->parameters.zero_page_detection;
- params->has_direct_io = true;
params->direct_io = s->parameters.direct_io;
+ params->block_bitmap_mapping =
+ QAPI_CLONE(BitmapMigrationNodeAliasList,
+ s->parameters.block_bitmap_mapping);
+
+ migrate_mark_all_params_present(params);
+
+ /*
+ * The block-bitmap-mapping breaks the expected API of
+ * query-migrate-parameters of having all members present. To keep
+ * compatibility, only emit this field if it's actually been
+ * set. The empty list is a valid value.
+ */
+ if (!s->has_block_bitmap_mapping) {
+ params->has_block_bitmap_mapping = false;
+ qapi_free_BitmapMigrationNodeAliasList(params->block_bitmap_mapping);
+ }
return params;
}
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 11/24] migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (9 preceding siblings ...)
2025-06-30 19:58 ` [PATCH v2 10/24] migration: Extract code to mark all parameters as present Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-07-04 16:11 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 12/24] migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply Fabiano Rosas
` (12 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
QAPI_CLONE_MEMBERS is a better option than copying parameters one by
one because it operates on the entire struct and follows pointers. It
also avoids the need to alter this function every time a new parameter
is added.
For this to work, the has_* fields of s->parameters need to be already
set beforehand, so move migrate_mark_all_params_present() to the init
routine.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/options.c | 41 +++--------------------------------------
1 file changed, 3 insertions(+), 38 deletions(-)
diff --git a/migration/options.c b/migration/options.c
index df9f0bd812..d07931f922 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1021,45 +1021,9 @@ static void migrate_mark_all_params_present(MigrationParameters *p)
MigrationParameters *qmp_query_migrate_parameters(Error **errp)
{
- MigrationParameters *params;
MigrationState *s = migrate_get_current();
-
- /* TODO use QAPI_CLONE() instead of duplicating it inline */
- params = g_malloc0(sizeof(*params));
-
- params->throttle_trigger_threshold = s->parameters.throttle_trigger_threshold;
- params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
- params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
- params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow;
- params->tls_creds = QAPI_CLONE(StrOrNull, s->parameters.tls_creds);
- params->tls_hostname = QAPI_CLONE(StrOrNull, s->parameters.tls_hostname);
- params->tls_authz = QAPI_CLONE(StrOrNull, s->parameters.tls_authz);
- params->max_bandwidth = s->parameters.max_bandwidth;
- params->avail_switchover_bandwidth = s->parameters.avail_switchover_bandwidth;
- params->downtime_limit = s->parameters.downtime_limit;
- params->x_checkpoint_delay = s->parameters.x_checkpoint_delay;
- params->multifd_channels = s->parameters.multifd_channels;
- params->multifd_compression = s->parameters.multifd_compression;
- params->multifd_zlib_level = s->parameters.multifd_zlib_level;
- params->multifd_qatzip_level = s->parameters.multifd_qatzip_level;
- params->multifd_zstd_level = s->parameters.multifd_zstd_level;
- params->xbzrle_cache_size = s->parameters.xbzrle_cache_size;
- params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth;
- params->max_cpu_throttle = s->parameters.max_cpu_throttle;
- params->announce_initial = s->parameters.announce_initial;
- params->announce_max = s->parameters.announce_max;
- params->announce_rounds = s->parameters.announce_rounds;
- params->announce_step = s->parameters.announce_step;
- params->x_vcpu_dirty_limit_period = s->parameters.x_vcpu_dirty_limit_period;
- params->vcpu_dirty_limit = s->parameters.vcpu_dirty_limit;
- params->mode = s->parameters.mode;
- params->zero_page_detection = s->parameters.zero_page_detection;
- params->direct_io = s->parameters.direct_io;
- params->block_bitmap_mapping =
- QAPI_CLONE(BitmapMigrationNodeAliasList,
- s->parameters.block_bitmap_mapping);
-
- migrate_mark_all_params_present(params);
+ MigrationParameters *params = QAPI_CLONE(MigrationParameters,
+ &s->parameters);
/*
* The block-bitmap-mapping breaks the expected API of
@@ -1077,6 +1041,7 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
void migrate_params_init(MigrationParameters *params)
{
+ migrate_mark_all_params_present(params);
}
static void migrate_post_update_params(MigrationParameters *new, Error **errp)
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 12/24] migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (10 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 11/24] migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-06-30 19:59 ` [PATCH v2 13/24] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply Fabiano Rosas
` (11 subsequent siblings)
23 siblings, 0 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
Use QAPI_CLONE_MEMBERS instead of making an assignment. The QAPI
method makes the handling of the TLS strings more intuitive because it
clones them as well.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/options.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/migration/options.c b/migration/options.c
index d07931f922..4564db77f2 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1225,9 +1225,9 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
static void migrate_params_test_apply(MigrationParameters *params,
MigrationParameters *dest)
{
- *dest = migrate_get_current()->parameters;
+ MigrationState *s = migrate_get_current();
- /* TODO use QAPI_CLONE() instead of duplicating it inline */
+ QAPI_CLONE_MEMBERS(MigrationParameters, dest, &s->parameters);
if (params->has_throttle_trigger_threshold) {
dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
@@ -1246,24 +1246,18 @@ static void migrate_params_test_apply(MigrationParameters *params,
}
if (params->tls_creds) {
+ qapi_free_StrOrNull(dest->tls_creds);
dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
- } else {
- /* drop the reference, it's owned by s->parameters */
- dest->tls_creds = NULL;
}
if (params->tls_hostname) {
+ qapi_free_StrOrNull(dest->tls_hostname);
dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
- } else {
- /* drop the reference, it's owned by s->parameters */
- dest->tls_hostname = NULL;
}
if (params->tls_authz) {
+ qapi_free_StrOrNull(dest->tls_authz);
dest->tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
- } else {
- /* drop the reference, it's owned by s->parameters */
- dest->tls_authz = NULL;
}
if (params->has_max_bandwidth) {
@@ -1320,7 +1314,6 @@ static void migrate_params_test_apply(MigrationParameters *params,
}
if (params->has_block_bitmap_mapping) {
- dest->has_block_bitmap_mapping = true;
dest->block_bitmap_mapping = params->block_bitmap_mapping;
}
@@ -1485,6 +1478,14 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
migrate_params_test_apply(params, &tmp);
+ /*
+ * Mark block_bitmap_mapping as present now while we have the
+ * params structure with the user input around.
+ */
+ if (params->has_block_bitmap_mapping) {
+ migrate_get_current()->has_block_bitmap_mapping = true;
+ }
+
if (migrate_params_check(&tmp, errp)) {
migrate_params_apply(params);
migrate_post_update_params(params, errp);
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 13/24] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (11 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 12/24] migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-08-13 19:05 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 14/24] migration: Use visitors in migrate_params_test_apply Fabiano Rosas
` (10 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
Instead of setting parameters one by one, use the temporary object,
which already contains the current migration parameters plus the new
ones and was just validated by migration_params_check(). Use cloning
to overwrite it.
This avoids the need to alter this function every time a new parameter
is added.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/options.c | 123 +++-----------------------------------------
1 file changed, 7 insertions(+), 116 deletions(-)
diff --git a/migration/options.c b/migration/options.c
index 4564db77f2..6619b5f21a 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -13,6 +13,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
#include "exec/target_page.h"
#include "qapi/clone-visitor.h"
#include "qapi/error.h"
@@ -1341,123 +1342,13 @@ static void migrate_params_test_apply(MigrationParameters *params,
static void migrate_params_apply(MigrationParameters *params)
{
MigrationState *s = migrate_get_current();
+ MigrationParameters *cur = &s->parameters;
- /* TODO use QAPI_CLONE() instead of duplicating it inline */
+ assert(bql_locked());
- if (params->has_throttle_trigger_threshold) {
- s->parameters.throttle_trigger_threshold = params->throttle_trigger_threshold;
- }
-
- if (params->has_cpu_throttle_initial) {
- s->parameters.cpu_throttle_initial = params->cpu_throttle_initial;
- }
-
- if (params->has_cpu_throttle_increment) {
- s->parameters.cpu_throttle_increment = params->cpu_throttle_increment;
- }
-
- if (params->has_cpu_throttle_tailslow) {
- s->parameters.cpu_throttle_tailslow = params->cpu_throttle_tailslow;
- }
-
- if (params->tls_creds) {
- qapi_free_StrOrNull(s->parameters.tls_creds);
- s->parameters.tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
- }
-
- if (params->tls_hostname) {
- qapi_free_StrOrNull(s->parameters.tls_hostname);
- s->parameters.tls_hostname = QAPI_CLONE(StrOrNull,
- params->tls_hostname);
- }
-
- if (params->tls_authz) {
- qapi_free_StrOrNull(s->parameters.tls_authz);
- s->parameters.tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
- }
-
- if (params->has_max_bandwidth) {
- s->parameters.max_bandwidth = params->max_bandwidth;
- }
-
- if (params->has_avail_switchover_bandwidth) {
- s->parameters.avail_switchover_bandwidth = params->avail_switchover_bandwidth;
- }
-
- if (params->has_downtime_limit) {
- s->parameters.downtime_limit = params->downtime_limit;
- }
-
- if (params->has_x_checkpoint_delay) {
- s->parameters.x_checkpoint_delay = params->x_checkpoint_delay;
- }
-
- if (params->has_multifd_channels) {
- s->parameters.multifd_channels = params->multifd_channels;
- }
- if (params->has_multifd_compression) {
- s->parameters.multifd_compression = params->multifd_compression;
- }
- if (params->has_multifd_qatzip_level) {
- s->parameters.multifd_qatzip_level = params->multifd_qatzip_level;
- }
- if (params->has_multifd_zlib_level) {
- s->parameters.multifd_zlib_level = params->multifd_zlib_level;
- }
- if (params->has_multifd_zstd_level) {
- s->parameters.multifd_zstd_level = params->multifd_zstd_level;
- }
- if (params->has_xbzrle_cache_size) {
- s->parameters.xbzrle_cache_size = params->xbzrle_cache_size;
- }
- if (params->has_max_postcopy_bandwidth) {
- s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
- }
- if (params->has_max_cpu_throttle) {
- s->parameters.max_cpu_throttle = params->max_cpu_throttle;
- }
- if (params->has_announce_initial) {
- s->parameters.announce_initial = params->announce_initial;
- }
- if (params->has_announce_max) {
- s->parameters.announce_max = params->announce_max;
- }
- if (params->has_announce_rounds) {
- s->parameters.announce_rounds = params->announce_rounds;
- }
- if (params->has_announce_step) {
- s->parameters.announce_step = params->announce_step;
- }
-
- if (params->has_block_bitmap_mapping) {
- qapi_free_BitmapMigrationNodeAliasList(
- s->parameters.block_bitmap_mapping);
-
- s->has_block_bitmap_mapping = true;
- s->parameters.block_bitmap_mapping =
- QAPI_CLONE(BitmapMigrationNodeAliasList,
- params->block_bitmap_mapping);
- }
-
- if (params->has_x_vcpu_dirty_limit_period) {
- s->parameters.x_vcpu_dirty_limit_period =
- params->x_vcpu_dirty_limit_period;
- }
- if (params->has_vcpu_dirty_limit) {
- s->parameters.vcpu_dirty_limit = params->vcpu_dirty_limit;
- }
-
- if (params->has_mode) {
- s->parameters.mode = params->mode;
- }
-
- if (params->has_zero_page_detection) {
- s->parameters.zero_page_detection = params->zero_page_detection;
- }
-
- if (params->has_direct_io) {
- s->parameters.direct_io = params->direct_io;
- }
+ migrate_tls_opts_free(cur);
+ qapi_free_BitmapMigrationNodeAliasList(cur->block_bitmap_mapping);
+ QAPI_CLONE_MEMBERS(MigrationParameters, cur, params);
}
void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
@@ -1487,7 +1378,7 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
}
if (migrate_params_check(&tmp, errp)) {
- migrate_params_apply(params);
+ migrate_params_apply(&tmp);
migrate_post_update_params(params, errp);
}
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 14/24] migration: Use visitors in migrate_params_test_apply
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (12 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 13/24] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-08-13 20:05 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 15/24] migration: Cleanup hmp_info_migrate_parameters Fabiano Rosas
` (9 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
Convert the code in migrate_params_test_apply() from an open-coded
copy of every migration parameter to a copy using visitors. The
current code has conditionals for each parameter's has_* field, which
is exactly what the visitors do.
This hides the details of QAPI from the migration code and avoids the
need to update migrate_params_test_apply() every time a new migration
parameter is added. Both were very confusing and while the visitor
code can become a bit involved, there is no need for new contributors
to ever touch it.
Change the name of the function to a more direct reference of what it
does: merging the user params with the temporary copy.
Move the QAPI_CLONE_MEMBERS into the caller, so QAPI_CLONE can be used
and there's no need to allocate memory in the migration
code. Similarly, turn 'tmp' into a pointer so the proper qapi_free_
routine can be used.
An extra call to migrate_mark_all_params_present() is now needed
because the visitors update the has_ field for non-present fields, but
we actually want them all set so migrate_params_apply() can copy all
of them.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/options.c | 157 +++++++++++++++-----------------------------
1 file changed, 54 insertions(+), 103 deletions(-)
diff --git a/migration/options.c b/migration/options.c
index 6619b5f21a..695bec5b8f 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -20,6 +20,10 @@
#include "qapi/qapi-commands-migration.h"
#include "qapi/qapi-visit-migration.h"
#include "qapi/qmp/qerror.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
+#include "qapi/visitor.h"
+#include "qobject/qdict.h"
#include "qobject/qnull.h"
#include "system/runstate.h"
#include "migration/colo.h"
@@ -1223,120 +1227,63 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
return true;
}
-static void migrate_params_test_apply(MigrationParameters *params,
- MigrationParameters *dest)
+static bool migrate_params_merge(MigrationParameters *dst,
+ MigrationParameters *src, Error **errp)
{
- MigrationState *s = migrate_get_current();
+ QObject *ret_out = NULL;
+ Visitor *v;
+ bool ok;
- QAPI_CLONE_MEMBERS(MigrationParameters, dest, &s->parameters);
-
- if (params->has_throttle_trigger_threshold) {
- dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
- }
-
- if (params->has_cpu_throttle_initial) {
- dest->cpu_throttle_initial = params->cpu_throttle_initial;
- }
-
- if (params->has_cpu_throttle_increment) {
- dest->cpu_throttle_increment = params->cpu_throttle_increment;
+ /* free memory from pointers that are about to be assigned */
+ if (src->has_block_bitmap_mapping) {
+ qapi_free_BitmapMigrationNodeAliasList(dst->block_bitmap_mapping);
}
- if (params->has_cpu_throttle_tailslow) {
- dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow;
+ if (src->tls_creds) {
+ qapi_free_StrOrNull(dst->tls_creds);
}
- if (params->tls_creds) {
- qapi_free_StrOrNull(dest->tls_creds);
- dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
+ if (src->tls_hostname) {
+ qapi_free_StrOrNull(dst->tls_hostname);
}
- if (params->tls_hostname) {
- qapi_free_StrOrNull(dest->tls_hostname);
- dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
+ if (src->tls_authz) {
+ qapi_free_StrOrNull(dst->tls_authz);
}
- if (params->tls_authz) {
- qapi_free_StrOrNull(dest->tls_authz);
- dest->tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
+ /* read in from src */
+ v = qobject_output_visitor_new(&ret_out);
+ ok = visit_type_MigrationParameters(v, NULL, &src, errp);
+ if (!ok) {
+ goto out;
}
+ visit_complete(v, &ret_out);
+ visit_free(v);
- if (params->has_max_bandwidth) {
- dest->max_bandwidth = params->max_bandwidth;
+ /*
+ * Write to dst but leave existing fields intact (except for has_*
+ * which will be updated according to their presence in src).
+ */
+ v = qobject_input_visitor_new(ret_out);
+ ok = visit_start_struct(v, NULL, NULL, 0, errp);
+ if (!ok) {
+ goto out;
}
-
- if (params->has_avail_switchover_bandwidth) {
- dest->avail_switchover_bandwidth = params->avail_switchover_bandwidth;
+ ok = visit_type_MigrationParameters_members(v, dst, errp);
+ if (!ok) {
+ goto out;
}
-
- if (params->has_downtime_limit) {
- dest->downtime_limit = params->downtime_limit;
+ ok = visit_check_struct(v, errp);
+ visit_end_struct(v, NULL);
+ if (!ok) {
+ goto out;
}
- if (params->has_x_checkpoint_delay) {
- dest->x_checkpoint_delay = params->x_checkpoint_delay;
- }
+out:
+ visit_free(v);
+ qobject_unref(ret_out);
- if (params->has_multifd_channels) {
- dest->multifd_channels = params->multifd_channels;
- }
- if (params->has_multifd_compression) {
- dest->multifd_compression = params->multifd_compression;
- }
- if (params->has_multifd_qatzip_level) {
- dest->multifd_qatzip_level = params->multifd_qatzip_level;
- }
- if (params->has_multifd_zlib_level) {
- dest->multifd_zlib_level = params->multifd_zlib_level;
- }
- if (params->has_multifd_zstd_level) {
- dest->multifd_zstd_level = params->multifd_zstd_level;
- }
- if (params->has_xbzrle_cache_size) {
- dest->xbzrle_cache_size = params->xbzrle_cache_size;
- }
- if (params->has_max_postcopy_bandwidth) {
- dest->max_postcopy_bandwidth = params->max_postcopy_bandwidth;
- }
- if (params->has_max_cpu_throttle) {
- dest->max_cpu_throttle = params->max_cpu_throttle;
- }
- if (params->has_announce_initial) {
- dest->announce_initial = params->announce_initial;
- }
- if (params->has_announce_max) {
- dest->announce_max = params->announce_max;
- }
- if (params->has_announce_rounds) {
- dest->announce_rounds = params->announce_rounds;
- }
- if (params->has_announce_step) {
- dest->announce_step = params->announce_step;
- }
-
- if (params->has_block_bitmap_mapping) {
- dest->block_bitmap_mapping = params->block_bitmap_mapping;
- }
-
- if (params->has_x_vcpu_dirty_limit_period) {
- dest->x_vcpu_dirty_limit_period =
- params->x_vcpu_dirty_limit_period;
- }
- if (params->has_vcpu_dirty_limit) {
- dest->vcpu_dirty_limit = params->vcpu_dirty_limit;
- }
-
- if (params->has_mode) {
- dest->mode = params->mode;
- }
-
- if (params->has_zero_page_detection) {
- dest->zero_page_detection = params->zero_page_detection;
- }
-
- if (params->has_direct_io) {
- dest->direct_io = params->direct_io;
- }
+ return ok;
}
static void migrate_params_apply(MigrationParameters *params)
@@ -1353,7 +1300,9 @@ static void migrate_params_apply(MigrationParameters *params)
void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
{
- MigrationParameters tmp;
+ MigrationState *s = migrate_get_current();
+ g_autoptr(MigrationParameters) tmp = QAPI_CLONE(MigrationParameters,
+ &s->parameters);
/*
* Convert QTYPE_QNULL and NULL to the empty string (""). Even
@@ -1367,7 +1316,9 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
tls_opt_to_str(¶ms->tls_hostname);
tls_opt_to_str(¶ms->tls_authz);
- migrate_params_test_apply(params, &tmp);
+ if (!migrate_params_merge(tmp, params, errp)) {
+ return;
+ }
/*
* Mark block_bitmap_mapping as present now while we have the
@@ -1377,10 +1328,10 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
migrate_get_current()->has_block_bitmap_mapping = true;
}
- if (migrate_params_check(&tmp, errp)) {
- migrate_params_apply(&tmp);
+ if (migrate_params_check(tmp, errp)) {
+ /* mark all present, so they're all copied */
+ migrate_mark_all_params_present(tmp);
+ migrate_params_apply(tmp);
migrate_post_update_params(params, errp);
}
-
- migrate_tls_opts_free(&tmp);
}
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 15/24] migration: Cleanup hmp_info_migrate_parameters
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (13 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 14/24] migration: Use visitors in migrate_params_test_apply Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-08-13 20:40 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 16/24] migration: Add capabilities into MigrationParameters Fabiano Rosas
` (8 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
Do a cleanup of hmp_info_migrate_parameters() before adding more lines
into it:
- Make sure every parameter asserts that the has_* field is
set. qmp_query_migrate_parameters should have set them all. (except
for block-bitmap-mapping)
- Remove the if (params), qmp_query_migrate_parameters never returns
NULL.
- Add a macro to encapsulate boilerplate.
- Line breaks for legibility.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration-hmp-cmds.c | 277 ++++++++++++++++++---------------
1 file changed, 155 insertions(+), 122 deletions(-)
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index f29bdc12a8..b5618981b3 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -33,6 +33,11 @@
#include "options.h"
#include "migration.h"
+#define PARAM_INFO(_a, _f, _e, _v) do { \
+ assert(_a); \
+ monitor_printf(mon, _f, MigrationParameter_str(_e), _v); \
+ } while (0)
+
static void migration_global_dump(Monitor *mon)
{
MigrationState *ms = migrate_get_current();
@@ -243,133 +248,161 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
MigrationState *s = migrate_get_current();
params = qmp_query_migrate_parameters(NULL);
+ assert(params);
- if (params) {
- monitor_printf(mon, "%s: %" PRIu64 " ms\n",
- MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_INITIAL),
- params->announce_initial);
- monitor_printf(mon, "%s: %" PRIu64 " ms\n",
- MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_MAX),
- params->announce_max);
- monitor_printf(mon, "%s: %" PRIu64 "\n",
- MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_ROUNDS),
- params->announce_rounds);
- monitor_printf(mon, "%s: %" PRIu64 " ms\n",
- MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_STEP),
- params->announce_step);
- assert(params->has_throttle_trigger_threshold);
- monitor_printf(mon, "%s: %u\n",
- MigrationParameter_str(MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD),
- params->throttle_trigger_threshold);
- assert(params->has_cpu_throttle_initial);
- monitor_printf(mon, "%s: %u\n",
- MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL),
- params->cpu_throttle_initial);
- assert(params->has_cpu_throttle_increment);
- monitor_printf(mon, "%s: %u\n",
- MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT),
- params->cpu_throttle_increment);
- assert(params->has_cpu_throttle_tailslow);
- monitor_printf(mon, "%s: %s\n",
- MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW),
- params->cpu_throttle_tailslow ? "on" : "off");
- assert(params->has_max_cpu_throttle);
- monitor_printf(mon, "%s: %u\n",
- MigrationParameter_str(MIGRATION_PARAMETER_MAX_CPU_THROTTLE),
- params->max_cpu_throttle);
- assert(params->tls_creds);
- monitor_printf(mon, "%s: '%s'\n",
- MigrationParameter_str(MIGRATION_PARAMETER_TLS_CREDS),
- params->tls_creds->u.s);
- assert(params->tls_hostname);
- monitor_printf(mon, "%s: '%s'\n",
- MigrationParameter_str(MIGRATION_PARAMETER_TLS_HOSTNAME),
- params->tls_hostname->u.s);
- assert(params->has_max_bandwidth);
- monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n",
- MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH),
- params->max_bandwidth);
- assert(params->has_avail_switchover_bandwidth);
- monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n",
- MigrationParameter_str(MIGRATION_PARAMETER_AVAIL_SWITCHOVER_BANDWIDTH),
- params->avail_switchover_bandwidth);
- assert(params->has_downtime_limit);
- monitor_printf(mon, "%s: %" PRIu64 " ms\n",
- MigrationParameter_str(MIGRATION_PARAMETER_DOWNTIME_LIMIT),
- params->downtime_limit);
- assert(params->has_x_checkpoint_delay);
- monitor_printf(mon, "%s: %u ms\n",
- MigrationParameter_str(MIGRATION_PARAMETER_X_CHECKPOINT_DELAY),
- params->x_checkpoint_delay);
- monitor_printf(mon, "%s: %u\n",
- MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_CHANNELS),
- params->multifd_channels);
- monitor_printf(mon, "%s: %s\n",
- MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_COMPRESSION),
- MultiFDCompression_str(params->multifd_compression));
- assert(params->has_zero_page_detection);
- monitor_printf(mon, "%s: %s\n",
- MigrationParameter_str(MIGRATION_PARAMETER_ZERO_PAGE_DETECTION),
- qapi_enum_lookup(&ZeroPageDetection_lookup,
- params->zero_page_detection));
- monitor_printf(mon, "%s: %" PRIu64 " bytes\n",
- MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE),
- params->xbzrle_cache_size);
- monitor_printf(mon, "%s: %" PRIu64 "\n",
- MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH),
- params->max_postcopy_bandwidth);
- assert(params->tls_authz);
- monitor_printf(mon, "%s: '%s'\n",
- MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ),
- params->tls_authz->u.s);
-
- if (s->has_block_bitmap_mapping) {
- const BitmapMigrationNodeAliasList *bmnal;
-
- monitor_printf(mon, "%s:\n",
- MigrationParameter_str(
- MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING));
-
- for (bmnal = params->block_bitmap_mapping;
- bmnal;
- bmnal = bmnal->next)
- {
- const BitmapMigrationNodeAlias *bmna = bmnal->value;
- const BitmapMigrationBitmapAliasList *bmbal;
-
- monitor_printf(mon, " '%s' -> '%s'\n",
- bmna->node_name, bmna->alias);
-
- for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) {
- const BitmapMigrationBitmapAlias *bmba = bmbal->value;
-
- monitor_printf(mon, " '%s' -> '%s'\n",
- bmba->name, bmba->alias);
- }
+ PARAM_INFO(params->has_announce_initial,
+ "%s: %" PRIu64 " ms\n",
+ MIGRATION_PARAMETER_ANNOUNCE_INITIAL,
+ params->announce_initial);
+
+ PARAM_INFO(params->has_announce_max,
+ "%s: %" PRIu64 " ms\n",
+ MIGRATION_PARAMETER_ANNOUNCE_MAX,
+ params->announce_max);
+
+ PARAM_INFO(params->has_announce_rounds,
+ "%s: %" PRIu64 "\n",
+ MIGRATION_PARAMETER_ANNOUNCE_ROUNDS,
+ params->announce_rounds);
+
+ PARAM_INFO(params->has_announce_step,
+ "%s: %" PRIu64 " ms\n",
+ MIGRATION_PARAMETER_ANNOUNCE_STEP,
+ params->announce_step);
+
+ PARAM_INFO(params->has_throttle_trigger_threshold,
+ "%s: %u\n",
+ MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD,
+ params->throttle_trigger_threshold);
+
+ PARAM_INFO(params->has_cpu_throttle_initial,
+ "%s: %u\n",
+ MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL,
+ params->cpu_throttle_initial);
+
+ PARAM_INFO(params->has_cpu_throttle_increment,
+ "%s: %u\n",
+ MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT,
+ params->cpu_throttle_increment);
+
+ PARAM_INFO(params->has_cpu_throttle_tailslow,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW,
+ params->cpu_throttle_tailslow ? "on" : "off");
+
+ PARAM_INFO(params->has_max_cpu_throttle,
+ "%s: %u\n",
+ MIGRATION_PARAMETER_MAX_CPU_THROTTLE,
+ params->max_cpu_throttle);
+
+ PARAM_INFO(params->tls_creds,
+ "%s: '%s'\n",
+ MIGRATION_PARAMETER_TLS_CREDS,
+ params->tls_creds->u.s);
+
+ PARAM_INFO(params->tls_hostname,
+ "%s: '%s'\n",
+ MIGRATION_PARAMETER_TLS_HOSTNAME,
+ params->tls_hostname->u.s);
+
+ PARAM_INFO(params->has_max_bandwidth,
+ "%s: %" PRIu64 " bytes/second\n",
+ MIGRATION_PARAMETER_MAX_BANDWIDTH,
+ params->max_bandwidth);
+
+ PARAM_INFO(params->has_avail_switchover_bandwidth,
+ "%s: %" PRIu64 " bytes/second\n",
+ MIGRATION_PARAMETER_AVAIL_SWITCHOVER_BANDWIDTH,
+ params->avail_switchover_bandwidth);
+
+ PARAM_INFO(params->has_downtime_limit,
+ "%s: %" PRIu64 " ms\n",
+ MIGRATION_PARAMETER_DOWNTIME_LIMIT,
+ params->downtime_limit);
+
+ PARAM_INFO(params->has_x_checkpoint_delay,
+ "%s: %u ms\n",
+ MIGRATION_PARAMETER_X_CHECKPOINT_DELAY,
+ params->x_checkpoint_delay);
+
+ PARAM_INFO(params->has_multifd_channels,
+ "%s: %u\n",
+ MIGRATION_PARAMETER_MULTIFD_CHANNELS,
+ params->multifd_channels);
+
+ PARAM_INFO(params->has_multifd_compression,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_MULTIFD_COMPRESSION,
+ qapi_enum_lookup(&MultiFDCompression_lookup,
+ params->multifd_compression));
+
+ PARAM_INFO(params->has_zero_page_detection,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_ZERO_PAGE_DETECTION,
+ qapi_enum_lookup(&ZeroPageDetection_lookup,
+ params->zero_page_detection));
+
+ PARAM_INFO(params->has_xbzrle_cache_size,
+ "%s: %" PRIu64 " bytes\n",
+ MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE,
+ params->xbzrle_cache_size);
+
+ PARAM_INFO(params->has_max_postcopy_bandwidth,
+ "%s: %" PRIu64 "\n",
+ MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH,
+ params->max_postcopy_bandwidth);
+
+ PARAM_INFO(params->tls_authz,
+ "%s: '%s'\n",
+ MIGRATION_PARAMETER_TLS_AUTHZ,
+ params->tls_authz->u.s);
+
+ if (s->has_block_bitmap_mapping) {
+ const BitmapMigrationNodeAliasList *bmnal;
+
+ monitor_printf(mon, "%s:\n",
+ MigrationParameter_str(
+ MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING));
+
+ for (bmnal = params->block_bitmap_mapping;
+ bmnal;
+ bmnal = bmnal->next)
+ {
+ const BitmapMigrationNodeAlias *bmna = bmnal->value;
+ const BitmapMigrationBitmapAliasList *bmbal;
+
+ monitor_printf(mon, " '%s' -> '%s'\n",
+ bmna->node_name, bmna->alias);
+
+ for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) {
+ const BitmapMigrationBitmapAlias *bmba = bmbal->value;
+
+ monitor_printf(mon, " '%s' -> '%s'\n",
+ bmba->name, bmba->alias);
}
}
-
- monitor_printf(mon, "%s: %" PRIu64 " ms\n",
- MigrationParameter_str(MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD),
- params->x_vcpu_dirty_limit_period);
-
- monitor_printf(mon, "%s: %" PRIu64 " MB/s\n",
- MigrationParameter_str(MIGRATION_PARAMETER_VCPU_DIRTY_LIMIT),
- params->vcpu_dirty_limit);
-
- assert(params->has_mode);
- monitor_printf(mon, "%s: %s\n",
- MigrationParameter_str(MIGRATION_PARAMETER_MODE),
- qapi_enum_lookup(&MigMode_lookup, params->mode));
-
- if (params->has_direct_io) {
- monitor_printf(mon, "%s: %s\n",
- MigrationParameter_str(
- MIGRATION_PARAMETER_DIRECT_IO),
- params->direct_io ? "on" : "off");
- }
}
+ PARAM_INFO(params->has_x_vcpu_dirty_limit_period,
+ "%s: %" PRIu64 " ms\n",
+ MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD,
+ params->x_vcpu_dirty_limit_period);
+
+ PARAM_INFO(params->has_vcpu_dirty_limit,
+ "%s: %" PRIu64 " MB/s\n",
+ MIGRATION_PARAMETER_VCPU_DIRTY_LIMIT,
+ params->vcpu_dirty_limit);
+
+ PARAM_INFO(params->has_mode,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_MODE,
+ qapi_enum_lookup(&MigMode_lookup, params->mode));
+
+ PARAM_INFO(params->has_direct_io,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_DIRECT_IO,
+ params->direct_io ? "on" : "off");
+
qapi_free_MigrationParameters(params);
}
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 16/24] migration: Add capabilities into MigrationParameters
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (14 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 15/24] migration: Cleanup hmp_info_migrate_parameters Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-07-01 8:25 ` Markus Armbruster
2025-07-04 16:33 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 17/24] migration: Remove s->capabilities Fabiano Rosas
` (7 subsequent siblings)
23 siblings, 2 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Eric Blake
Add capabilities to MigrationParameters. This structure will hold all
migration options. Capabilities will go away in the next patch.
Also add capabilities to MigrationParameter as the enum needs to be
kept in sync with MigrationParameters. This affects the parsing of
migration HMP commands so make the necessary additions there too.
From this point on, both QMP and HMP versions of
migrate-set-parameters and query-migrate-parameters gain the ability
to work with capabilities.
With MigrationParameters now having members for each capability, the
migration capabilities commands (query-migrate-capabilities,
migrate-set-capabilities) will soon be deprecated. Add a set of
helpers to convert between the old MigrationCapability representation
and the new representation as members of MigrationParameters.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration-hmp-cmds.c | 198 +++++++++++++++++++++++++++++++++
migration/migration.c | 8 ++
migration/options.c | 129 +++++++++++++++++++++
migration/options.h | 5 +
qapi/migration.json | 135 +++++++++++++++++++++-
5 files changed, 471 insertions(+), 4 deletions(-)
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index b5618981b3..8615340a6b 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -403,6 +403,116 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
MIGRATION_PARAMETER_DIRECT_IO,
params->direct_io ? "on" : "off");
+ PARAM_INFO(params->has_xbzrle,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_XBZRLE,
+ params->xbzrle ? "on" : "off");
+
+ PARAM_INFO(params->has_rdma_pin_all,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_RDMA_PIN_ALL,
+ params->rdma_pin_all ? "on" : "off");
+
+ PARAM_INFO(params->has_auto_converge,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_AUTO_CONVERGE,
+ params->auto_converge ? "on" : "off");
+
+ PARAM_INFO(params->has_zero_blocks,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_ZERO_BLOCKS,
+ params->zero_blocks ? "on" : "off");
+
+ PARAM_INFO(params->has_events,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_EVENTS,
+ params->events ? "on" : "off");
+
+ PARAM_INFO(params->has_postcopy_ram,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_POSTCOPY_RAM,
+ params->postcopy_ram ? "on" : "off");
+
+ PARAM_INFO(params->has_x_colo,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_X_COLO,
+ params->x_colo ? "on" : "off");
+
+ PARAM_INFO(params->has_release_ram,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_RELEASE_RAM,
+ params->release_ram ? "on" : "off");
+
+ PARAM_INFO(params->has_return_path,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_RETURN_PATH,
+ params->return_path ? "on" : "off");
+
+ PARAM_INFO(params->has_pause_before_switchover,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_PAUSE_BEFORE_SWITCHOVER,
+ params->pause_before_switchover ? "on" : "off");
+
+ PARAM_INFO(params->has_multifd,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_MULTIFD,
+ params->multifd ? "on" : "off");
+
+ PARAM_INFO(params->has_dirty_bitmaps,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_DIRTY_BITMAPS,
+ params->dirty_bitmaps ? "on" : "off");
+
+ PARAM_INFO(params->has_postcopy_blocktime,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_POSTCOPY_BLOCKTIME,
+ params->postcopy_blocktime ? "on" : "off");
+
+ PARAM_INFO(params->has_late_block_activate,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_LATE_BLOCK_ACTIVATE,
+ params->late_block_activate ? "on" : "off");
+
+ PARAM_INFO(params->has_x_ignore_shared,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_X_IGNORE_SHARED,
+ params->x_ignore_shared ? "on" : "off");
+
+ PARAM_INFO(params->has_validate_uuid,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_VALIDATE_UUID,
+ params->validate_uuid ? "on" : "off");
+
+ PARAM_INFO(params->has_background_snapshot,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_BACKGROUND_SNAPSHOT,
+ params->background_snapshot ? "on" : "off");
+
+ PARAM_INFO(params->has_zero_copy_send,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_ZERO_COPY_SEND,
+ params->zero_copy_send ? "on" : "off");
+
+ PARAM_INFO(params->has_postcopy_preempt,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_POSTCOPY_PREEMPT,
+ params->postcopy_preempt ? "on" : "off");
+
+ PARAM_INFO(params->has_switchover_ack,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_SWITCHOVER_ACK,
+ params->switchover_ack ? "on" : "off");
+
+ PARAM_INFO(params->has_dirty_limit,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_DIRTY_LIMIT,
+ params->dirty_limit ? "on" : "off");
+
+ PARAM_INFO(params->has_mapped_ram,
+ "%s: %s\n",
+ MIGRATION_PARAMETER_MAPPED_RAM,
+ params->mapped_ram ? "on" : "off");
+
qapi_free_MigrationParameters(params);
}
@@ -682,6 +792,94 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
p->has_direct_io = true;
visit_type_bool(v, param, &p->direct_io, &err);
break;
+ case MIGRATION_PARAMETER_XBZRLE:
+ p->has_xbzrle = true;
+ visit_type_bool(v, param, &p->xbzrle, &err);
+ break;
+ case MIGRATION_PARAMETER_RDMA_PIN_ALL:
+ p->has_rdma_pin_all = true;
+ visit_type_bool(v, param, &p->rdma_pin_all, &err);
+ break;
+ case MIGRATION_PARAMETER_AUTO_CONVERGE:
+ p->has_auto_converge = true;
+ visit_type_bool(v, param, &p->auto_converge, &err);
+ break;
+ case MIGRATION_PARAMETER_ZERO_BLOCKS:
+ p->has_zero_blocks = true;
+ visit_type_bool(v, param, &p->zero_blocks, &err);
+ break;
+ case MIGRATION_PARAMETER_EVENTS:
+ p->has_events = true;
+ visit_type_bool(v, param, &p->events, &err);
+ break;
+ case MIGRATION_PARAMETER_POSTCOPY_RAM:
+ p->has_postcopy_ram = true;
+ visit_type_bool(v, param, &p->postcopy_ram, &err);
+ break;
+ case MIGRATION_PARAMETER_X_COLO:
+ p->has_x_colo = true;
+ visit_type_bool(v, param, &p->x_colo, &err);
+ break;
+ case MIGRATION_PARAMETER_RELEASE_RAM:
+ p->has_release_ram = true;
+ visit_type_bool(v, param, &p->release_ram, &err);
+ break;
+ case MIGRATION_PARAMETER_RETURN_PATH:
+ p->has_return_path = true;
+ visit_type_bool(v, param, &p->return_path, &err);
+ break;
+ case MIGRATION_PARAMETER_PAUSE_BEFORE_SWITCHOVER:
+ p->has_pause_before_switchover = true;
+ visit_type_bool(v, param, &p->pause_before_switchover, &err);
+ break;
+ case MIGRATION_PARAMETER_MULTIFD:
+ p->has_multifd = true;
+ visit_type_bool(v, param, &p->multifd, &err);
+ break;
+ case MIGRATION_PARAMETER_DIRTY_BITMAPS:
+ p->has_dirty_bitmaps = true;
+ visit_type_bool(v, param, &p->dirty_bitmaps, &err);
+ break;
+ case MIGRATION_PARAMETER_POSTCOPY_BLOCKTIME:
+ p->has_postcopy_blocktime = true;
+ visit_type_bool(v, param, &p->postcopy_blocktime, &err);
+ break;
+ case MIGRATION_PARAMETER_LATE_BLOCK_ACTIVATE:
+ p->has_late_block_activate = true;
+ visit_type_bool(v, param, &p->late_block_activate, &err);
+ break;
+ case MIGRATION_PARAMETER_X_IGNORE_SHARED:
+ p->has_x_ignore_shared = true;
+ visit_type_bool(v, param, &p->x_ignore_shared, &err);
+ break;
+ case MIGRATION_PARAMETER_VALIDATE_UUID:
+ p->has_validate_uuid = true;
+ visit_type_bool(v, param, &p->validate_uuid, &err);
+ break;
+ case MIGRATION_PARAMETER_BACKGROUND_SNAPSHOT:
+ p->has_background_snapshot = true;
+ visit_type_bool(v, param, &p->background_snapshot, &err);
+ break;
+ case MIGRATION_PARAMETER_ZERO_COPY_SEND:
+ p->has_zero_copy_send = true;
+ visit_type_bool(v, param, &p->zero_copy_send, &err);
+ break;
+ case MIGRATION_PARAMETER_POSTCOPY_PREEMPT:
+ p->has_postcopy_preempt = true;
+ visit_type_bool(v, param, &p->postcopy_preempt, &err);
+ break;
+ case MIGRATION_PARAMETER_SWITCHOVER_ACK:
+ p->has_switchover_ack = true;
+ visit_type_bool(v, param, &p->switchover_ack, &err);
+ break;
+ case MIGRATION_PARAMETER_DIRTY_LIMIT:
+ p->has_dirty_limit = true;
+ visit_type_bool(v, param, &p->dirty_limit, &err);
+ break;
+ case MIGRATION_PARAMETER_MAPPED_RAM:
+ p->has_mapped_ram = true;
+ visit_type_bool(v, param, &p->mapped_ram, &err);
+ break;
default:
g_assert_not_reached();
}
diff --git a/migration/migration.c b/migration/migration.c
index 487019dc69..11d9016d14 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -4096,6 +4096,14 @@ static bool migration_object_check(MigrationState *ms, Error **errp)
return false;
}
+ /*
+ * FIXME: Temporarily while -global capabilties are still using
+ * s->capabilities. Will be gone by the end of the series.
+ */
+ for (int i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+ migrate_capability_set_compat(&ms->parameters, i, ms->capabilities[i]);
+ }
+
return migrate_caps_check(old_caps, ms->capabilities, errp);
}
diff --git a/migration/options.c b/migration/options.c
index 695bec5b8f..a4b8d3f1b0 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -685,6 +685,111 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
return true;
}
+static bool *migrate_capability_get_addr(MigrationParameters *params, int i)
+{
+ bool *cap_addr = NULL;
+
+ switch (i) {
+ case MIGRATION_CAPABILITY_XBZRLE:
+ cap_addr = ¶ms->xbzrle;
+ break;
+ case MIGRATION_CAPABILITY_RDMA_PIN_ALL:
+ cap_addr = ¶ms->rdma_pin_all;
+ break;
+ case MIGRATION_CAPABILITY_AUTO_CONVERGE:
+ cap_addr = ¶ms->auto_converge;
+ break;
+ case MIGRATION_CAPABILITY_ZERO_BLOCKS:
+ cap_addr = ¶ms->zero_blocks;
+ break;
+ case MIGRATION_CAPABILITY_EVENTS:
+ cap_addr = ¶ms->events;
+ break;
+ case MIGRATION_CAPABILITY_POSTCOPY_RAM:
+ cap_addr = ¶ms->postcopy_ram;
+ break;
+ case MIGRATION_CAPABILITY_X_COLO:
+ cap_addr = ¶ms->x_colo;
+ break;
+ case MIGRATION_CAPABILITY_RELEASE_RAM:
+ cap_addr = ¶ms->release_ram;
+ break;
+ case MIGRATION_CAPABILITY_RETURN_PATH:
+ cap_addr = ¶ms->return_path;
+ break;
+ case MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER:
+ cap_addr = ¶ms->pause_before_switchover;
+ break;
+ case MIGRATION_CAPABILITY_MULTIFD:
+ cap_addr = ¶ms->multifd;
+ break;
+ case MIGRATION_CAPABILITY_DIRTY_BITMAPS:
+ cap_addr = ¶ms->dirty_bitmaps;
+ break;
+ case MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME:
+ cap_addr = ¶ms->postcopy_blocktime;
+ break;
+ case MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE:
+ cap_addr = ¶ms->late_block_activate;
+ break;
+ case MIGRATION_CAPABILITY_X_IGNORE_SHARED:
+ cap_addr = ¶ms->x_ignore_shared;
+ break;
+ case MIGRATION_CAPABILITY_VALIDATE_UUID:
+ cap_addr = ¶ms->validate_uuid;
+ break;
+ case MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT:
+ cap_addr = ¶ms->background_snapshot;
+ break;
+ case MIGRATION_CAPABILITY_ZERO_COPY_SEND:
+ cap_addr = ¶ms->zero_copy_send;
+ break;
+ case MIGRATION_CAPABILITY_POSTCOPY_PREEMPT:
+ cap_addr = ¶ms->postcopy_preempt;
+ break;
+ case MIGRATION_CAPABILITY_SWITCHOVER_ACK:
+ cap_addr = ¶ms->switchover_ack;
+ break;
+ case MIGRATION_CAPABILITY_DIRTY_LIMIT:
+ cap_addr = ¶ms->dirty_limit;
+ break;
+ case MIGRATION_CAPABILITY_MAPPED_RAM:
+ cap_addr = ¶ms->mapped_ram;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return cap_addr;
+}
+
+/* Compatibility for code that reads capabilities in a loop */
+bool migrate_capability_get_compat(MigrationParameters *params, int i)
+{
+ return *(migrate_capability_get_addr(params, i));
+}
+
+/* Compatibility for code that writes capabilities in a loop */
+void migrate_capability_set_compat(MigrationParameters *params, int i, bool val)
+{
+ *(migrate_capability_get_addr(params, i)) = val;
+}
+
+/*
+ * Set capabilities for compatibility with the old
+ * migrate-set-capabilities command.
+ */
+void migrate_capabilities_set_compat(MigrationParameters *params,
+ MigrationCapabilityStatusList *caps)
+{
+ MigrationCapabilityStatusList *cap;
+
+ for (cap = caps; cap; cap = cap->next) {
+ migrate_capability_set_compat(params, cap->value->capability,
+ cap->value->state);
+ }
+}
+
MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
{
MigrationCapabilityStatusList *head = NULL, **tail = &head;
@@ -726,6 +831,8 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
for (cap = params; cap; cap = cap->next) {
s->capabilities[cap->value->capability] = cap->value->state;
}
+
+ migrate_capabilities_set_compat(&s->parameters, params);
}
/* parameters */
@@ -1014,6 +1121,15 @@ static void migrate_mark_all_params_present(MigrationParameters *p)
&p->has_announce_step, &p->has_block_bitmap_mapping,
&p->has_x_vcpu_dirty_limit_period, &p->has_vcpu_dirty_limit,
&p->has_mode, &p->has_zero_page_detection, &p->has_direct_io,
+ &p->has_xbzrle, &p->has_rdma_pin_all, &p->has_auto_converge,
+ &p->has_zero_blocks, &p->has_events, &p->has_postcopy_ram,
+ &p->has_x_colo, &p->has_release_ram, &p->has_return_path,
+ &p->has_pause_before_switchover, &p->has_multifd, &p->has_dirty_bitmaps,
+ &p->has_postcopy_blocktime, &p->has_late_block_activate,
+ &p->has_x_ignore_shared, &p->has_validate_uuid,
+ &p->has_background_snapshot, &p->has_zero_copy_send,
+ &p->has_postcopy_preempt, &p->has_switchover_ack, &p->has_dirty_limit,
+ &p->has_mapped_ram,
};
len = ARRAY_SIZE(has_fields);
@@ -1316,6 +1432,19 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
tls_opt_to_str(¶ms->tls_hostname);
tls_opt_to_str(¶ms->tls_authz);
+ /*
+ * FIXME: Temporarily while migrate_caps_check is not
+ * converted to look at s->parameters. Will be gone the end of
+ * the series.
+ */
+ bool new_caps[MIGRATION_CAPABILITY__MAX] = { 0 };
+ for (int i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+ new_caps[i] = migrate_capability_get_compat(&s->parameters, i);
+ }
+ if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
+ return;
+ }
+
if (!migrate_params_merge(tmp, params, errp)) {
return;
}
diff --git a/migration/options.h b/migration/options.h
index 999eee6f3b..cac9201a5e 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -92,4 +92,9 @@ ZeroPageDetection migrate_zero_page_detection(void);
bool migrate_params_check(MigrationParameters *params, Error **errp);
void migrate_params_init(MigrationParameters *params);
void migrate_tls_opts_free(MigrationParameters *params);
+bool migrate_capability_get_compat(MigrationParameters *params, int i);
+void migrate_capability_set_compat(MigrationParameters *params, int i,
+ bool val);
+void migrate_capabilities_set_compat(MigrationParameters *params,
+ MigrationCapabilityStatusList *caps);
#endif
diff --git a/qapi/migration.json b/qapi/migration.json
index 40e00fb86e..3d3f5624c5 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -763,7 +763,14 @@
'vcpu-dirty-limit',
'mode',
'zero-page-detection',
- 'direct-io'] }
+ 'direct-io', 'xbzrle', 'rdma-pin-all', 'auto-converge',
+ 'zero-blocks', 'events', 'postcopy-ram', 'x-colo',
+ 'release-ram', 'return-path', 'pause-before-switchover',
+ 'multifd', 'dirty-bitmaps', 'postcopy-blocktime',
+ 'late-block-activate', 'x-ignore-shared',
+ 'validate-uuid', 'background-snapshot',
+ 'zero-copy-send', 'postcopy-preempt',
+ 'switchover-ack', 'dirty-limit', 'mapped-ram' ] }
##
# @migrate-set-parameters:
@@ -934,10 +941,108 @@
# only has effect if the @mapped-ram capability is enabled.
# (Since 9.1)
#
+# @xbzrle: Migration supports xbzrle (Xor Based Zero Run Length
+# Encoding). This feature allows us to minimize migration traffic
+# for certain work loads, by sending compressed difference of the
+# pages
+#
+# @rdma-pin-all: Controls whether or not the entire VM memory
+# footprint is mlock()'d on demand or all at once. Refer to
+# docs/rdma.txt for usage. Disabled by default. (since 2.0)
+#
+# @zero-blocks: During storage migration encode blocks of zeroes
+# efficiently. This essentially saves 1MB of zeroes per block on
+# the wire. Enabling requires source and target VM to support
+# this feature. To enable it is sufficient to enable the
+# capability on the source VM. The feature is disabled by
+# default. (since 1.6)
+#
+# @events: generate events for each migration state change (since 2.4)
+#
+# @auto-converge: If enabled, QEMU will automatically throttle down
+# the guest to speed up convergence of RAM migration. (since 1.6)
+#
+# @postcopy-ram: Start executing on the migration target before all of
+# RAM has been migrated, pulling the remaining pages along as
+# needed. The capacity must have the same setting on both source
+# and target or migration will not even start. NOTE: If the
+# migration fails during postcopy the VM will fail. (since 2.6)
+#
+# @x-colo: If enabled, migration will never end, and the state of the
+# VM on the primary side will be migrated continuously to the VM
+# on secondary side, this process is called COarse-Grain LOck
+# Stepping (COLO) for Non-stop Service. (since 2.8)
+#
+# @release-ram: if enabled, qemu will free the migrated ram pages on
+# the source during postcopy-ram migration. (since 2.9)
+#
+# @return-path: If enabled, migration will use the return path even
+# for precopy. (since 2.10)
+#
+# @pause-before-switchover: Pause outgoing migration before
+# serialising device state and before disabling block IO (since
+# 2.11)
+#
+# @multifd: Use more than one fd for migration (since 4.0)
+#
+# @dirty-bitmaps: If enabled, QEMU will migrate named dirty bitmaps.
+# (since 2.12)
+#
+# @postcopy-blocktime: Calculate downtime for postcopy live migration
+# (since 3.0)
+#
+# @late-block-activate: If enabled, the destination will not activate
+# block devices (and thus take locks) immediately at the end of
+# migration. (since 3.0)
+#
+# @x-ignore-shared: If enabled, QEMU will not migrate shared memory
+# that is accessible on the destination machine. (since 4.0)
+#
+# @validate-uuid: Send the UUID of the source to allow the destination
+# to ensure it is the same. (since 4.2)
+#
+# @background-snapshot: If enabled, the migration stream will be a
+# snapshot of the VM exactly at the point when the migration
+# procedure starts. The VM RAM is saved with running VM.
+# (since 6.0)
+#
+# @zero-copy-send: Controls behavior on sending memory pages on
+# migration. When true, enables a zero-copy mechanism for sending
+# memory pages, if host supports it. Requires that QEMU be
+# permitted to use locked memory for guest RAM pages. (since 7.1)
+#
+# @postcopy-preempt: If enabled, the migration process will allow
+# postcopy requests to preempt precopy stream, so postcopy
+# requests will be handled faster. This is a performance feature
+# and should not affect the correctness of postcopy migration.
+# (since 7.1)
+#
+# @switchover-ack: If enabled, migration will not stop the source VM
+# and complete the migration until an ACK is received from the
+# destination that it's OK to do so. Exactly when this ACK is
+# sent depends on the migrated devices that use this feature. For
+# example, a device can use it to make sure some of its data is
+# sent and loaded in the destination before doing switchover.
+# This can reduce downtime if devices that support this capability
+# are present. 'return-path' capability must be enabled to use
+# it. (since 8.1)
+#
+# @dirty-limit: If enabled, migration will throttle vCPUs as needed to
+# keep their dirty page rate within @vcpu-dirty-limit. This can
+# improve responsiveness of large guests during live migration,
+# and can result in more stable read performance. Requires KVM
+# with accelerator property "dirty-ring-size" set. (Since 8.1)
+#
+# @mapped-ram: Migrate using fixed offsets in the migration file for
+# each RAM page. Requires a migration URI that supports seeking,
+# such as a file. (since 9.0)
+#
# Features:
#
-# @unstable: Members @x-checkpoint-delay and
-# @x-vcpu-dirty-limit-period are experimental.
+# @unstable: Members @x-checkpoint-delay, @x-vcpu-dirty-limit-period,
+# @x-colo and @x-ignore-shared are experimental.
+# @deprecated: Member @zero-blocks is deprecated as being part of
+# block migration which was already removed.
#
# Since: 2.4
##
@@ -972,7 +1077,29 @@
'*vcpu-dirty-limit': 'uint64',
'*mode': 'MigMode',
'*zero-page-detection': 'ZeroPageDetection',
- '*direct-io': 'bool' } }
+ '*direct-io': 'bool',
+ '*xbzrle': 'bool',
+ '*rdma-pin-all': 'bool',
+ '*auto-converge': 'bool',
+ '*zero-blocks': { 'type': 'bool', 'features': [ 'deprecated' ] },
+ '*events': 'bool',
+ '*postcopy-ram': 'bool',
+ '*x-colo': { 'type': 'bool', 'features': [ 'unstable' ] },
+ '*release-ram': 'bool',
+ '*return-path': 'bool',
+ '*pause-before-switchover': 'bool',
+ '*multifd': 'bool',
+ '*dirty-bitmaps': 'bool',
+ '*postcopy-blocktime': 'bool',
+ '*late-block-activate': 'bool',
+ '*x-ignore-shared': { 'type': 'bool', 'features': [ 'unstable' ] },
+ '*validate-uuid': 'bool',
+ '*background-snapshot': 'bool',
+ '*zero-copy-send': 'bool',
+ '*postcopy-preempt': 'bool',
+ '*switchover-ack': 'bool',
+ '*dirty-limit': 'bool',
+ '*mapped-ram': 'bool' } }
##
# @query-migrate-parameters:
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 17/24] migration: Remove s->capabilities
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (15 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 16/24] migration: Add capabilities into MigrationParameters Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-08-13 20:48 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands Fabiano Rosas
` (6 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
Last patch added capabilities to s->parameters. Now we can replace all
instances of s->capabilities with s->parameters:
- The -global properties now get set directly in s->parameters.
- Accessors from options.c now read from s->parameters.
- migrate_caps_check() now takes a MigrationParameters object. The
function is still kept around because migrate-set-capabilities will
still use it.
- The machinery for background-snapshot compatibility check goes
away. We can check each capability by name (if s->parameters.cap ...)
- savevm uses the helper functions introduced in the last patch to do
validation of capabilities found on the migration stream.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration.c | 22 +---
migration/migration.h | 1 -
migration/options.c | 284 ++++++++++++++++++------------------------
migration/options.h | 19 +--
migration/savevm.c | 8 +-
5 files changed, 133 insertions(+), 201 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index 11d9016d14..aa954f5fc7 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -266,9 +266,10 @@ static bool
migration_capabilities_and_transport_compatible(MigrationAddress *addr,
Error **errp)
{
+ MigrationState *s = migrate_get_current();
+
if (addr->transport == MIGRATION_ADDRESS_TYPE_RDMA) {
- return migrate_rdma_caps_check(migrate_get_current()->capabilities,
- errp);
+ return migrate_rdma_caps_check(&s->parameters, errp);
}
return true;
@@ -4089,22 +4090,7 @@ static void migration_instance_init(Object *obj)
*/
static bool migration_object_check(MigrationState *ms, Error **errp)
{
- /* Assuming all off */
- bool old_caps[MIGRATION_CAPABILITY__MAX] = { 0 };
-
- if (!migrate_params_check(&ms->parameters, errp)) {
- return false;
- }
-
- /*
- * FIXME: Temporarily while -global capabilties are still using
- * s->capabilities. Will be gone by the end of the series.
- */
- for (int i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
- migrate_capability_set_compat(&ms->parameters, i, ms->capabilities[i]);
- }
-
- return migrate_caps_check(old_caps, ms->capabilities, errp);
+ return migrate_params_check(&ms->parameters, errp);
}
static const TypeInfo migration_type = {
diff --git a/migration/migration.h b/migration/migration.h
index 84c3007ab8..7d3a607029 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -358,7 +358,6 @@ struct MigrationState {
int64_t downtime_start;
int64_t downtime;
int64_t expected_downtime;
- bool capabilities[MIGRATION_CAPABILITY__MAX];
int64_t setup_time;
/*
diff --git a/migration/options.c b/migration/options.c
index a4b8d3f1b0..90440731d0 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -85,9 +85,6 @@
#define DEFAULT_MIGRATE_ANNOUNCE_ROUNDS 5
#define DEFAULT_MIGRATE_ANNOUNCE_STEP 100
-#define DEFINE_PROP_MIG_CAP(name, x) \
- DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)
-
const PropertyInfo qdev_prop_StrOrNull;
#define DEFINE_PROP_STR_OR_NULL(_name, _state, _field) \
DEFINE_PROP(_name, _state, _field, qdev_prop_StrOrNull, StrOrNull *, \
@@ -188,30 +185,40 @@ const Property migration_properties[] = {
DEFINE_PROP_ZERO_PAGE_DETECTION("zero-page-detection", MigrationState,
parameters.zero_page_detection,
ZERO_PAGE_DETECTION_MULTIFD),
-
- /* Migration capabilities */
- DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
- DEFINE_PROP_MIG_CAP("x-rdma-pin-all", MIGRATION_CAPABILITY_RDMA_PIN_ALL),
- DEFINE_PROP_MIG_CAP("x-auto-converge", MIGRATION_CAPABILITY_AUTO_CONVERGE),
- DEFINE_PROP_MIG_CAP("x-zero-blocks", MIGRATION_CAPABILITY_ZERO_BLOCKS),
- DEFINE_PROP_MIG_CAP("x-events", MIGRATION_CAPABILITY_EVENTS),
- DEFINE_PROP_MIG_CAP("x-postcopy-ram", MIGRATION_CAPABILITY_POSTCOPY_RAM),
- DEFINE_PROP_MIG_CAP("x-postcopy-preempt",
- MIGRATION_CAPABILITY_POSTCOPY_PREEMPT),
- DEFINE_PROP_MIG_CAP("x-colo", MIGRATION_CAPABILITY_X_COLO),
- DEFINE_PROP_MIG_CAP("x-release-ram", MIGRATION_CAPABILITY_RELEASE_RAM),
- DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
- DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD),
- DEFINE_PROP_MIG_CAP("x-background-snapshot",
- MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT),
+ DEFINE_PROP_BOOL("x-xbzrle",
+ MigrationState, parameters.xbzrle, false),
+ DEFINE_PROP_BOOL("x-rdma-pin-all",
+ MigrationState, parameters.rdma_pin_all, false),
+ DEFINE_PROP_BOOL("x-auto-converge",
+ MigrationState, parameters.auto_converge, false),
+ DEFINE_PROP_BOOL("x-zero-blocks",
+ MigrationState, parameters.zero_blocks, false),
+ DEFINE_PROP_BOOL("x-events",
+ MigrationState, parameters.events, false),
+ DEFINE_PROP_BOOL("x-postcopy-ram",
+ MigrationState, parameters.postcopy_ram, false),
+ DEFINE_PROP_BOOL("x-postcopy-preempt",
+ MigrationState, parameters.postcopy_preempt, false),
+ DEFINE_PROP_BOOL("x-colo",
+ MigrationState, parameters.x_colo, false),
+ DEFINE_PROP_BOOL("x-release-ram",
+ MigrationState, parameters.release_ram, false),
+ DEFINE_PROP_BOOL("x-return-path",
+ MigrationState, parameters.return_path, false),
+ DEFINE_PROP_BOOL("x-multifd",
+ MigrationState, parameters.multifd, false),
+ DEFINE_PROP_BOOL("x-background-snapshot",
+ MigrationState, parameters.background_snapshot, false),
#ifdef CONFIG_LINUX
- DEFINE_PROP_MIG_CAP("x-zero-copy-send",
- MIGRATION_CAPABILITY_ZERO_COPY_SEND),
+ DEFINE_PROP_BOOL("x-zero-copy-send",
+ MigrationState, parameters.zero_copy_send, false),
#endif
- DEFINE_PROP_MIG_CAP("x-switchover-ack",
- MIGRATION_CAPABILITY_SWITCHOVER_ACK),
- DEFINE_PROP_MIG_CAP("x-dirty-limit", MIGRATION_CAPABILITY_DIRTY_LIMIT),
- DEFINE_PROP_MIG_CAP("mapped-ram", MIGRATION_CAPABILITY_MAPPED_RAM),
+ DEFINE_PROP_BOOL("x-switchover-ack",
+ MigrationState, parameters.switchover_ack, false),
+ DEFINE_PROP_BOOL("x-dirty-limit",
+ MigrationState, parameters.dirty_limit, false),
+ DEFINE_PROP_BOOL("mapped-ram",
+ MigrationState, parameters.mapped_ram, false),
};
const size_t migration_properties_count = ARRAY_SIZE(migration_properties);
@@ -266,7 +273,7 @@ bool migrate_auto_converge(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_AUTO_CONVERGE];
+ return s->parameters.auto_converge;
}
bool migrate_send_switchover_start(void)
@@ -280,144 +287,142 @@ bool migrate_background_snapshot(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT];
+ return s->parameters.background_snapshot;
}
bool migrate_colo(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_X_COLO];
+ return s->parameters.x_colo;
}
bool migrate_dirty_bitmaps(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_DIRTY_BITMAPS];
+ return s->parameters.dirty_bitmaps;
}
bool migrate_dirty_limit(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_DIRTY_LIMIT];
+ return s->parameters.dirty_limit;
}
bool migrate_events(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_EVENTS];
+ return s->parameters.events;
}
bool migrate_mapped_ram(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_MAPPED_RAM];
+ return s->parameters.mapped_ram;
}
bool migrate_ignore_shared(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_X_IGNORE_SHARED];
+ return s->parameters.x_ignore_shared;
}
bool migrate_late_block_activate(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE];
+ return s->parameters.late_block_activate;
}
bool migrate_multifd(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_MULTIFD];
+ return s->parameters.multifd;
}
bool migrate_pause_before_switchover(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER];
+ return s->parameters.pause_before_switchover;
}
bool migrate_postcopy_blocktime(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME];
+ return s->parameters.postcopy_blocktime;
}
bool migrate_postcopy_preempt(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT];
+ return s->parameters.postcopy_preempt;
}
bool migrate_postcopy_ram(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM];
+ return s->parameters.postcopy_ram;
}
bool migrate_rdma_pin_all(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL];
+ return s->parameters.rdma_pin_all;
}
bool migrate_release_ram(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_RELEASE_RAM];
+ return s->parameters.release_ram;
}
bool migrate_return_path(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_RETURN_PATH];
+ return s->parameters.return_path;
}
bool migrate_switchover_ack(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_SWITCHOVER_ACK];
+ return s->parameters.switchover_ack;
}
bool migrate_validate_uuid(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_VALIDATE_UUID];
+ return s->parameters.validate_uuid;
}
bool migrate_xbzrle(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_XBZRLE];
+ return s->parameters.xbzrle;
}
bool migrate_zero_copy_send(void)
{
MigrationState *s = migrate_get_current();
- return s->capabilities[MIGRATION_CAPABILITY_ZERO_COPY_SEND];
+ return s->parameters.zero_copy_send;
}
-/* pseudo capabilities */
-
bool migrate_multifd_flush_after_each_section(void)
{
MigrationState *s = migrate_get_current();
@@ -462,54 +467,22 @@ WriteTrackingSupport migrate_query_write_tracking(void)
return WT_SUPPORT_COMPATIBLE;
}
-/* Migration capabilities set */
-struct MigrateCapsSet {
- int size; /* Capability set size */
- MigrationCapability caps[]; /* Variadic array of capabilities */
-};
-typedef struct MigrateCapsSet MigrateCapsSet;
-
-/* Define and initialize MigrateCapsSet */
-#define INITIALIZE_MIGRATE_CAPS_SET(_name, ...) \
- MigrateCapsSet _name = { \
- .size = sizeof((int []) { __VA_ARGS__ }) / sizeof(int), \
- .caps = { __VA_ARGS__ } \
- }
-
-/* Background-snapshot compatibility check list */
-static const
-INITIALIZE_MIGRATE_CAPS_SET(check_caps_background_snapshot,
- MIGRATION_CAPABILITY_POSTCOPY_RAM,
- MIGRATION_CAPABILITY_DIRTY_BITMAPS,
- MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME,
- MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE,
- MIGRATION_CAPABILITY_RETURN_PATH,
- MIGRATION_CAPABILITY_MULTIFD,
- MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER,
- MIGRATION_CAPABILITY_AUTO_CONVERGE,
- MIGRATION_CAPABILITY_RELEASE_RAM,
- MIGRATION_CAPABILITY_RDMA_PIN_ALL,
- MIGRATION_CAPABILITY_XBZRLE,
- MIGRATION_CAPABILITY_X_COLO,
- MIGRATION_CAPABILITY_VALIDATE_UUID,
- MIGRATION_CAPABILITY_ZERO_COPY_SEND);
-
static bool migrate_incoming_started(void)
{
return !!migration_incoming_get_current()->transport_data;
}
-bool migrate_rdma_caps_check(bool *caps, Error **errp)
+bool migrate_rdma_caps_check(MigrationParameters *params, Error **errp)
{
- if (caps[MIGRATION_CAPABILITY_XBZRLE]) {
+ if (params->xbzrle) {
error_setg(errp, "RDMA and XBZRLE can't be used together");
return false;
}
- if (caps[MIGRATION_CAPABILITY_MULTIFD]) {
+ if (params->multifd) {
error_setg(errp, "RDMA and multifd can't be used together");
return false;
}
- if (caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
+ if (params->postcopy_ram) {
error_setg(errp, "RDMA and postcopy-ram can't be used together");
return false;
}
@@ -517,26 +490,19 @@ bool migrate_rdma_caps_check(bool *caps, Error **errp)
return true;
}
-/**
- * @migration_caps_check - check capability compatibility
- *
- * @old_caps: old capability list
- * @new_caps: new capability list
- * @errp: set *errp if the check failed, with reason
- *
- * Returns true if check passed, otherwise false.
- */
-bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
+bool migrate_caps_check(MigrationParameters *new, Error **errp)
{
- ERRP_GUARD();
+ MigrationState *s = migrate_get_current();
MigrationIncomingState *mis = migration_incoming_get_current();
+ bool postcopy_already_on = s->parameters.postcopy_ram;
+ ERRP_GUARD();
- if (new_caps[MIGRATION_CAPABILITY_ZERO_BLOCKS]) {
+ if (new->zero_blocks) {
warn_report("zero-blocks capability is deprecated");
}
#ifndef CONFIG_REPLICATION
- if (new_caps[MIGRATION_CAPABILITY_X_COLO]) {
+ if (new->x_colo) {
error_setg(errp, "QEMU compiled without replication module"
" can't enable COLO");
error_append_hint(errp, "Please enable replication before COLO.\n");
@@ -544,27 +510,27 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
}
#endif
- if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
+ if (new->postcopy_ram) {
/* This check is reasonably expensive, so only when it's being
* set the first time, also it's only the destination that needs
* special support.
*/
- if (!old_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] &&
+ if (!postcopy_already_on &&
runstate_check(RUN_STATE_INMIGRATE) &&
!postcopy_ram_supported_by_host(mis, errp)) {
error_prepend(errp, "Postcopy is not supported: ");
return false;
}
- if (new_caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED]) {
+ if (new->x_ignore_shared) {
error_setg(errp, "Postcopy is not compatible with ignore-shared");
return false;
}
}
- if (new_caps[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) {
+ if (new->background_snapshot) {
WriteTrackingSupport wt_support;
- int idx;
+
/*
* Check if 'background-snapshot' capability is supported by
* host kernel and compatible with guest memory configuration.
@@ -580,41 +546,45 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
return false;
}
- /*
- * Check if there are any migration capabilities
- * incompatible with 'background-snapshot'.
- */
- for (idx = 0; idx < check_caps_background_snapshot.size; idx++) {
- int incomp_cap = check_caps_background_snapshot.caps[idx];
- if (new_caps[incomp_cap]) {
- error_setg(errp,
- "Background-snapshot is not compatible with %s",
- MigrationCapability_str(incomp_cap));
- return false;
- }
+ if (new->postcopy_ram ||
+ new->dirty_bitmaps ||
+ new->postcopy_blocktime ||
+ new->late_block_activate ||
+ new->return_path ||
+ new->multifd ||
+ new->pause_before_switchover ||
+ new->auto_converge ||
+ new->release_ram ||
+ new->rdma_pin_all ||
+ new->xbzrle ||
+ new->x_colo ||
+ new->validate_uuid ||
+ new->zero_copy_send) {
+ error_setg(errp,
+ "Background-snapshot is not compatible with "
+ "currently set capabilities");
+ return false;
}
}
#ifdef CONFIG_LINUX
- if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND] &&
- (!new_caps[MIGRATION_CAPABILITY_MULTIFD] ||
- new_caps[MIGRATION_CAPABILITY_XBZRLE] ||
- migrate_multifd_compression() ||
- migrate_tls())) {
+ if (new->zero_copy_send &&
+ (!new->multifd || new->xbzrle ||
+ migrate_multifd_compression() || migrate_tls())) {
error_setg(errp,
"Zero copy only available for non-compressed non-TLS multifd migration");
return false;
}
#else
- if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND]) {
+ if (new->zero_copy_send) {
error_setg(errp,
"Zero copy currently only available on Linux");
return false;
}
#endif
- if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]) {
- if (!new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
+ if (new->postcopy_preempt) {
+ if (!new->postcopy_ram) {
error_setg(errp, "Postcopy preempt requires postcopy-ram");
return false;
}
@@ -626,22 +596,22 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
}
}
- if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
+ if (new->multifd) {
if (!migrate_multifd() && migrate_incoming_started()) {
error_setg(errp, "Multifd must be set before incoming starts");
return false;
}
}
- if (new_caps[MIGRATION_CAPABILITY_SWITCHOVER_ACK]) {
- if (!new_caps[MIGRATION_CAPABILITY_RETURN_PATH]) {
+ if (new->switchover_ack) {
+ if (!new->return_path) {
error_setg(errp, "Capability 'switchover-ack' requires capability "
"'return-path'");
return false;
}
}
- if (new_caps[MIGRATION_CAPABILITY_DIRTY_LIMIT]) {
- if (new_caps[MIGRATION_CAPABILITY_AUTO_CONVERGE]) {
+ if (new->dirty_limit) {
+ if (new->auto_converge) {
error_setg(errp, "dirty-limit conflicts with auto-converge"
" either of then available currently");
return false;
@@ -654,21 +624,21 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
}
}
- if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
- if (new_caps[MIGRATION_CAPABILITY_XBZRLE]) {
+ if (new->multifd) {
+ if (new->xbzrle) {
error_setg(errp, "Multifd is not compatible with xbzrle");
return false;
}
}
- if (new_caps[MIGRATION_CAPABILITY_MAPPED_RAM]) {
- if (new_caps[MIGRATION_CAPABILITY_XBZRLE]) {
+ if (new->mapped_ram) {
+ if (new->xbzrle) {
error_setg(errp,
"Mapped-ram migration is incompatible with xbzrle");
return false;
}
- if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
+ if (new->postcopy_ram) {
error_setg(errp,
"Mapped-ram migration is incompatible with postcopy");
return false;
@@ -679,7 +649,7 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
* On destination side, check the cases that capability is being set
* after incoming thread has started.
*/
- if (migrate_rdma() && !migrate_rdma_caps_check(new_caps, errp)) {
+ if (migrate_rdma() && !migrate_rdma_caps_check(new, errp)) {
return false;
}
return true;
@@ -800,39 +770,37 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
caps = g_malloc0(sizeof(*caps));
caps->capability = i;
- caps->state = s->capabilities[i];
+ caps->state = migrate_capability_get_compat(&s->parameters, i);
QAPI_LIST_APPEND(tail, caps);
}
return head;
}
-void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
+void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *capabilities,
Error **errp)
{
MigrationState *s = migrate_get_current();
- MigrationCapabilityStatusList *cap;
- bool new_caps[MIGRATION_CAPABILITY__MAX];
+ g_autoptr(MigrationParameters) params = NULL;
if (migration_is_running() || migration_in_colo_state()) {
error_setg(errp, "There's a migration process in progress");
return;
}
- memcpy(new_caps, s->capabilities, sizeof(new_caps));
- for (cap = params; cap; cap = cap->next) {
- new_caps[cap->value->capability] = cap->value->state;
- }
+ /*
+ * Capabilities validation needs to first copy from s->parameters
+ * in case the incoming capabilities have a capability that
+ * conflicts with another that's already set.
+ */
+ params = QAPI_CLONE(MigrationParameters, &s->parameters);
+ migrate_capabilities_set_compat(params, capabilities);
- if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
+ if (!migrate_caps_check(params, errp)) {
return;
}
- for (cap = params; cap; cap = cap->next) {
- s->capabilities[cap->value->capability] = cap->value->state;
- }
-
- migrate_capabilities_set_compat(&s->parameters, params);
+ migrate_capabilities_set_compat(&s->parameters, capabilities);
}
/* parameters */
@@ -893,9 +861,8 @@ bool migrate_direct_io(void)
* isolated to the main migration thread while multifd channels
* process the aligned data with O_DIRECT enabled.
*/
- return s->parameters.direct_io &&
- s->capabilities[MIGRATION_CAPABILITY_MAPPED_RAM] &&
- s->capabilities[MIGRATION_CAPABILITY_MULTIFD];
+ return s->parameters.direct_io && s->parameters.mapped_ram &&
+ s->parameters.multifd;
}
uint64_t migrate_downtime_limit(void)
@@ -1340,6 +1307,10 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
return false;
}
+ if (!migrate_caps_check(params, errp)) {
+ return false;
+ }
+
return true;
}
@@ -1432,19 +1403,6 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
tls_opt_to_str(¶ms->tls_hostname);
tls_opt_to_str(¶ms->tls_authz);
- /*
- * FIXME: Temporarily while migrate_caps_check is not
- * converted to look at s->parameters. Will be gone the end of
- * the series.
- */
- bool new_caps[MIGRATION_CAPABILITY__MAX] = { 0 };
- for (int i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
- new_caps[i] = migrate_capability_get_compat(&s->parameters, i);
- }
- if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
- return;
- }
-
if (!migrate_params_merge(tmp, params, errp)) {
return;
}
diff --git a/migration/options.h b/migration/options.h
index cac9201a5e..1ce38c30fb 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -1,5 +1,5 @@
/*
- * QEMU migration capabilities
+ * QEMU migration options
*
* Copyright (c) 2012-2023 Red Hat Inc
*
@@ -23,8 +23,6 @@
extern const Property migration_properties[];
extern const size_t migration_properties_count;
-/* capabilities */
-
bool migrate_auto_converge(void);
bool migrate_colo(void);
bool migrate_dirty_bitmaps(void);
@@ -43,22 +41,12 @@ bool migrate_validate_uuid(void);
bool migrate_xbzrle(void);
bool migrate_zero_copy_send(void);
-/*
- * pseudo capabilities
- *
- * These are functions that are used in a similar way to capabilities
- * check, but they are not a capability.
- */
-
bool migrate_multifd_flush_after_each_section(void);
bool migrate_postcopy(void);
bool migrate_rdma(void);
bool migrate_tls(void);
-/* capabilities helpers */
-
-bool migrate_rdma_caps_check(bool *caps, Error **errp);
-bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp);
+bool migrate_rdma_caps_check(MigrationParameters *config, Error **errp);
/* parameters */
@@ -87,8 +75,6 @@ const char *migrate_tls_hostname(void);
uint64_t migrate_xbzrle_cache_size(void);
ZeroPageDetection migrate_zero_page_detection(void);
-/* parameters helpers */
-
bool migrate_params_check(MigrationParameters *params, Error **errp);
void migrate_params_init(MigrationParameters *params);
void migrate_tls_opts_free(MigrationParameters *params);
@@ -97,4 +83,5 @@ void migrate_capability_set_compat(MigrationParameters *params, int i,
bool val);
void migrate_capabilities_set_compat(MigrationParameters *params,
MigrationCapabilityStatusList *caps);
+bool migrate_caps_check(MigrationParameters *new, Error **errp);
#endif
diff --git a/migration/savevm.c b/migration/savevm.c
index bb04a4520d..b51ff54624 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -291,7 +291,8 @@ static uint32_t get_validatable_capabilities_count(void)
uint32_t result = 0;
int i;
for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
- if (should_validate_capability(i) && s->capabilities[i]) {
+ if (should_validate_capability(i) &&
+ migrate_capability_get_compat(&s->parameters, i)) {
result++;
}
}
@@ -313,7 +314,8 @@ static int configuration_pre_save(void *opaque)
state->capabilities = g_renew(MigrationCapability, state->capabilities,
state->caps_count);
for (i = j = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
- if (should_validate_capability(i) && s->capabilities[i]) {
+ if (should_validate_capability(i) &&
+ migrate_capability_get_compat(&s->parameters, i)) {
state->capabilities[j++] = i;
}
}
@@ -363,7 +365,7 @@ static bool configuration_validate_capabilities(SaveState *state)
continue;
}
source_state = test_bit(i, source_caps_bm);
- target_state = s->capabilities[i];
+ target_state = migrate_capability_get_compat(&s->parameters, i);
if (source_state != target_state) {
error_report("Capability %s is %s, but received capability is %s",
MigrationCapability_str(i),
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (16 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 17/24] migration: Remove s->capabilities Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-07-01 8:30 ` Markus Armbruster
` (2 more replies)
2025-06-30 19:59 ` [PATCH v2 19/24] migration: Store the initial values used for s->parameters Fabiano Rosas
` (5 subsequent siblings)
23 siblings, 3 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, devel, Eric Blake
The concept of capabilities is being merged into the concept of
parameters. From now on, the commands that handle capabilities are
deprecated in favor of the commands that handle parameters.
Affected commands:
- migrate-set-capabilities
- query-migrate-capabilities
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
docs/about/deprecated.rst | 12 ++++++++++++
migration/migration-hmp-cmds.c | 6 ++++++
qapi/migration.json | 16 ++++++++++++++--
3 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index 42037131de..15474833ea 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -605,3 +605,15 @@ command documentation for details on the ``fdset`` usage.
The ``zero-blocks`` capability was part of the block migration which
doesn't exist anymore since it was removed in QEMU v9.1.
+
+``migrate-set-capabilities`` command (since 10.1)
+'''''''''''''''''''''''''''''''''''''''''''''''''
+
+This command was deprecated. Use ``migrate-set-parameters`` instead
+which now supports setting capabilities.
+
+``query-migrate-capabilities`` command (since 10.1)
+'''''''''''''''''''''''''''''''''''''''''''''''''''
+
+This command was deprecated. Use ``query-migrate-parameters`` instead
+which now supports querying capabilities.
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 8615340a6b..7f234d5aa8 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -229,6 +229,9 @@ void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict)
{
MigrationCapabilityStatusList *caps, *cap;
+ warn_report("info migrate_capabilities is deprecated;"
+ " use info migrate_parameters instead");
+
caps = qmp_query_migrate_capabilities(NULL);
if (caps) {
@@ -616,6 +619,9 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
MigrationCapabilityStatus *value;
int val;
+ warn_report("migrate_set_capability is deprecated;"
+ " use migrate_set_parameter instead");
+
val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
if (val < 0) {
goto end;
diff --git a/qapi/migration.json b/qapi/migration.json
index 3d3f5624c5..c5e6ea1a2d 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -521,6 +521,11 @@
#
# @capabilities: json array of capability modifications to make
#
+# Features:
+#
+# @deprecated: This command is deprecated in favor of
+# migrate-set-parameters.
+#
# Since: 1.2
#
# .. qmp-example::
@@ -530,7 +535,8 @@
# <- { "return": {} }
##
{ 'command': 'migrate-set-capabilities',
- 'data': { 'capabilities': ['MigrationCapabilityStatus'] } }
+ 'data': { 'capabilities': ['MigrationCapabilityStatus'] },
+ 'features': ['deprecated'] }
##
# @query-migrate-capabilities:
@@ -539,6 +545,11 @@
#
# Returns: @MigrationCapabilityStatus
#
+# Features:
+#
+# @deprecated: This command is deprecated in favor of
+# query-migrate-parameters.
+#
# Since: 1.2
#
# .. qmp-example::
@@ -554,7 +565,8 @@
# {"state": false, "capability": "x-colo"}
# ]}
##
-{ 'command': 'query-migrate-capabilities', 'returns': ['MigrationCapabilityStatus']}
+{ 'command': 'query-migrate-capabilities', 'returns': ['MigrationCapabilityStatus'],
+ 'features': ['deprecated'] }
##
# @MultiFDCompression:
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 19/24] migration: Store the initial values used for s->parameters
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (17 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-08-13 21:09 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 20/24] migration: Allow migrate commands to provide the migration config Fabiano Rosas
` (4 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu
Each migration parameters has a default value, store them for later
use in resetting s->parameters. Values overridden via the command line
with the debugging option -global migration.<param> will be included.
Make the structure const and change the appropriate signatures to make
sure its values are not changed by accident. Some functions take two
MigrationParameters pointers and it's easy to confuse them.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration.c | 3 +++
migration/migration.h | 6 ++++++
migration/options.c | 21 +++++++++++++++++----
migration/options.h | 7 ++++---
4 files changed, 30 insertions(+), 7 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index aa954f5fc7..13b70dbb94 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -335,6 +335,7 @@ void migration_object_init(void)
current_incoming->exit_on_error = INMIGRATE_DEFAULT_EXIT_ON_ERROR;
migration_object_check(current_migration, &error_fatal);
+ migrate_params_store_defaults(current_migration);
ram_mig_init();
dirty_bitmap_mig_init();
@@ -4051,6 +4052,8 @@ static void migration_instance_finalize(Object *obj)
MigrationState *ms = MIGRATION_OBJ(obj);
qapi_free_BitmapMigrationNodeAliasList(ms->parameters.block_bitmap_mapping);
+ /* drop const */
+ qapi_free_MigrationParameters((MigrationParameters *)ms->initial_params);
qemu_mutex_destroy(&ms->error_mutex);
qemu_mutex_destroy(&ms->qemu_file_lock);
qemu_sem_destroy(&ms->wait_unplug_sem);
diff --git a/migration/migration.h b/migration/migration.h
index 7d3a607029..b1107b4e30 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -319,6 +319,12 @@ struct MigrationState {
/* params from 'migrate-set-parameters' */
MigrationParameters parameters;
+ /*
+ * This holds the values initially set in the 'parameters' struct
+ * above. Any values overriden by -global migration.<parameter>
+ * will be reflected here as well.
+ */
+ const MigrationParameters *initial_params;
MigrationStatus state;
diff --git a/migration/options.c b/migration/options.c
index 90440731d0..2f6ccefa21 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -472,7 +472,7 @@ static bool migrate_incoming_started(void)
return !!migration_incoming_get_current()->transport_data;
}
-bool migrate_rdma_caps_check(MigrationParameters *params, Error **errp)
+bool migrate_rdma_caps_check(const MigrationParameters *params, Error **errp)
{
if (params->xbzrle) {
error_setg(errp, "RDMA and XBZRLE can't be used together");
@@ -490,7 +490,7 @@ bool migrate_rdma_caps_check(MigrationParameters *params, Error **errp)
return true;
}
-bool migrate_caps_check(MigrationParameters *new, Error **errp)
+bool migrate_caps_check(const MigrationParameters *new, Error **errp)
{
MigrationState *s = migrate_get_current();
MigrationIncomingState *mis = migration_incoming_get_current();
@@ -1161,7 +1161,7 @@ static void migrate_post_update_params(MigrationParameters *new, Error **errp)
* Check whether the parameters are valid. Error will be put into errp
* (if provided). Return true if valid, otherwise false.
*/
-bool migrate_params_check(MigrationParameters *params, Error **errp)
+bool migrate_params_check(const MigrationParameters *params, Error **errp)
{
ERRP_GUARD();
@@ -1373,7 +1373,7 @@ out:
return ok;
}
-static void migrate_params_apply(MigrationParameters *params)
+static void migrate_params_apply(const MigrationParameters *params)
{
MigrationState *s = migrate_get_current();
MigrationParameters *cur = &s->parameters;
@@ -1385,6 +1385,19 @@ static void migrate_params_apply(MigrationParameters *params)
QAPI_CLONE_MEMBERS(MigrationParameters, cur, params);
}
+void migrate_params_store_defaults(MigrationState *s)
+{
+ assert(!s->initial_params);
+
+ /*
+ * The defaults set for each qdev property in migration_properties
+ * will be stored as the default values for each migration
+ * parameter. For debugging, using -global can override the
+ * defaults.
+ */
+ s->initial_params = QAPI_CLONE(MigrationParameters, &s->parameters);
+}
+
void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
{
MigrationState *s = migrate_get_current();
diff --git a/migration/options.h b/migration/options.h
index 1ce38c30fb..91154c4322 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -46,7 +46,7 @@ bool migrate_postcopy(void);
bool migrate_rdma(void);
bool migrate_tls(void);
-bool migrate_rdma_caps_check(MigrationParameters *config, Error **errp);
+bool migrate_rdma_caps_check(const MigrationParameters *config, Error **errp);
/* parameters */
@@ -75,7 +75,7 @@ const char *migrate_tls_hostname(void);
uint64_t migrate_xbzrle_cache_size(void);
ZeroPageDetection migrate_zero_page_detection(void);
-bool migrate_params_check(MigrationParameters *params, Error **errp);
+bool migrate_params_check(const MigrationParameters *params, Error **errp);
void migrate_params_init(MigrationParameters *params);
void migrate_tls_opts_free(MigrationParameters *params);
bool migrate_capability_get_compat(MigrationParameters *params, int i);
@@ -83,5 +83,6 @@ void migrate_capability_set_compat(MigrationParameters *params, int i,
bool val);
void migrate_capabilities_set_compat(MigrationParameters *params,
MigrationCapabilityStatusList *caps);
-bool migrate_caps_check(MigrationParameters *new, Error **errp);
+bool migrate_caps_check(const MigrationParameters *const new, Error **errp);
+void migrate_params_store_defaults(MigrationState *s);
#endif
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 20/24] migration: Allow migrate commands to provide the migration config
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (18 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 19/24] migration: Store the initial values used for s->parameters Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-07-01 8:35 ` Markus Armbruster
2025-08-13 21:27 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 21/24] tests/qtest/migration: Take reference when passing %p to qtest_qmp Fabiano Rosas
` (3 subsequent siblings)
23 siblings, 2 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Eric Blake, Paolo Bonzini
Allow the migrate and migrate_incoming commands to pass the migration
configuration options all at once, dispensing the use of
migrate-set-parameters and migrate-set-capabilities.
The motivation of this is to simplify the interface with the
management layer and avoid the usage of several command invocations to
configure a migration. It also avoids stale parameters from a previous
migration to influence the current migration.
The options that are changed during the migration can still be set
with the existing commands.
The order of precedence is:
'config' argument > -global migration cmdline > migrate-set-parameters
> defaults (migration_properties)
I.e. the config takes precedence over all, values not present in the
config assume the default values. The -global migration command line
option allows the defaults to be overridden for debug.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration-hmp-cmds.c | 5 +++--
migration/migration.c | 28 +++++++++++++++++++++++++---
migration/options.c | 19 +++++++++++++++++++
migration/options.h | 4 +++-
qapi/migration.json | 16 ++++++++++++++++
system/vl.c | 3 ++-
6 files changed, 68 insertions(+), 7 deletions(-)
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 7f234d5aa8..2075d6c6e5 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -583,7 +583,7 @@ void hmp_migrate_incoming(Monitor *mon, const QDict *qdict)
}
QAPI_LIST_PREPEND(caps, g_steal_pointer(&channel));
- qmp_migrate_incoming(NULL, true, caps, true, false, &err);
+ qmp_migrate_incoming(NULL, true, caps, NULL, true, false, &err);
qapi_free_MigrationChannelList(caps);
end:
@@ -960,7 +960,8 @@ void hmp_migrate(Monitor *mon, const QDict *qdict)
}
QAPI_LIST_PREPEND(caps, g_steal_pointer(&channel));
- qmp_migrate(NULL, true, caps, false, false, true, resume, &err);
+ qmp_migrate(NULL, true, caps, NULL, false, false, true, resume,
+ &err);
if (hmp_handle_error(mon, err)) {
return;
}
diff --git a/migration/migration.c b/migration/migration.c
index 13b70dbb94..42a2a6e8f2 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1917,13 +1917,24 @@ void migrate_del_blocker(Error **reasonp)
void qmp_migrate_incoming(const char *uri, bool has_channels,
MigrationChannelList *channels,
- bool has_exit_on_error, bool exit_on_error,
- Error **errp)
+ MigrationParameters *config, bool has_exit_on_error,
+ bool exit_on_error, Error **errp)
{
Error *local_err = NULL;
static bool once = true;
+ MigrationState *s = migrate_get_current();
MigrationIncomingState *mis = migration_incoming_get_current();
+ if (config) {
+ /*
+ * If a config was provided, all options set previously by
+ * migrate-set-parameters get ignored.
+ */
+ if (!migrate_params_override(s, config, errp)) {
+ return;
+ }
+ }
+
if (!once) {
error_setg(errp, "The incoming migration has already been started");
return;
@@ -2183,7 +2194,8 @@ static gboolean qmp_migrate_finish_cb(QIOChannel *channel,
}
void qmp_migrate(const char *uri, bool has_channels,
- MigrationChannelList *channels, bool has_detach, bool detach,
+ MigrationChannelList *channels,
+ bool has_detach, bool detach, MigrationParameters *config,
bool has_resume, bool resume, Error **errp)
{
bool resume_requested;
@@ -2194,6 +2206,16 @@ void qmp_migrate(const char *uri, bool has_channels,
MigrationChannel *channelv[MIGRATION_CHANNEL_TYPE__MAX] = { NULL };
MigrationChannel *cpr_channel = NULL;
+ if (config) {
+ /*
+ * If a config was provided, all options set previously by
+ * migrate-set-parameters get ignored.
+ */
+ if (!migrate_params_override(s, config, errp)) {
+ return;
+ }
+ }
+
/*
* Having preliminary checks for uri and channel
*/
diff --git a/migration/options.c b/migration/options.c
index 2f6ccefa21..0f6d021093 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1398,6 +1398,25 @@ void migrate_params_store_defaults(MigrationState *s)
s->initial_params = QAPI_CLONE(MigrationParameters, &s->parameters);
}
+bool migrate_params_override(MigrationState *s, MigrationParameters *new,
+ Error **errp)
+{
+ ERRP_GUARD();
+
+ assert(bql_locked());
+
+ /* reset to initial parameters */
+ migrate_params_apply(s->initial_params);
+
+ /* apply the new ones on top */
+ qmp_migrate_set_parameters(new, errp);
+ if (*errp) {
+ return false;
+ }
+
+ return true;
+}
+
void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
{
MigrationState *s = migrate_get_current();
diff --git a/migration/options.h b/migration/options.h
index 91154c4322..fa56c977a6 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -83,6 +83,8 @@ void migrate_capability_set_compat(MigrationParameters *params, int i,
bool val);
void migrate_capabilities_set_compat(MigrationParameters *params,
MigrationCapabilityStatusList *caps);
-bool migrate_caps_check(const MigrationParameters *const new, Error **errp);
+bool migrate_caps_check(const MigrationParameters *new, Error **errp);
void migrate_params_store_defaults(MigrationState *s);
+bool migrate_params_override(MigrationState *s, MigrationParameters *new,
+ Error **errp);
#endif
diff --git a/qapi/migration.json b/qapi/migration.json
index c5e6ea1a2d..11b7d7ebec 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1456,6 +1456,13 @@
#
# @resume: resume one paused migration, default "off". (since 3.0)
#
+# @config: migration configuration options, previously set via
+# @migrate-set-parameters and @migrate-set-capabilities. Setting
+# this argument causes all migration configuration options
+# previously set via @migrate-set-parameters to be ignored.
+# Configuration options not set will assume their default
+# values. (since 10.1)
+#
# Features:
#
# @deprecated: Argument @detach is deprecated.
@@ -1520,6 +1527,7 @@
'data': {'*uri': 'str',
'*channels': [ 'MigrationChannel' ],
'*detach': { 'type': 'bool', 'features': [ 'deprecated' ] },
+ '*config': 'MigrationParameters',
'*resume': 'bool' } }
##
@@ -1539,6 +1547,13 @@
# error details could be retrieved with query-migrate.
# (since 9.1)
#
+# @config: migration configuration options, previously set via
+# @migrate-set-parameters and @migrate-set-capabilities. Setting
+# this argument causes all migration configuration options
+# previously set via @migrate-set-parameters to be ignored.
+# Configuration options not set will assume their default
+# values. (since 10.1)
+#
# Since: 2.3
#
# .. admonition:: Notes
@@ -1592,6 +1607,7 @@
{ 'command': 'migrate-incoming',
'data': {'*uri': 'str',
'*channels': [ 'MigrationChannel' ],
+ '*config': 'MigrationParameters',
'*exit-on-error': 'bool' } }
##
diff --git a/system/vl.c b/system/vl.c
index 3b7057e6c6..b29fd24d08 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -2823,7 +2823,8 @@ void qmp_x_exit_preconfig(Error **errp)
g_new0(MigrationChannelList, 1);
channels->value = incoming_channels[MIGRATION_CHANNEL_TYPE_MAIN];
- qmp_migrate_incoming(NULL, true, channels, true, true, &local_err);
+ qmp_migrate_incoming(NULL, true, channels, NULL, true, true,
+ &local_err);
if (local_err) {
error_reportf_err(local_err, "-incoming %s: ", incoming);
exit(1);
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 21/24] tests/qtest/migration: Take reference when passing %p to qtest_qmp
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (19 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 20/24] migration: Allow migrate commands to provide the migration config Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-08-13 22:22 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 22/24] tests/qtest/migration: Adapt the capabilities helper to take a config Fabiano Rosas
` (2 subsequent siblings)
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini
The documentation of qobject_from_jsonv() states that it takes
ownership of any %p arguments passed in.
Next patches will add config-passing to the tests, so take an extra
reference in the migrate_qmp* functions to ensure the config is not
freed from under us.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
tests/qtest/migration/migration-qmp.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
index fb59741b2c..d82ac8c750 100644
--- a/tests/qtest/migration/migration-qmp.c
+++ b/tests/qtest/migration/migration-qmp.c
@@ -97,7 +97,8 @@ void migrate_qmp_fail(QTestState *who, const char *uri,
}
err = qtest_qmp_assert_failure_ref(
- who, "{ 'execute': 'migrate', 'arguments': %p}", args);
+ who, "{ 'execute': 'migrate', 'arguments': %p}",
+ qdict_clone_shallow(args));
g_assert(qdict_haskey(err, "desc"));
@@ -136,7 +137,8 @@ void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
}
qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate', 'arguments': %p}", args);
+ "{ 'execute': 'migrate', 'arguments': %p}",
+ qdict_clone_shallow(args));
}
void migrate_set_capability(QTestState *who, const char *capability,
@@ -174,7 +176,7 @@ void migrate_incoming_qmp(QTestState *to, const char *uri, QObject *channels,
migrate_set_capability(to, "events", true);
rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
- args);
+ qdict_clone_shallow(args));
if (!qdict_haskey(rsp, "return")) {
g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true);
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 22/24] tests/qtest/migration: Adapt the capabilities helper to take a config
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (20 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 21/24] tests/qtest/migration: Take reference when passing %p to qtest_qmp Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-08-14 14:02 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 23/24] tests/qtest/migration: Adapt convergence routines to config Fabiano Rosas
2025-06-30 19:59 ` [PATCH v2 24/24] tests/qtest/migration: Pass the migration config to file tests Fabiano Rosas
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini
Allow migrate_start_set_capabilities() to set the config object
instead of setting the capabilities via calls to
migrate-set-capabilities.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
tests/qtest/migration/framework.c | 31 +++++++++++++++++++++++++++++++
tests/qtest/migration/framework.h | 1 +
2 files changed, 32 insertions(+)
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 407c9023c0..9ff5576328 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -211,6 +211,37 @@ static QList *migrate_start_get_qmp_capabilities(const MigrateStart *args)
static void migrate_start_set_capabilities(QTestState *from, QTestState *to,
MigrateStart *args)
{
+ if (args->config) {
+ const char *cap_multifd;
+ bool multifd;
+
+ for (uint8_t i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+ const char *cap = MigrationCapability_lookup.array[i];
+
+ if (!args->caps[i]) {
+ continue;
+ }
+
+ qdict_put_bool(args->config, cap, true);
+ }
+
+ if (!args->defer_target_connect) {
+ qdict_put_bool(args->config, "events", true);
+ }
+
+ cap_multifd = MigrationCapability_str(MIGRATION_CAPABILITY_MULTIFD);
+ multifd = qdict_get_try_bool(args->config, cap_multifd, false);
+
+ if (multifd) {
+ qdict_put_int(args->config, "multifd-channels",
+ MULTIFD_TEST_CHANNELS);
+ qdict_put_int(args->config, "multifd-channels",
+ MULTIFD_TEST_CHANNELS);
+ }
+
+ return;
+ }
+
/*
* MigrationCapability_lookup and MIGRATION_CAPABILITY_ constants
* are from qapi-types-migration.h.
diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
index 01e425e64e..9b281d6757 100644
--- a/tests/qtest/migration/framework.h
+++ b/tests/qtest/migration/framework.h
@@ -128,6 +128,7 @@ typedef struct {
* migration_set_capabilities().
*/
bool caps[MIGRATION_CAPABILITY__MAX];
+ QDict *config;
} MigrateStart;
typedef enum PostcopyRecoveryFailStage {
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 23/24] tests/qtest/migration: Adapt convergence routines to config
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (21 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 22/24] tests/qtest/migration: Adapt the capabilities helper to take a config Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-06-30 19:59 ` [PATCH v2 24/24] tests/qtest/migration: Pass the migration config to file tests Fabiano Rosas
23 siblings, 0 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini
Adapt the convergence routines migrate_ensure_[non_]converge to
receive a config argument and set the convergence parameters in it
instead of using migrate-set-parameters.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
tests/qtest/migration/framework.c | 10 +++++-----
tests/qtest/migration/migration-qmp.c | 22 ++++++++++++++++------
tests/qtest/migration/migration-qmp.h | 4 ++--
tests/qtest/migration/misc-tests.c | 4 ++--
tests/qtest/migration/precopy-tests.c | 22 +++++++++++-----------
5 files changed, 36 insertions(+), 26 deletions(-)
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 9ff5576328..5025299d6a 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -513,7 +513,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
args->postcopy_data = args->start_hook(from, to);
}
- migrate_ensure_non_converge(from);
+ migrate_ensure_non_converge(from, args->start.config);
migrate_prepare_for_dirty_mem(from);
qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
" 'arguments': { "
@@ -791,7 +791,7 @@ void test_precopy_common(MigrateCommon *args)
}
if (args->live) {
- migrate_ensure_non_converge(from);
+ migrate_ensure_non_converge(from, args->start.config);
migrate_prepare_for_dirty_mem(from);
} else {
/*
@@ -803,7 +803,7 @@ void test_precopy_common(MigrateCommon *args)
if (args->result == MIG_TEST_SUCCEED) {
qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
wait_for_stop(from, &src_state);
- migrate_ensure_converge(from);
+ migrate_ensure_converge(from, args->start.config);
}
}
@@ -862,7 +862,7 @@ void test_precopy_common(MigrateCommon *args)
}
migrate_wait_for_dirty_mem(from, to);
- migrate_ensure_converge(from);
+ migrate_ensure_converge(from, args->start.config);
/*
* We do this first, as it has a timeout to stop us
@@ -965,7 +965,7 @@ void test_file_common(MigrateCommon *args, bool stop_src)
data_hook = args->start_hook(from, to);
}
- migrate_ensure_converge(from);
+ migrate_ensure_converge(from, args->start.config);
wait_for_serial("src_serial");
if (stop_src) {
diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
index d82ac8c750..8918ce87d8 100644
--- a/tests/qtest/migration/migration-qmp.c
+++ b/tests/qtest/migration/migration-qmp.c
@@ -471,18 +471,28 @@ void migrate_set_parameter_bool(QTestState *who, const char *parameter,
migrate_check_parameter_bool(who, parameter, value);
}
-void migrate_ensure_non_converge(QTestState *who)
+void migrate_ensure_non_converge(QTestState *who, QDict *config)
{
/* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
- migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
- migrate_set_parameter_int(who, "downtime-limit", 1);
+ if (config) {
+ qdict_put_int(config, "max-bandwidth", 3 * 1000 * 1000);
+ qdict_put_int(config, "downtime-limit", 1);
+ } else {
+ migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
+ migrate_set_parameter_int(who, "downtime-limit", 1);
+ }
}
-void migrate_ensure_converge(QTestState *who)
+void migrate_ensure_converge(QTestState *who, QDict *config)
{
/* Should converge with 30s downtime + 1 gbs bandwidth limit */
- migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
- migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
+ if (config) {
+ qdict_put_int(config, "max-bandwidth", 1 * 1000 * 1000 * 1000);
+ qdict_put_int(config, "downtime-limit", 30 * 1000);
+ } else {
+ migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
+ migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
+ }
}
void migrate_pause(QTestState *who)
diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
index faa8181d91..a80546a258 100644
--- a/tests/qtest/migration/migration-qmp.h
+++ b/tests/qtest/migration/migration-qmp.h
@@ -36,8 +36,8 @@ void migrate_set_parameter_str(QTestState *who, const char *parameter,
const char *value);
void migrate_set_parameter_bool(QTestState *who, const char *parameter,
int value);
-void migrate_ensure_non_converge(QTestState *who);
-void migrate_ensure_converge(QTestState *who);
+void migrate_ensure_non_converge(QTestState *who, QDict *config);
+void migrate_ensure_converge(QTestState *who, QDict *config);
void migrate_pause(QTestState *who);
void migrate_continue(QTestState *who, const char *state);
void migrate_recover(QTestState *who, const char *uri);
diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
index 54995256d8..abbbf966e9 100644
--- a/tests/qtest/migration/misc-tests.c
+++ b/tests/qtest/migration/misc-tests.c
@@ -70,7 +70,7 @@ static void test_analyze_script(void)
file = g_strdup_printf("%s/migfile", tmpfs);
uri = g_strdup_printf("exec:cat > %s", file);
- migrate_ensure_converge(from);
+ migrate_ensure_converge(from, args.config);
migrate_qmp(from, to, uri, NULL, "{}");
wait_for_migration_complete(from);
@@ -105,7 +105,7 @@ static void test_ignore_shared(void)
return;
}
- migrate_ensure_non_converge(from);
+ migrate_ensure_non_converge(from, args.config);
migrate_prepare_for_dirty_mem(from);
/* Wait for the first serial output from the source */
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index bb38292550..35d4274c69 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -387,7 +387,7 @@ static void test_auto_converge(void)
* Set the initial parameters so that the migration could not converge
* without throttling.
*/
- migrate_ensure_non_converge(from);
+ migrate_ensure_non_converge(from, args.config);
/* To check remaining size after precopy */
migrate_set_capability(from, "pause-before-switchover", true);
@@ -440,7 +440,7 @@ static void test_auto_converge(void)
g_assert_cmpint(hit, ==, 1);
/* Now, when we tested that throttling works, let it converge */
- migrate_ensure_converge(from);
+ migrate_ensure_converge(from, args.config);
/*
* Wait for pre-switchover status to check last throttle percentage
@@ -580,7 +580,7 @@ static void test_multifd_tcp_cancel(bool postcopy_ram)
return;
}
- migrate_ensure_non_converge(from);
+ migrate_ensure_non_converge(from, args.config);
migrate_prepare_for_dirty_mem(from);
if (postcopy_ram) {
@@ -640,13 +640,13 @@ static void test_multifd_tcp_cancel(bool postcopy_ram)
/* Start incoming migration from the 1st socket */
migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, "{}");
- migrate_ensure_non_converge(from);
+ migrate_ensure_non_converge(from, args.config);
migrate_qmp(from, to2, NULL, NULL, "{}");
migrate_wait_for_dirty_mem(from, to2);
- migrate_ensure_converge(from);
+ migrate_ensure_converge(from, args.config);
wait_for_stop(from, get_src());
qtest_qmp_eventwait(to2, "RESUME");
@@ -675,7 +675,7 @@ static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
*/
wait_for_serial("src_serial");
- migrate_ensure_converge(from);
+ migrate_ensure_converge(from, NULL);
migrate_qmp(from, to, uri, NULL, "{}");
@@ -699,7 +699,7 @@ static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to,
migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
wait_for_serial("src_serial");
- migrate_ensure_converge(from);
+ migrate_ensure_converge(from, NULL);
migrate_qmp(from, to, uri, NULL, "{}");
@@ -723,7 +723,7 @@ static void test_cancel_src_after_complete(QTestState *from, QTestState *to,
migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
wait_for_serial("src_serial");
- migrate_ensure_converge(from);
+ migrate_ensure_converge(from, NULL);
migrate_qmp(from, to, uri, NULL, "{}");
@@ -752,7 +752,7 @@ static void test_cancel_src_after_none(QTestState *from, QTestState *to,
migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
- migrate_ensure_converge(from);
+ migrate_ensure_converge(from, NULL);
migrate_qmp(from, to, uri, NULL, "{}");
wait_for_migration_complete(from);
@@ -771,7 +771,7 @@ static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
wait_for_serial("src_serial");
- migrate_ensure_converge(from);
+ migrate_ensure_converge(from, NULL);
migrate_qmp(from, to, uri, NULL, "{}");
@@ -1080,7 +1080,7 @@ static void migrate_dirty_limit_wait_showup(QTestState *from,
migrate_set_parameter_int(from, "vcpu-dirty-limit", value);
/* Make sure migrate can't converge */
- migrate_ensure_non_converge(from);
+ migrate_ensure_non_converge(from, NULL);
/* To check limit rate after precopy */
migrate_set_capability(from, "pause-before-switchover", true);
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PATCH v2 24/24] tests/qtest/migration: Pass the migration config to file tests
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
` (22 preceding siblings ...)
2025-06-30 19:59 ` [PATCH v2 23/24] tests/qtest/migration: Adapt convergence routines to config Fabiano Rosas
@ 2025-06-30 19:59 ` Fabiano Rosas
2025-08-14 14:24 ` Peter Xu
23 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-06-30 19:59 UTC (permalink / raw)
To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini
Use the existing file tests to test the new way of passing parameters
to the migration via the config argument to qmp_migrate*.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
tests/qtest/migration/file-tests.c | 68 +++++++++++----------------
tests/qtest/migration/framework.c | 9 ++--
tests/qtest/migration/precopy-tests.c | 1 +
3 files changed, 34 insertions(+), 44 deletions(-)
diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c
index 4d78ce0855..656d6527e8 100644
--- a/tests/qtest/migration/file-tests.c
+++ b/tests/qtest/migration/file-tests.c
@@ -27,6 +27,7 @@ static void test_precopy_file(void)
MigrateCommon args = {
.connect_uri = uri,
.listen_uri = "defer",
+ .start.config = qdict_new(),
};
test_file_common(&args, true);
@@ -74,6 +75,7 @@ static void test_precopy_file_offset_fdset(void)
.connect_uri = uri,
.listen_uri = "defer",
.start_hook = migrate_hook_start_file_offset_fdset,
+ .start.config = qdict_new(),
};
test_file_common(&args, false);
@@ -88,6 +90,7 @@ static void test_precopy_file_offset(void)
MigrateCommon args = {
.connect_uri = uri,
.listen_uri = "defer",
+ .start.config = qdict_new(),
};
test_file_common(&args, false);
@@ -102,6 +105,7 @@ static void test_precopy_file_offset_bad(void)
.connect_uri = uri,
.listen_uri = "defer",
.result = MIG_TEST_QMP_ERROR,
+ .start.config = qdict_new(),
};
test_file_common(&args, false);
@@ -114,11 +118,10 @@ static void test_precopy_file_mapped_ram_live(void)
MigrateCommon args = {
.connect_uri = uri,
.listen_uri = "defer",
- .start = {
- .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
- },
+ .start.config = qdict_new(),
};
+ qdict_put_bool(args.start.config, "mapped-ram", true);
test_file_common(&args, false);
}
@@ -129,11 +132,9 @@ static void test_precopy_file_mapped_ram(void)
MigrateCommon args = {
.connect_uri = uri,
.listen_uri = "defer",
- .start = {
- .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
- },
+ .start.config = qdict_new(),
};
-
+ qdict_put_bool(args.start.config, "mapped-ram", true);
test_file_common(&args, true);
}
@@ -144,12 +145,11 @@ static void test_multifd_file_mapped_ram_live(void)
MigrateCommon args = {
.connect_uri = uri,
.listen_uri = "defer",
- .start = {
- .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
- .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
- },
+ .start.config = qdict_new(),
};
+ qdict_put_bool(args.start.config, "mapped-ram", true);
+ qdict_put_bool(args.start.config, "multifd", true);
test_file_common(&args, false);
}
@@ -160,24 +160,13 @@ static void test_multifd_file_mapped_ram(void)
MigrateCommon args = {
.connect_uri = uri,
.listen_uri = "defer",
- .start = {
- .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
- .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
- },
+ .start.config = qdict_new(),
};
-
+ qdict_put_bool(args.start.config, "mapped-ram", true);
+ qdict_put_bool(args.start.config, "multifd", true);
test_file_common(&args, true);
}
-static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from,
- QTestState *to)
-{
- migrate_set_parameter_bool(from, "direct-io", true);
- migrate_set_parameter_bool(to, "direct-io", true);
-
- return NULL;
-}
-
static void test_multifd_file_mapped_ram_dio(void)
{
g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
@@ -185,13 +174,13 @@ static void test_multifd_file_mapped_ram_dio(void)
MigrateCommon args = {
.connect_uri = uri,
.listen_uri = "defer",
- .start_hook = migrate_hook_start_multifd_mapped_ram_dio,
- .start = {
- .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
- .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
- },
+ .start.config = qdict_new(),
};
+ qdict_put_bool(args.start.config, "direct-io", true);
+ qdict_put_bool(args.start.config, "mapped-ram", true);
+ qdict_put_bool(args.start.config, "multifd", true);
+
if (!probe_o_direct_support(tmpfs)) {
g_test_skip("Filesystem does not support O_DIRECT");
return;
@@ -235,9 +224,6 @@ static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from,
fdset_add_fds(from, file, O_WRONLY, 2, true);
fdset_add_fds(to, file, O_RDONLY, 2, true);
- migrate_set_parameter_bool(from, "direct-io", true);
- migrate_set_parameter_bool(to, "direct-io", true);
-
return NULL;
}
@@ -261,12 +247,11 @@ static void test_multifd_file_mapped_ram_fdset(void)
.listen_uri = "defer",
.start_hook = migrate_hook_start_multifd_mapped_ram_fdset,
.end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
- .start = {
- .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
- .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
- },
+ .start.config = qdict_new(),
};
+ qdict_put_bool(args.start.config, "mapped-ram", true);
+ qdict_put_bool(args.start.config, "multifd", true);
test_file_common(&args, true);
}
@@ -279,12 +264,13 @@ static void test_multifd_file_mapped_ram_fdset_dio(void)
.listen_uri = "defer",
.start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio,
.end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
- .start = {
- .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
- .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
- },
+ .start.config = qdict_new(),
};
+ qdict_put_bool(args.start.config, "direct-io", true);
+ qdict_put_bool(args.start.config, "mapped-ram", true);
+ qdict_put_bool(args.start.config, "multifd", true);
+
if (!probe_o_direct_support(tmpfs)) {
g_test_skip("Filesystem does not support O_DIRECT");
return;
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 5025299d6a..37c5c884af 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -974,18 +974,21 @@ void test_file_common(MigrateCommon *args, bool stop_src)
}
if (args->result == MIG_TEST_QMP_ERROR) {
- migrate_qmp_fail(from, args->connect_uri, NULL, "{}");
+ migrate_qmp_fail(from, args->connect_uri, NULL, "{ 'config': %p }",
+ args->start.config);
goto finish;
}
- migrate_qmp(from, to, args->connect_uri, NULL, "{}");
+ migrate_qmp(from, to, args->connect_uri, NULL, "{ 'config': %p }",
+ args->start.config);
wait_for_migration_complete(from);
/*
* We need to wait for the source to finish before starting the
* destination.
*/
- migrate_incoming_qmp(to, args->connect_uri, NULL, "{}");
+ migrate_incoming_qmp(to, args->connect_uri, NULL, "{ 'config': %p }",
+ args->start.config);
wait_for_migration_complete(to);
if (stop_src) {
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index 35d4274c69..9606dc1d02 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -338,6 +338,7 @@ static void test_precopy_fd_file(void)
.connect_uri = "fd:fd-mig",
.start_hook = migrate_hook_start_precopy_fd_file,
.end_hook = migrate_hook_end_fd,
+ .start.config = qdict_new(),
};
test_file_common(&args, true);
}
--
2.35.3
^ permalink raw reply related [flat|nested] 73+ messages in thread
* Re: [PATCH v2 01/24] migration: Fix leak of block_bitmap_mapping
2025-06-30 19:58 ` [PATCH v2 01/24] migration: Fix leak of block_bitmap_mapping Fabiano Rosas
@ 2025-07-01 6:12 ` Markus Armbruster
2025-07-03 21:31 ` Peter Xu
0 siblings, 1 reply; 73+ messages in thread
From: Markus Armbruster @ 2025-07-01 6:12 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, Peter Xu
Fabiano Rosas <farosas@suse.de> writes:
> Caught by inspection, but ASAN also reports:
>
> Direct leak of 16 byte(s) in 1 object(s) allocated from:
> #0 in malloc
> #1 in g_malloc
> #2 in g_memdup
> #3 in qapi_clone_start_struct ../qapi/qapi-clone-visitor.c:40:12
> #4 in qapi_clone_start_list ../qapi/qapi-clone-visitor.c:59:12
> #5 in visit_start_list ../qapi/qapi-visit-core.c:80:10
> #6 in visit_type_BitmapMigrationNodeAliasList qapi/qapi-visit-migration.c:639:10
> #7 in migrate_params_apply ../migration/options.c:1407:13
> #8 in qmp_migrate_set_parameters ../migration/options.c:1463:5
> #9 in qmp_marshal_migrate_set_parameters qapi/qapi-commands-migration.c:214:5
> #10 in do_qmp_dispatch_bh ../qapi/qmp-dispatch.c:128:5
migration_instance_finalize() runs when a TYPE_MIGRATION object dies, we
have just one such object, pointed to by @current_migration, and it
lives until QEMU shuts down.
So this is as harmless as they get. Please mentions this in the commit
message, to guide backporters.
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> migration/migration.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/migration/migration.c b/migration/migration.c
> index 4098870bce..7ec60d97f9 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -4050,6 +4050,7 @@ static void migration_instance_finalize(Object *obj)
> {
> MigrationState *ms = MIGRATION_OBJ(obj);
>
> + qapi_free_BitmapMigrationNodeAliasList(ms->parameters.block_bitmap_mapping);
> qemu_mutex_destroy(&ms->error_mutex);
> qemu_mutex_destroy(&ms->qemu_file_lock);
> qemu_sem_destroy(&ms->wait_unplug_sem);
With an adjusted commit message:
Reviewed-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 02/24] migration: Add a qdev property for StrOrNull
2025-06-30 19:58 ` [PATCH v2 02/24] migration: Add a qdev property for StrOrNull Fabiano Rosas
@ 2025-07-01 6:38 ` Markus Armbruster
2025-07-03 22:32 ` Peter Xu
0 siblings, 1 reply; 73+ messages in thread
From: Markus Armbruster @ 2025-07-01 6:38 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, Peter Xu
Fabiano Rosas <farosas@suse.de> writes:
> The MigrationState is a QOM object with TYPE_DEVICE as a parent. This
> was done about eight years ago so the migration code could make use of
> qdev properties to define the defaults for the migration parameters
> and to be able to expose migration knobs for debugging via the
> '-global migration' command line option.
>
> Due to unrelated historical reasons, three of the migration parameters
> (TLS options) received different types when used via the
> query-migrate-parameters QMP command than with the
> migrate-set-parameters command. This has created a lot of duplication
> in the migration code and in the QAPI documentation because the whole
> of MigrationParameters had to be duplicated as well.
>
> The migration code is now being fixed to remove the duplication and
> for that to happen the offending fields need to be reconciled into a
> single type. The StrOrNull type is going to be used.
>
> To keep the command line compatibility, the parameters need to
> continue being exposed via qdev properties accessible from the command
> line. Introduce a qdev property StrOrNull just for that.
>
> Note that this code is being kept in migration/options.c because this
> version of StrOrNull doesn't need to handle QNULL because it was never
> a valid option in the previous command line, which took a string.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> migration/options.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 47 insertions(+)
>
> diff --git a/migration/options.c b/migration/options.c
> index 162c72cda4..384ef9e421 100644
> --- a/migration/options.c
> +++ b/migration/options.c
> @@ -83,6 +83,11 @@
> #define DEFINE_PROP_MIG_CAP(name, x) \
> DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)
>
> +const PropertyInfo qdev_prop_StrOrNull;
> +#define DEFINE_PROP_STR_OR_NULL(_name, _state, _field) \
> + DEFINE_PROP(_name, _state, _field, qdev_prop_StrOrNull, StrOrNull *, \
> + .set_default = true)
> +
> #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD 1000 /* milliseconds */
> #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT 1 /* MB/s */
>
> @@ -204,6 +209,48 @@ const Property migration_properties[] = {
> };
> const size_t migration_properties_count = ARRAY_SIZE(migration_properties);
>
> +/*
> + * qdev property for TLS options handling via '-global migration'
> + * command line.
> + */
Looks like this was a function comment. It's not, it applies to the
PropertyInfo and its method. Move it to the PropertyInfo?
Maybe
/*
* String property like qdev_prop_string, except it's backed by a
* StrOrNull * instead of a char *. This is intended for
* TYPE_MIGRATION's TLS options.
*/
> +static void set_StrOrNull(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + const Property *prop = opaque;
> + StrOrNull **ptr = object_field_prop_ptr(obj, prop);
> + StrOrNull *str_or_null = g_new0(StrOrNull, 1);
> +
> + /*
> + * Only str to keep compatibility, QNULL was never used via
> + * command line.
> + */
> + str_or_null->type = QTYPE_QSTRING;
> + if (!visit_type_str(v, name, &str_or_null->u.s, errp)) {
> + return;
> + }
> +
> + qapi_free_StrOrNull(*ptr);
> + *ptr = str_or_null;
> +}
> +
> +static void release_StrOrNull(Object *obj, const char *name, void *opaque)
> +{
> + const Property *prop = opaque;
> + qapi_free_StrOrNull(*(StrOrNull **)object_field_prop_ptr(obj, prop));
> +}
> +
> +static void set_default_value_tls_opt(ObjectProperty *op, const Property *prop)
> +{
> + object_property_set_default_str(op, "");
> +}
> +
> +const PropertyInfo qdev_prop_StrOrNull = {
> + .type = "StrOrNull",
> + .set = set_StrOrNull,
> + .release = release_StrOrNull,
> + .set_default_value = set_default_value_tls_opt,
> +};
No getter, i.e. properties will be write-only. This is unusual. Is it
safe?
> +
> bool migrate_auto_converge(void)
> {
> MigrationState *s = migrate_get_current();
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 03/24] migration: Normalize tls arguments
2025-06-30 19:58 ` [PATCH v2 03/24] migration: Normalize tls arguments Fabiano Rosas
@ 2025-07-01 7:46 ` Markus Armbruster
2025-07-01 14:20 ` Fabiano Rosas
0 siblings, 1 reply; 73+ messages in thread
From: Markus Armbruster @ 2025-07-01 7:46 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, Peter Xu, Eric Blake
Fabiano Rosas <farosas@suse.de> writes:
> The migration parameters tls_creds, tls_authz and tls_hostname
> currently have a non-uniform handling. When used as arguments to
> migrate-set-parameters, their type is StrOrNull and when used as
> return value from query-migrate-parameters their type is a plain
> string.
>
> Not only having to convert between the types is cumbersome, but it
> also creates the issue of requiring two different QAPI types to be
> used, one for each command. MigrateSetParameters is used for
> migrate-set-parameters with the TLS arguments as StrOrNull while
> MigrationParameters is used for query-migrate-parameters with the TLS
> arguments as str.
>
> Since StrOrNull could be considered a superset of str, change the type
> of the TLS arguments in MigrationParameters to StrOrNull. Also ensure
> that QTYPE_QNULL is never used.
>
> 1) migrate-set-parameters will always write QTYPE_QSTRING to
> s->parameters, either an empty or non-empty string.
>
> 2) query-migrate-parameters will always return a QTYPE_QSTRING, either
> empty or non-empty.
>
> 3) the migrate_tls_* helpers will always return a non-empty string or
> NULL, for the internal migration code's consumption.
>
> Points (1) and (2) above help simplify the parameters validation and
> the query command handling because s->parameters is already kept in
> the format that query-migrate-parameters (and info migrate_paramters)
> expect. Point (3) is so people don't need to care about StrOrNull in
> migration code.
>
> This will allow the type duplication to be removed in the next
> patches.
>
> Note that the type of @tls_creds, @tls-hostname, @tls-authz changes
> from str to StrOrNull in introspection of the query-migrate-parameters
> command. We accept this imprecision to enable de-duplication.
>
> There's no need to free the TLS options in
> migration_instance_finalize() because they're freed by the qdev
> properties .release method.
>
> Temporary in this patch:
> migrate_params_test_apply() copies s->parameters into a temporary
> structure, so it's necessary to drop the references to the TLS options
> if they were not set by the user to avoid double-free. This is fixed
> in the next patches.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
[...]
> diff --git a/migration/options.c b/migration/options.c
> index 384ef9e421..f7bbdba5fc 100644
> --- a/migration/options.c
> +++ b/migration/options.c
[...]
> @@ -935,6 +951,37 @@ AnnounceParameters *migrate_announce_params(void)
> return ≈
> }
>
> +void migrate_tls_opts_free(MigrationParameters *params)
> +{
> + qapi_free_StrOrNull(params->tls_creds);
> + qapi_free_StrOrNull(params->tls_hostname);
> + qapi_free_StrOrNull(params->tls_authz);
> +}
> +
> +/* either non-empty or empty string */
This isn't true, because ...
> +static void tls_opt_to_str(StrOrNull **tls_opt)
> +{
> + StrOrNull *opt = *tls_opt;
> +
> + if (!opt) {
> + return;
... it can also be null.
Maybe
/* Normalize QTYPE_QNULL to QTYPE_QSTRING "" */
> + }
> +
> + switch (opt->type) {
> + case QTYPE_QSTRING:
> + return;
> + case QTYPE_QNULL:
> + qobject_unref(opt->u.n);
> + break;
> + default:
> + g_assert_not_reached();
> + }
> +
> + opt->type = QTYPE_QSTRING;
> + opt->u.s = g_strdup("");
> + *tls_opt = opt;
> +}
I'd prefer something like
if (!opt || opt->type == QTYPE_QSTRING) {
return;
}
qobject_unref(opt->u.n);
opt->type = QTYPE_QSTRING;
opt->u.s = g_strdup("");
*tls_opt = opt;
But this is clearly a matter of taste.
> +
> MigrationParameters *qmp_query_migrate_parameters(Error **errp)
> {
> MigrationParameters *params;
[...]
> @@ -1251,18 +1294,24 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
> }
>
> if (params->tls_creds) {
> - assert(params->tls_creds->type == QTYPE_QSTRING);
> - dest->tls_creds = params->tls_creds->u.s;
> + dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
> + } else {
> + /* drop the reference, it's owned by s->parameters */
> + dest->tls_creds = NULL;
Suggest "clear the reference" to avoid associations with reference
counting.
> }
>
> if (params->tls_hostname) {
> - assert(params->tls_hostname->type == QTYPE_QSTRING);
> - dest->tls_hostname = params->tls_hostname->u.s;
> + dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
> + } else {
> + /* drop the reference, it's owned by s->parameters */
> + dest->tls_hostname = NULL;
> }
>
> if (params->tls_authz) {
> - assert(params->tls_authz->type == QTYPE_QSTRING);
> - dest->tls_authz = params->tls_authz->u.s;
> + dest->tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
> + } else {
> + /* drop the reference, it's owned by s->parameters */
> + dest->tls_authz = NULL;
> }
>
> if (params->has_max_bandwidth) {
[...]
> diff --git a/qapi/migration.json b/qapi/migration.json
> index 4963f6ca12..97bb022c45 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -1293,9 +1293,9 @@
> '*cpu-throttle-initial': 'uint8',
> '*cpu-throttle-increment': 'uint8',
> '*cpu-throttle-tailslow': 'bool',
> - '*tls-creds': 'str',
> - '*tls-hostname': 'str',
> - '*tls-authz': 'str',
> + '*tls-creds': 'StrOrNull',
> + '*tls-hostname': 'StrOrNull',
> + '*tls-authz': 'StrOrNull',
> '*max-bandwidth': 'size',
> '*avail-switchover-bandwidth': 'size',
> '*downtime-limit': 'uint64',
QAPI schema
Acked-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 04/24] migration: Remove MigrateSetParameters
2025-06-30 19:58 ` [PATCH v2 04/24] migration: Remove MigrateSetParameters Fabiano Rosas
@ 2025-07-01 8:00 ` Markus Armbruster
2025-07-03 19:34 ` Fabiano Rosas
2025-07-04 15:39 ` Peter Xu
1 sibling, 1 reply; 73+ messages in thread
From: Markus Armbruster @ 2025-07-01 8:00 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Peter Xu, Eric Blake
Fabiano Rosas <farosas@suse.de> writes:
> Now that the TLS options have been made the same between
> migrate-set-parameters and query-migrate-parameters, a single type can
> be used. Remove MigrateSetParameters.
>
> The TLS options documentation from MigrationParameters were replaced
> with the ones from MigrateSetParameters which was more complete.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
[...]
> diff --git a/qapi/migration.json b/qapi/migration.json
> index 97bb022c45..3788c39857 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -914,206 +914,10 @@
> 'zero-page-detection',
> 'direct-io'] }
>
> -##
> -# @MigrateSetParameters:
[...]
> ##
> # @migrate-set-parameters:
> #
> -# Set various migration parameters.
> +# Set migration parameters. All fields are optional.
Use "arguments" instead of "fields".
> #
> # Since: 2.4
> #
> @@ -1124,13 +928,11 @@
> # <- { "return": {} }
> ##
> { 'command': 'migrate-set-parameters', 'boxed': true,
> - 'data': 'MigrateSetParameters' }
> + 'data': 'MigrationParameters' }
>
> ##
> # @MigrationParameters:
> #
> -# The optional members aren't actually optional.
> -#
> # @announce-initial: Initial delay (in milliseconds) before sending
> # the first announce (Since 4.0)
> #
> @@ -1148,12 +950,12 @@
> # percentage. The default value is 50. (Since 5.0)
> #
> # @cpu-throttle-initial: Initial percentage of time guest cpus are
> -# throttled when migration auto-converge is activated.
> -# (Since 2.7)
> +# throttled when migration auto-converge is activated. The
> +# default value is 20. (Since 2.7)
> #
> # @cpu-throttle-increment: throttle percentage increase each time
> # auto-converge detects that migration is not making progress.
> -# (Since 2.7)
> +# The default value is 10. (Since 2.7)
> #
> # @cpu-throttle-tailslow: Make CPU throttling slower at tail stage.
> # At the tail stage of throttling, the Guest is very sensitive to
> @@ -1172,21 +974,25 @@
> # for establishing a TLS connection over the migration data
> # channel. On the outgoing side of the migration, the credentials
> # must be for a 'client' endpoint, while for the incoming side the
> -# credentials must be for a 'server' endpoint. An empty string
> -# means that QEMU will use plain text mode for migration, rather
> -# than TLS. (Since 2.7)
> -#
> -# Note: 2.8 omits empty @tls-creds instead.
> +# credentials must be for a 'server' endpoint. Setting this to a
> +# non-empty string enables TLS for all migrations. An empty
> +# string means that QEMU will use plain text mode for migration,
> +# rather than TLS. This is the default. (Since 2.7)
> #
> # @tls-hostname: migration target's hostname for validating the
> # server's x509 certificate identity. If empty, QEMU will use the
> -# hostname from the migration URI, if any. (Since 2.7)
> +# hostname from the migration URI, if any. A non-empty value is
> +# required when using x509 based TLS credentials and the migration
> +# URI does not include a hostname, such as fd: or exec: based
> +# migration. (Since 2.7)
> #
> -# Note: 2.8 omits empty @tls-hostname instead.
> +# Note: empty value works only since 2.9.
> #
> # @tls-authz: ID of the 'authz' object subclass that provides access
> # control checking of the TLS x509 certificate distinguished name.
> -# (Since 4.0)
> +# This object is only resolved at time of use, so can be deleted
> +# and recreated on the fly while the migration server is active.
> +# If missing, it will default to denying access (Since 4.0)
> #
> # @max-bandwidth: maximum speed for migration, in bytes per second.
> # (Since 2.8)
> @@ -1205,8 +1011,8 @@
> # @downtime-limit: set maximum tolerated downtime for migration.
> # maximum downtime in milliseconds (Since 2.8)
> #
> -# @x-checkpoint-delay: the delay time between two COLO checkpoints.
> -# (Since 2.8)
> +# @x-checkpoint-delay: the delay time between two COLO checkpoints in
> +# periodic mode. (Since 2.8)
> #
> # @multifd-channels: Number of channels used to migrate data in
> # parallel. This is the same number that the number of sockets
Please add
##
# @query-migrate-parameters:
#
-# Return information about the current migration parameters
+# Return information about the current migration parameters.
+# Optional members of the return value are always present.
#
# Returns: @MigrationParameters
#
# Since: 2.4
#
and double-check "always" is actually true.
With that, QAPI schema
Acked-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 05/24] qapi/migration: Don't document MigrationParameter
2025-06-30 19:58 ` [PATCH v2 05/24] qapi/migration: Don't document MigrationParameter Fabiano Rosas
@ 2025-07-01 8:04 ` Markus Armbruster
2025-07-04 15:40 ` Peter Xu
1 sibling, 0 replies; 73+ messages in thread
From: Markus Armbruster @ 2025-07-01 8:04 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, Peter Xu, Eric Blake
Fabiano Rosas <farosas@suse.de> writes:
> The MigrationParameter (singular) enumeration is not part of the
> migration QMP API, it's only used for nicely converting HMP strings
> into MigrationParameters (plural) members and for providing readline
> completion.
>
> Documenting this enum only serves to duplicate documentation between
> MigrationParameter and MigrationParameters.
>
> Add an exception to QAPIs pragma.json and stop documenting it.
Please add something like
The generated "QEMU QMP Reference Manual" now lists the enum members
as "Not documented." Tolerable.
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
With that
Acked-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 16/24] migration: Add capabilities into MigrationParameters
2025-06-30 19:59 ` [PATCH v2 16/24] migration: Add capabilities into MigrationParameters Fabiano Rosas
@ 2025-07-01 8:25 ` Markus Armbruster
2025-07-04 13:15 ` Fabiano Rosas
2025-07-04 16:33 ` Peter Xu
1 sibling, 1 reply; 73+ messages in thread
From: Markus Armbruster @ 2025-07-01 8:25 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, Peter Xu, Eric Blake
Fabiano Rosas <farosas@suse.de> writes:
> Add capabilities to MigrationParameters. This structure will hold all
> migration options. Capabilities will go away in the next patch.
>
> Also add capabilities to MigrationParameter as the enum needs to be
> kept in sync with MigrationParameters. This affects the parsing of
> migration HMP commands so make the necessary additions there too.
>
> From this point on, both QMP and HMP versions of
> migrate-set-parameters and query-migrate-parameters gain the ability
> to work with capabilities.
>
> With MigrationParameters now having members for each capability, the
> migration capabilities commands (query-migrate-capabilities,
> migrate-set-capabilities) will soon be deprecated. Add a set of
> helpers to convert between the old MigrationCapability representation
> and the new representation as members of MigrationParameters.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
[...]
> diff --git a/qapi/migration.json b/qapi/migration.json
> index 40e00fb86e..3d3f5624c5 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -763,7 +763,14 @@
> 'vcpu-dirty-limit',
> 'mode',
> 'zero-page-detection',
> - 'direct-io'] }
> + 'direct-io', 'xbzrle', 'rdma-pin-all', 'auto-converge',
> + 'zero-blocks', 'events', 'postcopy-ram', 'x-colo',
> + 'release-ram', 'return-path', 'pause-before-switchover',
> + 'multifd', 'dirty-bitmaps', 'postcopy-blocktime',
> + 'late-block-activate', 'x-ignore-shared',
> + 'validate-uuid', 'background-snapshot',
> + 'zero-copy-send', 'postcopy-preempt',
> + 'switchover-ack', 'dirty-limit', 'mapped-ram' ] }
This is MigrateParameter. Different order than in MigrationParameters.
Intentional?
>
> ##
> # @migrate-set-parameters:
> @@ -934,10 +941,108 @@
> # only has effect if the @mapped-ram capability is enabled.
> # (Since 9.1)
> #
> +# @xbzrle: Migration supports xbzrle (Xor Based Zero Run Length
> +# Encoding). This feature allows us to minimize migration traffic
> +# for certain work loads, by sending compressed difference of the
> +# pages
> +#
> +# @rdma-pin-all: Controls whether or not the entire VM memory
> +# footprint is mlock()'d on demand or all at once. Refer to
> +# docs/rdma.txt for usage. Disabled by default. (since 2.0)
> +#
> +# @zero-blocks: During storage migration encode blocks of zeroes
> +# efficiently. This essentially saves 1MB of zeroes per block on
> +# the wire. Enabling requires source and target VM to support
> +# this feature. To enable it is sufficient to enable the
> +# capability on the source VM. The feature is disabled by
> +# default. (since 1.6)
> +#
> +# @events: generate events for each migration state change (since 2.4)
> +#
> +# @auto-converge: If enabled, QEMU will automatically throttle down
> +# the guest to speed up convergence of RAM migration. (since 1.6)
> +#
> +# @postcopy-ram: Start executing on the migration target before all of
> +# RAM has been migrated, pulling the remaining pages along as
> +# needed. The capacity must have the same setting on both source
> +# and target or migration will not even start. NOTE: If the
Make this
# and target or migration will not even start. **Note:** if the
Crossed with commit 188b31ad425c (qapi: Use proper markup instead of
CAPS for emphasis in doc comments).
> +# migration fails during postcopy the VM will fail. (since 2.6)
> +#
> +# @x-colo: If enabled, migration will never end, and the state of the
> +# VM on the primary side will be migrated continuously to the VM
> +# on secondary side, this process is called COarse-Grain LOck
> +# Stepping (COLO) for Non-stop Service. (since 2.8)
> +#
> +# @release-ram: if enabled, qemu will free the migrated ram pages on
And this
# @release-ram: if enabled, QEMU will free the migrated ram pages on
Crossed with commit 6263225492ba (qapi: Correct spelling of QEMU in doc
comments).
> +# the source during postcopy-ram migration. (since 2.9)
> +#
> +# @return-path: If enabled, migration will use the return path even
> +# for precopy. (since 2.10)
> +#
> +# @pause-before-switchover: Pause outgoing migration before
> +# serialising device state and before disabling block IO (since
> +# 2.11)
# serialising device state and before disabling block IO
# (since 2.11)
Crossed with commit c1a6aa1d443e (qapi: Avoid breaking lines within
(since X.Y))
> +#
> +# @multifd: Use more than one fd for migration (since 4.0)
> +#
> +# @dirty-bitmaps: If enabled, QEMU will migrate named dirty bitmaps.
> +# (since 2.12)
> +#
> +# @postcopy-blocktime: Calculate downtime for postcopy live migration
> +# (since 3.0)
> +#
> +# @late-block-activate: If enabled, the destination will not activate
> +# block devices (and thus take locks) immediately at the end of
> +# migration. (since 3.0)
> +#
> +# @x-ignore-shared: If enabled, QEMU will not migrate shared memory
> +# that is accessible on the destination machine. (since 4.0)
> +#
> +# @validate-uuid: Send the UUID of the source to allow the destination
> +# to ensure it is the same. (since 4.2)
> +#
> +# @background-snapshot: If enabled, the migration stream will be a
> +# snapshot of the VM exactly at the point when the migration
> +# procedure starts. The VM RAM is saved with running VM.
> +# (since 6.0)
> +#
> +# @zero-copy-send: Controls behavior on sending memory pages on
> +# migration. When true, enables a zero-copy mechanism for sending
> +# memory pages, if host supports it. Requires that QEMU be
> +# permitted to use locked memory for guest RAM pages. (since 7.1)
> +#
> +# @postcopy-preempt: If enabled, the migration process will allow
> +# postcopy requests to preempt precopy stream, so postcopy
> +# requests will be handled faster. This is a performance feature
> +# and should not affect the correctness of postcopy migration.
> +# (since 7.1)
> +#
> +# @switchover-ack: If enabled, migration will not stop the source VM
> +# and complete the migration until an ACK is received from the
> +# destination that it's OK to do so. Exactly when this ACK is
> +# sent depends on the migrated devices that use this feature. For
> +# example, a device can use it to make sure some of its data is
> +# sent and loaded in the destination before doing switchover.
> +# This can reduce downtime if devices that support this capability
> +# are present. 'return-path' capability must be enabled to use
> +# it. (since 8.1)
> +#
> +# @dirty-limit: If enabled, migration will throttle vCPUs as needed to
> +# keep their dirty page rate within @vcpu-dirty-limit. This can
> +# improve responsiveness of large guests during live migration,
> +# and can result in more stable read performance. Requires KVM
> +# with accelerator property "dirty-ring-size" set. (Since 8.1)
> +#
> +# @mapped-ram: Migrate using fixed offsets in the migration file for
> +# each RAM page. Requires a migration URI that supports seeking,
> +# such as a file. (since 9.0)
> +#
> # Features:
> #
> -# @unstable: Members @x-checkpoint-delay and
> -# @x-vcpu-dirty-limit-period are experimental.
> +# @unstable: Members @x-checkpoint-delay, @x-vcpu-dirty-limit-period,
> +# @x-colo and @x-ignore-shared are experimental.
> +# @deprecated: Member @zero-blocks is deprecated as being part of
> +# block migration which was already removed.
> #
> # Since: 2.4
> ##
> @@ -972,7 +1077,29 @@
> '*vcpu-dirty-limit': 'uint64',
> '*mode': 'MigMode',
> '*zero-page-detection': 'ZeroPageDetection',
> - '*direct-io': 'bool' } }
> + '*direct-io': 'bool',
> + '*xbzrle': 'bool',
> + '*rdma-pin-all': 'bool',
> + '*auto-converge': 'bool',
> + '*zero-blocks': { 'type': 'bool', 'features': [ 'deprecated' ] },
> + '*events': 'bool',
> + '*postcopy-ram': 'bool',
> + '*x-colo': { 'type': 'bool', 'features': [ 'unstable' ] },
> + '*release-ram': 'bool',
> + '*return-path': 'bool',
> + '*pause-before-switchover': 'bool',
> + '*multifd': 'bool',
> + '*dirty-bitmaps': 'bool',
> + '*postcopy-blocktime': 'bool',
> + '*late-block-activate': 'bool',
> + '*x-ignore-shared': { 'type': 'bool', 'features': [ 'unstable' ] },
> + '*validate-uuid': 'bool',
> + '*background-snapshot': 'bool',
> + '*zero-copy-send': 'bool',
> + '*postcopy-preempt': 'bool',
> + '*switchover-ack': 'bool',
> + '*dirty-limit': 'bool',
> + '*mapped-ram': 'bool' } }
>
> ##
> # @query-migrate-parameters:
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands
2025-06-30 19:59 ` [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands Fabiano Rosas
@ 2025-07-01 8:30 ` Markus Armbruster
2025-07-01 8:38 ` Jiri Denemark
2025-08-13 20:50 ` Peter Xu
2 siblings, 0 replies; 73+ messages in thread
From: Markus Armbruster @ 2025-07-01 8:30 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, Peter Xu, devel, Eric Blake
Fabiano Rosas <farosas@suse.de> writes:
> The concept of capabilities is being merged into the concept of
> parameters. From now on, the commands that handle capabilities are
> deprecated in favor of the commands that handle parameters.
>
> Affected commands:
>
> - migrate-set-capabilities
> - query-migrate-capabilities
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> docs/about/deprecated.rst | 12 ++++++++++++
> migration/migration-hmp-cmds.c | 6 ++++++
> qapi/migration.json | 16 ++++++++++++++--
> 3 files changed, 32 insertions(+), 2 deletions(-)
>
> diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
> index 42037131de..15474833ea 100644
> --- a/docs/about/deprecated.rst
> +++ b/docs/about/deprecated.rst
> @@ -605,3 +605,15 @@ command documentation for details on the ``fdset`` usage.
>
> The ``zero-blocks`` capability was part of the block migration which
> doesn't exist anymore since it was removed in QEMU v9.1.
> +
> +``migrate-set-capabilities`` command (since 10.1)
> +'''''''''''''''''''''''''''''''''''''''''''''''''
> +
> +This command was deprecated. Use ``migrate-set-parameters`` instead
> +which now supports setting capabilities.
> +
> +``query-migrate-capabilities`` command (since 10.1)
> +'''''''''''''''''''''''''''''''''''''''''''''''''''
> +
> +This command was deprecated. Use ``query-migrate-parameters`` instead
> +which now supports querying capabilities.
Scratch "This command was deprecated."
Could also scratch "which now supports..." Up to you.
> diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
> index 8615340a6b..7f234d5aa8 100644
> --- a/migration/migration-hmp-cmds.c
> +++ b/migration/migration-hmp-cmds.c
> @@ -229,6 +229,9 @@ void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict)
> {
> MigrationCapabilityStatusList *caps, *cap;
>
> + warn_report("info migrate_capabilities is deprecated;"
> + " use info migrate_parameters instead");
> +
> caps = qmp_query_migrate_capabilities(NULL);
>
> if (caps) {
> @@ -616,6 +619,9 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
> MigrationCapabilityStatus *value;
> int val;
>
> + warn_report("migrate_set_capability is deprecated;"
> + " use migrate_set_parameter instead");
> +
> val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
> if (val < 0) {
> goto end;
> diff --git a/qapi/migration.json b/qapi/migration.json
> index 3d3f5624c5..c5e6ea1a2d 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -521,6 +521,11 @@
> #
> # @capabilities: json array of capability modifications to make
> #
> +# Features:
> +#
> +# @deprecated: This command is deprecated in favor of
> +# migrate-set-parameters.
For consistency with existing deprecation notes:
# @deprecated: This command is deprecated. Use migrate-set-parameters
# instead.
> +#
> # Since: 1.2
> #
> # .. qmp-example::
> @@ -530,7 +535,8 @@
> # <- { "return": {} }
> ##
> { 'command': 'migrate-set-capabilities',
> - 'data': { 'capabilities': ['MigrationCapabilityStatus'] } }
> + 'data': { 'capabilities': ['MigrationCapabilityStatus'] },
> + 'features': ['deprecated'] }
>
> ##
> # @query-migrate-capabilities:
> @@ -539,6 +545,11 @@
> #
> # Returns: @MigrationCapabilityStatus
> #
> +# Features:
> +#
> +# @deprecated: This command is deprecated in favor of
> +# query-migrate-parameters.
Likewise.
> +#
> # Since: 1.2
> #
> # .. qmp-example::
> @@ -554,7 +565,8 @@
> # {"state": false, "capability": "x-colo"}
> # ]}
> ##
> -{ 'command': 'query-migrate-capabilities', 'returns': ['MigrationCapabilityStatus']}
> +{ 'command': 'query-migrate-capabilities', 'returns': ['MigrationCapabilityStatus'],
> + 'features': ['deprecated'] }
>
> ##
> # @MultiFDCompression:
With that:
Reviewed-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 20/24] migration: Allow migrate commands to provide the migration config
2025-06-30 19:59 ` [PATCH v2 20/24] migration: Allow migrate commands to provide the migration config Fabiano Rosas
@ 2025-07-01 8:35 ` Markus Armbruster
2025-08-13 21:27 ` Peter Xu
1 sibling, 0 replies; 73+ messages in thread
From: Markus Armbruster @ 2025-07-01 8:35 UTC (permalink / raw)
To: Fabiano Rosas
Cc: qemu-devel, berrange, armbru, Peter Xu, Eric Blake, Paolo Bonzini
Fabiano Rosas <farosas@suse.de> writes:
> Allow the migrate and migrate_incoming commands to pass the migration
> configuration options all at once, dispensing the use of
> migrate-set-parameters and migrate-set-capabilities.
>
> The motivation of this is to simplify the interface with the
> management layer and avoid the usage of several command invocations to
> configure a migration. It also avoids stale parameters from a previous
> migration to influence the current migration.
>
> The options that are changed during the migration can still be set
> with the existing commands.
>
> The order of precedence is:
>
> 'config' argument > -global migration cmdline > migrate-set-parameters
> > defaults (migration_properties)
>
> I.e. the config takes precedence over all, values not present in the
> config assume the default values. The -global migration command line
> option allows the defaults to be overridden for debug.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
[...]
> diff --git a/qapi/migration.json b/qapi/migration.json
> index c5e6ea1a2d..11b7d7ebec 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -1456,6 +1456,13 @@
> #
> # @resume: resume one paused migration, default "off". (since 3.0)
> #
> +# @config: migration configuration options, previously set via
> +# @migrate-set-parameters and @migrate-set-capabilities. Setting
> +# this argument causes all migration configuration options
> +# previously set via @migrate-set-parameters to be ignored.
> +# Configuration options not set will assume their default
> +# values. (since 10.1)
> +#
Recommend
# @config: migration configuration options. When present, any
# migration configuration previously set with
# @migrate-set-parameters is ignored. (since 10.1)
I could be persuaded to keep the sentence on defaults.
> # Features:
> #
> # @deprecated: Argument @detach is deprecated.
> @@ -1520,6 +1527,7 @@
> 'data': {'*uri': 'str',
> '*channels': [ 'MigrationChannel' ],
> '*detach': { 'type': 'bool', 'features': [ 'deprecated' ] },
> + '*config': 'MigrationParameters',
> '*resume': 'bool' } }
>
> ##
> @@ -1539,6 +1547,13 @@
> # error details could be retrieved with query-migrate.
> # (since 9.1)
> #
> +# @config: migration configuration options, previously set via
> +# @migrate-set-parameters and @migrate-set-capabilities. Setting
> +# this argument causes all migration configuration options
> +# previously set via @migrate-set-parameters to be ignored.
> +# Configuration options not set will assume their default
> +# values. (since 10.1)
Likewise.
> +#
> # Since: 2.3
> #
> # .. admonition:: Notes
> @@ -1592,6 +1607,7 @@
> { 'command': 'migrate-incoming',
> 'data': {'*uri': 'str',
> '*channels': [ 'MigrationChannel' ],
> + '*config': 'MigrationParameters',
> '*exit-on-error': 'bool' } }
>
> ##
[...]
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands
2025-06-30 19:59 ` [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands Fabiano Rosas
2025-07-01 8:30 ` Markus Armbruster
@ 2025-07-01 8:38 ` Jiri Denemark
2025-07-01 9:00 ` Peter Krempa
2025-07-01 9:10 ` Daniel P. Berrangé
2025-08-13 20:50 ` Peter Xu
2 siblings, 2 replies; 73+ messages in thread
From: Jiri Denemark @ 2025-07-01 8:38 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Peter Xu, devel, Eric Blake
On Mon, Jun 30, 2025 at 16:59:07 -0300, Fabiano Rosas wrote:
> The concept of capabilities is being merged into the concept of
> parameters. From now on, the commands that handle capabilities are
> deprecated in favor of the commands that handle parameters.
>
> Affected commands:
>
> - migrate-set-capabilities
> - query-migrate-capabilities
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> docs/about/deprecated.rst | 12 ++++++++++++
> migration/migration-hmp-cmds.c | 6 ++++++
> qapi/migration.json | 16 ++++++++++++++--
> 3 files changed, 32 insertions(+), 2 deletions(-)
We'll need to adapt libvirt as both commands are actively used now. Is
there a way of detecting where the relevant commands for
setting/querying parameters support capabilities? I guess QAPI schema
should work, right?
Jirka
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands
2025-07-01 8:38 ` Jiri Denemark
@ 2025-07-01 9:00 ` Peter Krempa
2025-07-01 9:10 ` Daniel P. Berrangé
1 sibling, 0 replies; 73+ messages in thread
From: Peter Krempa @ 2025-07-01 9:00 UTC (permalink / raw)
To: Jiri Denemark
Cc: Fabiano Rosas, qemu-devel, armbru, Peter Xu, devel, Eric Blake
On Tue, Jul 01, 2025 at 10:38:44 +0200, Jiri Denemark via Devel wrote:
> On Mon, Jun 30, 2025 at 16:59:07 -0300, Fabiano Rosas wrote:
> > The concept of capabilities is being merged into the concept of
> > parameters. From now on, the commands that handle capabilities are
> > deprecated in favor of the commands that handle parameters.
> >
> > Affected commands:
> >
> > - migrate-set-capabilities
> > - query-migrate-capabilities
> >
> > Signed-off-by: Fabiano Rosas <farosas@suse.de>
> > ---
> > docs/about/deprecated.rst | 12 ++++++++++++
> > migration/migration-hmp-cmds.c | 6 ++++++
> > qapi/migration.json | 16 ++++++++++++++--
> > 3 files changed, 32 insertions(+), 2 deletions(-)
>
> We'll need to adapt libvirt as both commands are actively used now. Is
> there a way of detecting where the relevant commands for
> setting/querying parameters support capabilities? I guess QAPI schema
> should work, right?
The parameters command gains the fields from "migrate-set-capabilities"
which is easy to query. Alternatively we can query the "deprecated"
feature as well.
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands
2025-07-01 8:38 ` Jiri Denemark
2025-07-01 9:00 ` Peter Krempa
@ 2025-07-01 9:10 ` Daniel P. Berrangé
1 sibling, 0 replies; 73+ messages in thread
From: Daniel P. Berrangé @ 2025-07-01 9:10 UTC (permalink / raw)
To: Jiri Denemark
Cc: Fabiano Rosas, qemu-devel, armbru, Peter Xu, devel, Eric Blake
On Tue, Jul 01, 2025 at 10:38:44AM +0200, Jiri Denemark wrote:
> On Mon, Jun 30, 2025 at 16:59:07 -0300, Fabiano Rosas wrote:
> > The concept of capabilities is being merged into the concept of
> > parameters. From now on, the commands that handle capabilities are
> > deprecated in favor of the commands that handle parameters.
> >
> > Affected commands:
> >
> > - migrate-set-capabilities
> > - query-migrate-capabilities
> >
> > Signed-off-by: Fabiano Rosas <farosas@suse.de>
> > ---
> > docs/about/deprecated.rst | 12 ++++++++++++
> > migration/migration-hmp-cmds.c | 6 ++++++
> > qapi/migration.json | 16 ++++++++++++++--
> > 3 files changed, 32 insertions(+), 2 deletions(-)
>
> We'll need to adapt libvirt as both commands are actively used now. Is
> there a way of detecting where the relevant commands for
> setting/querying parameters support capabilities? I guess QAPI schema
> should work, right?
Query the 'migrate' command schema which gains a new 'config' parameter
in patch 20 in this series.
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 03/24] migration: Normalize tls arguments
2025-07-01 7:46 ` Markus Armbruster
@ 2025-07-01 14:20 ` Fabiano Rosas
2025-07-04 13:12 ` Fabiano Rosas
0 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-07-01 14:20 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, berrange, Peter Xu, Eric Blake
Markus Armbruster <armbru@redhat.com> writes:
> Fabiano Rosas <farosas@suse.de> writes:
>
>> The migration parameters tls_creds, tls_authz and tls_hostname
>> currently have a non-uniform handling. When used as arguments to
>> migrate-set-parameters, their type is StrOrNull and when used as
>> return value from query-migrate-parameters their type is a plain
>> string.
>>
>> Not only having to convert between the types is cumbersome, but it
>> also creates the issue of requiring two different QAPI types to be
>> used, one for each command. MigrateSetParameters is used for
>> migrate-set-parameters with the TLS arguments as StrOrNull while
>> MigrationParameters is used for query-migrate-parameters with the TLS
>> arguments as str.
>>
>> Since StrOrNull could be considered a superset of str, change the type
>> of the TLS arguments in MigrationParameters to StrOrNull. Also ensure
>> that QTYPE_QNULL is never used.
>>
>> 1) migrate-set-parameters will always write QTYPE_QSTRING to
>> s->parameters, either an empty or non-empty string.
>>
>> 2) query-migrate-parameters will always return a QTYPE_QSTRING, either
>> empty or non-empty.
>>
>> 3) the migrate_tls_* helpers will always return a non-empty string or
>> NULL, for the internal migration code's consumption.
>>
>> Points (1) and (2) above help simplify the parameters validation and
>> the query command handling because s->parameters is already kept in
>> the format that query-migrate-parameters (and info migrate_paramters)
>> expect. Point (3) is so people don't need to care about StrOrNull in
>> migration code.
>>
>> This will allow the type duplication to be removed in the next
>> patches.
>>
>> Note that the type of @tls_creds, @tls-hostname, @tls-authz changes
>> from str to StrOrNull in introspection of the query-migrate-parameters
>> command. We accept this imprecision to enable de-duplication.
>>
>> There's no need to free the TLS options in
>> migration_instance_finalize() because they're freed by the qdev
>> properties .release method.
>>
>> Temporary in this patch:
>> migrate_params_test_apply() copies s->parameters into a temporary
>> structure, so it's necessary to drop the references to the TLS options
>> if they were not set by the user to avoid double-free. This is fixed
>> in the next patches.
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>
> [...]
>
>> diff --git a/migration/options.c b/migration/options.c
>> index 384ef9e421..f7bbdba5fc 100644
>> --- a/migration/options.c
>> +++ b/migration/options.c
>
> [...]
>
>> @@ -935,6 +951,37 @@ AnnounceParameters *migrate_announce_params(void)
>> return ≈
>> }
>>
>> +void migrate_tls_opts_free(MigrationParameters *params)
>> +{
>> + qapi_free_StrOrNull(params->tls_creds);
>> + qapi_free_StrOrNull(params->tls_hostname);
>> + qapi_free_StrOrNull(params->tls_authz);
>> +}
>> +
>> +/* either non-empty or empty string */
>
> This isn't true, because ...
>
>> +static void tls_opt_to_str(StrOrNull **tls_opt)
>> +{
>> + StrOrNull *opt = *tls_opt;
>> +
>> + if (!opt) {
>> + return;
>
> ... it can also be null.
>
Hmm, I'll have to double check, but with the StrOrNull property being
initialized, NULL should not be possible. This looks like a mistake.
> Maybe
>
> /* Normalize QTYPE_QNULL to QTYPE_QSTRING "" */
>
>> + }
>> +
>> + switch (opt->type) {
>> + case QTYPE_QSTRING:
>> + return;
>> + case QTYPE_QNULL:
>> + qobject_unref(opt->u.n);
>> + break;
>> + default:
>> + g_assert_not_reached();
>> + }
>> +
>> + opt->type = QTYPE_QSTRING;
>> + opt->u.s = g_strdup("");
>> + *tls_opt = opt;
>> +}
>
> I'd prefer something like
>
> if (!opt || opt->type == QTYPE_QSTRING) {
> return;
> }
> qobject_unref(opt->u.n);
> opt->type = QTYPE_QSTRING;
> opt->u.s = g_strdup("");
> *tls_opt = opt;
>
> But this is clearly a matter of taste.
>
>> +
>> MigrationParameters *qmp_query_migrate_parameters(Error **errp)
>> {
>> MigrationParameters *params;
>
> [...]
>
>> @@ -1251,18 +1294,24 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
>> }
>>
>> if (params->tls_creds) {
>> - assert(params->tls_creds->type == QTYPE_QSTRING);
>> - dest->tls_creds = params->tls_creds->u.s;
>> + dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
>> + } else {
>> + /* drop the reference, it's owned by s->parameters */
>> + dest->tls_creds = NULL;
>
> Suggest "clear the reference" to avoid associations with reference
> counting.
>
>> }
>>
>> if (params->tls_hostname) {
>> - assert(params->tls_hostname->type == QTYPE_QSTRING);
>> - dest->tls_hostname = params->tls_hostname->u.s;
>> + dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
>> + } else {
>> + /* drop the reference, it's owned by s->parameters */
>> + dest->tls_hostname = NULL;
>> }
>>
>> if (params->tls_authz) {
>> - assert(params->tls_authz->type == QTYPE_QSTRING);
>> - dest->tls_authz = params->tls_authz->u.s;
>> + dest->tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
>> + } else {
>> + /* drop the reference, it's owned by s->parameters */
>> + dest->tls_authz = NULL;
>> }
>>
>> if (params->has_max_bandwidth) {
>
> [...]
>
>> diff --git a/qapi/migration.json b/qapi/migration.json
>> index 4963f6ca12..97bb022c45 100644
>> --- a/qapi/migration.json
>> +++ b/qapi/migration.json
>> @@ -1293,9 +1293,9 @@
>> '*cpu-throttle-initial': 'uint8',
>> '*cpu-throttle-increment': 'uint8',
>> '*cpu-throttle-tailslow': 'bool',
>> - '*tls-creds': 'str',
>> - '*tls-hostname': 'str',
>> - '*tls-authz': 'str',
>> + '*tls-creds': 'StrOrNull',
>> + '*tls-hostname': 'StrOrNull',
>> + '*tls-authz': 'StrOrNull',
>> '*max-bandwidth': 'size',
>> '*avail-switchover-bandwidth': 'size',
>> '*downtime-limit': 'uint64',
>
> QAPI schema
> Acked-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 04/24] migration: Remove MigrateSetParameters
2025-07-01 8:00 ` Markus Armbruster
@ 2025-07-03 19:34 ` Fabiano Rosas
2025-07-04 4:25 ` Markus Armbruster
0 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-07-03 19:34 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, berrange, armbru, Peter Xu, Eric Blake
Markus Armbruster <armbru@redhat.com> writes:
> Fabiano Rosas <farosas@suse.de> writes:
>
>> Now that the TLS options have been made the same between
>> migrate-set-parameters and query-migrate-parameters, a single type can
>> be used. Remove MigrateSetParameters.
>>
>> The TLS options documentation from MigrationParameters were replaced
>> with the ones from MigrateSetParameters which was more complete.
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>
> [...]
>
>> diff --git a/qapi/migration.json b/qapi/migration.json
>> index 97bb022c45..3788c39857 100644
>> --- a/qapi/migration.json
>> +++ b/qapi/migration.json
>> @@ -914,206 +914,10 @@
>> 'zero-page-detection',
>> 'direct-io'] }
>>
>> -##
>> -# @MigrateSetParameters:
>
> [...]
>
>> ##
>> # @migrate-set-parameters:
>> #
>> -# Set various migration parameters.
>> +# Set migration parameters. All fields are optional.
>
> Use "arguments" instead of "fields".
>
>> #
>> # Since: 2.4
>> #
>> @@ -1124,13 +928,11 @@
>> # <- { "return": {} }
>> ##
>> { 'command': 'migrate-set-parameters', 'boxed': true,
>> - 'data': 'MigrateSetParameters' }
>> + 'data': 'MigrationParameters' }
>>
>> ##
>> # @MigrationParameters:
>> #
>> -# The optional members aren't actually optional.
>> -#
>> # @announce-initial: Initial delay (in milliseconds) before sending
>> # the first announce (Since 4.0)
>> #
>> @@ -1148,12 +950,12 @@
>> # percentage. The default value is 50. (Since 5.0)
>> #
>> # @cpu-throttle-initial: Initial percentage of time guest cpus are
>> -# throttled when migration auto-converge is activated.
>> -# (Since 2.7)
>> +# throttled when migration auto-converge is activated. The
>> +# default value is 20. (Since 2.7)
>> #
>> # @cpu-throttle-increment: throttle percentage increase each time
>> # auto-converge detects that migration is not making progress.
>> -# (Since 2.7)
>> +# The default value is 10. (Since 2.7)
>> #
>> # @cpu-throttle-tailslow: Make CPU throttling slower at tail stage.
>> # At the tail stage of throttling, the Guest is very sensitive to
>> @@ -1172,21 +974,25 @@
>> # for establishing a TLS connection over the migration data
>> # channel. On the outgoing side of the migration, the credentials
>> # must be for a 'client' endpoint, while for the incoming side the
>> -# credentials must be for a 'server' endpoint. An empty string
>> -# means that QEMU will use plain text mode for migration, rather
>> -# than TLS. (Since 2.7)
>> -#
>> -# Note: 2.8 omits empty @tls-creds instead.
>> +# credentials must be for a 'server' endpoint. Setting this to a
>> +# non-empty string enables TLS for all migrations. An empty
>> +# string means that QEMU will use plain text mode for migration,
>> +# rather than TLS. This is the default. (Since 2.7)
>> #
>> # @tls-hostname: migration target's hostname for validating the
>> # server's x509 certificate identity. If empty, QEMU will use the
>> -# hostname from the migration URI, if any. (Since 2.7)
>> +# hostname from the migration URI, if any. A non-empty value is
>> +# required when using x509 based TLS credentials and the migration
>> +# URI does not include a hostname, such as fd: or exec: based
>> +# migration. (Since 2.7)
>> #
>> -# Note: 2.8 omits empty @tls-hostname instead.
>> +# Note: empty value works only since 2.9.
>> #
>> # @tls-authz: ID of the 'authz' object subclass that provides access
>> # control checking of the TLS x509 certificate distinguished name.
>> -# (Since 4.0)
>> +# This object is only resolved at time of use, so can be deleted
>> +# and recreated on the fly while the migration server is active.
>> +# If missing, it will default to denying access (Since 4.0)
>> #
>> # @max-bandwidth: maximum speed for migration, in bytes per second.
>> # (Since 2.8)
>> @@ -1205,8 +1011,8 @@
>> # @downtime-limit: set maximum tolerated downtime for migration.
>> # maximum downtime in milliseconds (Since 2.8)
>> #
>> -# @x-checkpoint-delay: the delay time between two COLO checkpoints.
>> -# (Since 2.8)
>> +# @x-checkpoint-delay: the delay time between two COLO checkpoints in
>> +# periodic mode. (Since 2.8)
>> #
>> # @multifd-channels: Number of channels used to migrate data in
>> # parallel. This is the same number that the number of sockets
>
> Please add
>
> ##
> # @query-migrate-parameters:
> #
> -# Return information about the current migration parameters
> +# Return information about the current migration parameters.
> +# Optional members of the return value are always present.
> #
> # Returns: @MigrationParameters
> #
> # Since: 2.4
> #
>
> and double-check "always" is actually true.
It's not, block-bitmap-mapping needs to be kept optional for
compatibility.
What about:
# Return information about the current migration parameters. Optional
# members of the return value are always present, except for
# block-bitmap-mapping that's only present if it has been previously
# set.
>
> With that, QAPI schema
> Acked-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 01/24] migration: Fix leak of block_bitmap_mapping
2025-07-01 6:12 ` Markus Armbruster
@ 2025-07-03 21:31 ` Peter Xu
2025-07-04 5:09 ` Markus Armbruster
0 siblings, 1 reply; 73+ messages in thread
From: Peter Xu @ 2025-07-03 21:31 UTC (permalink / raw)
To: Markus Armbruster; +Cc: Fabiano Rosas, qemu-devel, berrange
On Tue, Jul 01, 2025 at 08:12:27AM +0200, Markus Armbruster wrote:
> Fabiano Rosas <farosas@suse.de> writes:
>
> > Caught by inspection, but ASAN also reports:
> >
> > Direct leak of 16 byte(s) in 1 object(s) allocated from:
> > #0 in malloc
> > #1 in g_malloc
> > #2 in g_memdup
> > #3 in qapi_clone_start_struct ../qapi/qapi-clone-visitor.c:40:12
> > #4 in qapi_clone_start_list ../qapi/qapi-clone-visitor.c:59:12
> > #5 in visit_start_list ../qapi/qapi-visit-core.c:80:10
> > #6 in visit_type_BitmapMigrationNodeAliasList qapi/qapi-visit-migration.c:639:10
> > #7 in migrate_params_apply ../migration/options.c:1407:13
> > #8 in qmp_migrate_set_parameters ../migration/options.c:1463:5
> > #9 in qmp_marshal_migrate_set_parameters qapi/qapi-commands-migration.c:214:5
> > #10 in do_qmp_dispatch_bh ../qapi/qmp-dispatch.c:128:5
>
> migration_instance_finalize() runs when a TYPE_MIGRATION object dies, we
> have just one such object, pointed to by @current_migration, and it
> lives until QEMU shuts down.
>
> So this is as harmless as they get. Please mentions this in the commit
> message, to guide backporters.
If we do not copy qemu-stable, and do not attach Fixes, logically it should
imply no backport needed. Not sure if it was intentional, though.. Agreed
some enrichment in the log would always be nicer.
>
> > Signed-off-by: Fabiano Rosas <farosas@suse.de>
> > ---
> > migration/migration.c | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/migration/migration.c b/migration/migration.c
> > index 4098870bce..7ec60d97f9 100644
> > --- a/migration/migration.c
> > +++ b/migration/migration.c
> > @@ -4050,6 +4050,7 @@ static void migration_instance_finalize(Object *obj)
> > {
> > MigrationState *ms = MIGRATION_OBJ(obj);
> >
> > + qapi_free_BitmapMigrationNodeAliasList(ms->parameters.block_bitmap_mapping);
> > qemu_mutex_destroy(&ms->error_mutex);
> > qemu_mutex_destroy(&ms->qemu_file_lock);
> > qemu_sem_destroy(&ms->wait_unplug_sem);
>
> With an adjusted commit message:
> Reviewed-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 02/24] migration: Add a qdev property for StrOrNull
2025-07-01 6:38 ` Markus Armbruster
@ 2025-07-03 22:32 ` Peter Xu
2025-07-04 12:58 ` Fabiano Rosas
0 siblings, 1 reply; 73+ messages in thread
From: Peter Xu @ 2025-07-03 22:32 UTC (permalink / raw)
To: Markus Armbruster; +Cc: Fabiano Rosas, qemu-devel, berrange
On Tue, Jul 01, 2025 at 08:38:19AM +0200, Markus Armbruster wrote:
> Fabiano Rosas <farosas@suse.de> writes:
>
> > The MigrationState is a QOM object with TYPE_DEVICE as a parent. This
> > was done about eight years ago so the migration code could make use of
> > qdev properties to define the defaults for the migration parameters
> > and to be able to expose migration knobs for debugging via the
> > '-global migration' command line option.
> >
> > Due to unrelated historical reasons, three of the migration parameters
> > (TLS options) received different types when used via the
> > query-migrate-parameters QMP command than with the
> > migrate-set-parameters command. This has created a lot of duplication
> > in the migration code and in the QAPI documentation because the whole
> > of MigrationParameters had to be duplicated as well.
> >
> > The migration code is now being fixed to remove the duplication and
> > for that to happen the offending fields need to be reconciled into a
> > single type. The StrOrNull type is going to be used.
> >
> > To keep the command line compatibility, the parameters need to
> > continue being exposed via qdev properties accessible from the command
> > line. Introduce a qdev property StrOrNull just for that.
> >
> > Note that this code is being kept in migration/options.c because this
> > version of StrOrNull doesn't need to handle QNULL because it was never
> > a valid option in the previous command line, which took a string.
> >
> > Signed-off-by: Fabiano Rosas <farosas@suse.de>
> > ---
> > migration/options.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 47 insertions(+)
> >
> > diff --git a/migration/options.c b/migration/options.c
> > index 162c72cda4..384ef9e421 100644
> > --- a/migration/options.c
> > +++ b/migration/options.c
> > @@ -83,6 +83,11 @@
> > #define DEFINE_PROP_MIG_CAP(name, x) \
> > DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)
> >
> > +const PropertyInfo qdev_prop_StrOrNull;
> > +#define DEFINE_PROP_STR_OR_NULL(_name, _state, _field) \
> > + DEFINE_PROP(_name, _state, _field, qdev_prop_StrOrNull, StrOrNull *, \
> > + .set_default = true)
> > +
> > #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD 1000 /* milliseconds */
> > #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT 1 /* MB/s */
> >
> > @@ -204,6 +209,48 @@ const Property migration_properties[] = {
> > };
> > const size_t migration_properties_count = ARRAY_SIZE(migration_properties);
> >
> > +/*
> > + * qdev property for TLS options handling via '-global migration'
> > + * command line.
> > + */
>
> Looks like this was a function comment. It's not, it applies to the
> PropertyInfo and its method. Move it to the PropertyInfo?
>
> Maybe
>
> /*
> * String property like qdev_prop_string, except it's backed by a
> * StrOrNull * instead of a char *. This is intended for
> * TYPE_MIGRATION's TLS options.
> */
>
> > +static void set_StrOrNull(Object *obj, Visitor *v, const char *name,
> > + void *opaque, Error **errp)
> > +{
> > + const Property *prop = opaque;
> > + StrOrNull **ptr = object_field_prop_ptr(obj, prop);
> > + StrOrNull *str_or_null = g_new0(StrOrNull, 1);
> > +
> > + /*
> > + * Only str to keep compatibility, QNULL was never used via
> > + * command line.
> > + */
> > + str_or_null->type = QTYPE_QSTRING;
> > + if (!visit_type_str(v, name, &str_or_null->u.s, errp)) {
> > + return;
> > + }
> > +
> > + qapi_free_StrOrNull(*ptr);
> > + *ptr = str_or_null;
> > +}
> > +
> > +static void release_StrOrNull(Object *obj, const char *name, void *opaque)
> > +{
> > + const Property *prop = opaque;
> > + qapi_free_StrOrNull(*(StrOrNull **)object_field_prop_ptr(obj, prop));
> > +}
> > +
> > +static void set_default_value_tls_opt(ObjectProperty *op, const Property *prop)
> > +{
> > + object_property_set_default_str(op, "");
> > +}
> > +
> > +const PropertyInfo qdev_prop_StrOrNull = {
> > + .type = "StrOrNull",
> > + .set = set_StrOrNull,
> > + .release = release_StrOrNull,
> > + .set_default_value = set_default_value_tls_opt,
> > +};
>
> No getter, i.e. properties will be write-only. This is unusual. Is it
> safe?
Fair question..
I had a quick look, device_class_set_props_n() will try to register the
prop with legacy mode first then modern mode. Legacy mode is decided by
[1] below:
static void qdev_class_add_legacy_property(DeviceClass *dc, const Property *prop)
{
g_autofree char *name = NULL;
/* Register pointer properties as legacy properties */
if (!prop->info->print && prop->info->get) { <------------------ [1]
return;
}
name = g_strdup_printf("legacy-%s", prop->name);
object_class_property_add(OBJECT_CLASS(dc), name, "str",
prop->info->print ? qdev_get_legacy_property : prop->info->get,
NULL, NULL, (Property *)prop);
}
When with no get(), it seems it'll be wrongly treated as legacy property..
which further means whoever tries to get() on the property will invoke
qdev_get_legacy_property(), and likely crash on accessing info->print()..
The other issue is legacy property doesn't look like to provide a setter
function.. as it's passing NULL to object_class_property_add(set=XXX).
Likely we'll need to provide get() if without changing qdev code.
>
> > +
> > bool migrate_auto_converge(void)
> > {
> > MigrationState *s = migrate_get_current();
>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 04/24] migration: Remove MigrateSetParameters
2025-07-03 19:34 ` Fabiano Rosas
@ 2025-07-04 4:25 ` Markus Armbruster
0 siblings, 0 replies; 73+ messages in thread
From: Markus Armbruster @ 2025-07-04 4:25 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, Peter Xu, Eric Blake
Fabiano Rosas <farosas@suse.de> writes:
> Markus Armbruster <armbru@redhat.com> writes:
>
>> Fabiano Rosas <farosas@suse.de> writes:
>>
>>> Now that the TLS options have been made the same between
>>> migrate-set-parameters and query-migrate-parameters, a single type can
>>> be used. Remove MigrateSetParameters.
>>>
>>> The TLS options documentation from MigrationParameters were replaced
>>> with the ones from MigrateSetParameters which was more complete.
>>>
>>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>>
>> [...]
>>
>>> diff --git a/qapi/migration.json b/qapi/migration.json
>>> index 97bb022c45..3788c39857 100644
>>> --- a/qapi/migration.json
>>> +++ b/qapi/migration.json
[...]
>>> @@ -1205,8 +1011,8 @@
>>> # @downtime-limit: set maximum tolerated downtime for migration.
>>> # maximum downtime in milliseconds (Since 2.8)
>>> #
>>> -# @x-checkpoint-delay: the delay time between two COLO checkpoints.
>>> -# (Since 2.8)
>>> +# @x-checkpoint-delay: the delay time between two COLO checkpoints in
>>> +# periodic mode. (Since 2.8)
>>> #
>>> # @multifd-channels: Number of channels used to migrate data in
>>> # parallel. This is the same number that the number of sockets
>>
>> Please add
>>
>> ##
>> # @query-migrate-parameters:
>> #
>> -# Return information about the current migration parameters
>> +# Return information about the current migration parameters.
>> +# Optional members of the return value are always present.
>> #
>> # Returns: @MigrationParameters
>> #
>> # Since: 2.4
>> #
>>
>> and double-check "always" is actually true.
>
> It's not, block-bitmap-mapping needs to be kept optional for
> compatibility.
>
> What about:
>
> # Return information about the current migration parameters. Optional
> # members of the return value are always present, except for
> # block-bitmap-mapping that's only present if it has been previously
> # set.
Suggest "except @block-bitmap-mapping is only present if" or "execpt for
@block-bitmap-mapping, which is only present if".
>> With that, QAPI schema
>> Acked-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 01/24] migration: Fix leak of block_bitmap_mapping
2025-07-03 21:31 ` Peter Xu
@ 2025-07-04 5:09 ` Markus Armbruster
0 siblings, 0 replies; 73+ messages in thread
From: Markus Armbruster @ 2025-07-04 5:09 UTC (permalink / raw)
To: Peter Xu; +Cc: Fabiano Rosas, qemu-devel, berrange
Peter Xu <peterx@redhat.com> writes:
> On Tue, Jul 01, 2025 at 08:12:27AM +0200, Markus Armbruster wrote:
>> Fabiano Rosas <farosas@suse.de> writes:
>>
>> > Caught by inspection, but ASAN also reports:
>> >
>> > Direct leak of 16 byte(s) in 1 object(s) allocated from:
>> > #0 in malloc
>> > #1 in g_malloc
>> > #2 in g_memdup
>> > #3 in qapi_clone_start_struct ../qapi/qapi-clone-visitor.c:40:12
>> > #4 in qapi_clone_start_list ../qapi/qapi-clone-visitor.c:59:12
>> > #5 in visit_start_list ../qapi/qapi-visit-core.c:80:10
>> > #6 in visit_type_BitmapMigrationNodeAliasList qapi/qapi-visit-migration.c:639:10
>> > #7 in migrate_params_apply ../migration/options.c:1407:13
>> > #8 in qmp_migrate_set_parameters ../migration/options.c:1463:5
>> > #9 in qmp_marshal_migrate_set_parameters qapi/qapi-commands-migration.c:214:5
>> > #10 in do_qmp_dispatch_bh ../qapi/qmp-dispatch.c:128:5
>>
>> migration_instance_finalize() runs when a TYPE_MIGRATION object dies, we
>> have just one such object, pointed to by @current_migration, and it
>> lives until QEMU shuts down.
>>
>> So this is as harmless as they get. Please mentions this in the commit
>> message, to guide backporters.
>
> If we do not copy qemu-stable, and do not attach Fixes, logically it should
> imply no backport needed. Not sure if it was intentional, though..
Yes, qemu-stable@ and Fixes: are how we indicate "consider backporting
this". But since that's easily forgotten, absence doesn't imply "no
need to consider".
> Agreed
> some enrichment in the log would always be nicer.
Spelling out the impact of the bug fixes is a good habit. Or in this
case, the fact that it's not a bug. No biggie here, just nice. I like
nice commit messages :)
[...]
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 02/24] migration: Add a qdev property for StrOrNull
2025-07-03 22:32 ` Peter Xu
@ 2025-07-04 12:58 ` Fabiano Rosas
0 siblings, 0 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-07-04 12:58 UTC (permalink / raw)
To: Peter Xu, Markus Armbruster; +Cc: qemu-devel, berrange
Peter Xu <peterx@redhat.com> writes:
> On Tue, Jul 01, 2025 at 08:38:19AM +0200, Markus Armbruster wrote:
>> Fabiano Rosas <farosas@suse.de> writes:
>>
>> > The MigrationState is a QOM object with TYPE_DEVICE as a parent. This
>> > was done about eight years ago so the migration code could make use of
>> > qdev properties to define the defaults for the migration parameters
>> > and to be able to expose migration knobs for debugging via the
>> > '-global migration' command line option.
>> >
>> > Due to unrelated historical reasons, three of the migration parameters
>> > (TLS options) received different types when used via the
>> > query-migrate-parameters QMP command than with the
>> > migrate-set-parameters command. This has created a lot of duplication
>> > in the migration code and in the QAPI documentation because the whole
>> > of MigrationParameters had to be duplicated as well.
>> >
>> > The migration code is now being fixed to remove the duplication and
>> > for that to happen the offending fields need to be reconciled into a
>> > single type. The StrOrNull type is going to be used.
>> >
>> > To keep the command line compatibility, the parameters need to
>> > continue being exposed via qdev properties accessible from the command
>> > line. Introduce a qdev property StrOrNull just for that.
>> >
>> > Note that this code is being kept in migration/options.c because this
>> > version of StrOrNull doesn't need to handle QNULL because it was never
>> > a valid option in the previous command line, which took a string.
>> >
>> > Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> > ---
>> > migration/options.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
>> > 1 file changed, 47 insertions(+)
>> >
>> > diff --git a/migration/options.c b/migration/options.c
>> > index 162c72cda4..384ef9e421 100644
>> > --- a/migration/options.c
>> > +++ b/migration/options.c
>> > @@ -83,6 +83,11 @@
>> > #define DEFINE_PROP_MIG_CAP(name, x) \
>> > DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)
>> >
>> > +const PropertyInfo qdev_prop_StrOrNull;
>> > +#define DEFINE_PROP_STR_OR_NULL(_name, _state, _field) \
>> > + DEFINE_PROP(_name, _state, _field, qdev_prop_StrOrNull, StrOrNull *, \
>> > + .set_default = true)
>> > +
>> > #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD 1000 /* milliseconds */
>> > #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT 1 /* MB/s */
>> >
>> > @@ -204,6 +209,48 @@ const Property migration_properties[] = {
>> > };
>> > const size_t migration_properties_count = ARRAY_SIZE(migration_properties);
>> >
>> > +/*
>> > + * qdev property for TLS options handling via '-global migration'
>> > + * command line.
>> > + */
>>
>> Looks like this was a function comment. It's not, it applies to the
>> PropertyInfo and its method. Move it to the PropertyInfo?
>>
>> Maybe
>>
>> /*
>> * String property like qdev_prop_string, except it's backed by a
>> * StrOrNull * instead of a char *. This is intended for
>> * TYPE_MIGRATION's TLS options.
>> */
>>
>> > +static void set_StrOrNull(Object *obj, Visitor *v, const char *name,
>> > + void *opaque, Error **errp)
>> > +{
>> > + const Property *prop = opaque;
>> > + StrOrNull **ptr = object_field_prop_ptr(obj, prop);
>> > + StrOrNull *str_or_null = g_new0(StrOrNull, 1);
>> > +
>> > + /*
>> > + * Only str to keep compatibility, QNULL was never used via
>> > + * command line.
>> > + */
>> > + str_or_null->type = QTYPE_QSTRING;
>> > + if (!visit_type_str(v, name, &str_or_null->u.s, errp)) {
>> > + return;
>> > + }
>> > +
>> > + qapi_free_StrOrNull(*ptr);
>> > + *ptr = str_or_null;
>> > +}
>> > +
>> > +static void release_StrOrNull(Object *obj, const char *name, void *opaque)
>> > +{
>> > + const Property *prop = opaque;
>> > + qapi_free_StrOrNull(*(StrOrNull **)object_field_prop_ptr(obj, prop));
>> > +}
>> > +
>> > +static void set_default_value_tls_opt(ObjectProperty *op, const Property *prop)
>> > +{
>> > + object_property_set_default_str(op, "");
>> > +}
>> > +
>> > +const PropertyInfo qdev_prop_StrOrNull = {
>> > + .type = "StrOrNull",
>> > + .set = set_StrOrNull,
>> > + .release = release_StrOrNull,
>> > + .set_default_value = set_default_value_tls_opt,
>> > +};
>>
>> No getter, i.e. properties will be write-only. This is unusual. Is it
>> safe?
>
> Fair question..
>
> I had a quick look, device_class_set_props_n() will try to register the
> prop with legacy mode first then modern mode. Legacy mode is decided by
> [1] below:
>
> static void qdev_class_add_legacy_property(DeviceClass *dc, const Property *prop)
> {
> g_autofree char *name = NULL;
>
> /* Register pointer properties as legacy properties */
> if (!prop->info->print && prop->info->get) { <------------------ [1]
> return;
> }
>
> name = g_strdup_printf("legacy-%s", prop->name);
> object_class_property_add(OBJECT_CLASS(dc), name, "str",
> prop->info->print ? qdev_get_legacy_property : prop->info->get,
> NULL, NULL, (Property *)prop);
> }
>
> When with no get(), it seems it'll be wrongly treated as legacy property..
> which further means whoever tries to get() on the property will invoke
> qdev_get_legacy_property(), and likely crash on accessing info->print()..
>
> The other issue is legacy property doesn't look like to provide a setter
> function.. as it's passing NULL to object_class_property_add(set=XXX).
>
> Likely we'll need to provide get() if without changing qdev code.
>
Peter, thank you for the analysis and sorry all for not commenting on
this earlier. I have reached the same conclusions and have implemented
the .get method.
>>
>> > +
>> > bool migrate_auto_converge(void)
>> > {
>> > MigrationState *s = migrate_get_current();
>>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 03/24] migration: Normalize tls arguments
2025-07-01 14:20 ` Fabiano Rosas
@ 2025-07-04 13:12 ` Fabiano Rosas
2025-07-04 15:37 ` Peter Xu
0 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-07-04 13:12 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, berrange, Peter Xu, Eric Blake
Fabiano Rosas <farosas@suse.de> writes:
> Markus Armbruster <armbru@redhat.com> writes:
>
>> Fabiano Rosas <farosas@suse.de> writes:
>>
...
>>> diff --git a/migration/options.c b/migration/options.c
>>> index 384ef9e421..f7bbdba5fc 100644
>>> --- a/migration/options.c
>>> +++ b/migration/options.c
>>
>> [...]
>>
>>> @@ -935,6 +951,37 @@ AnnounceParameters *migrate_announce_params(void)
>>> return ≈
>>> }
>>>
>>> +void migrate_tls_opts_free(MigrationParameters *params)
>>> +{
>>> + qapi_free_StrOrNull(params->tls_creds);
>>> + qapi_free_StrOrNull(params->tls_hostname);
>>> + qapi_free_StrOrNull(params->tls_authz);
>>> +}
>>> +
>>> +/* either non-empty or empty string */
>>
>> This isn't true, because ...
>>
>>> +static void tls_opt_to_str(StrOrNull **tls_opt)
>>> +{
>>> + StrOrNull *opt = *tls_opt;
>>> +
>>> + if (!opt) {
>>> + return;
>>
>> ... it can also be null.
>>
>
> Hmm, I'll have to double check, but with the StrOrNull property being
> initialized, NULL should not be possible. This looks like a mistake.
>
The code is correct, this is coming from the QAPI, so it could be NULL
in case the user hasn't provided the option. I'll use your suggested
wording and the code suggestion as well.
>> Maybe
>>
>> /* Normalize QTYPE_QNULL to QTYPE_QSTRING "" */
>>
>>> + }
>>> +
>>> + switch (opt->type) {
>>> + case QTYPE_QSTRING:
>>> + return;
>>> + case QTYPE_QNULL:
>>> + qobject_unref(opt->u.n);
>>> + break;
>>> + default:
>>> + g_assert_not_reached();
>>> + }
>>> +
>>> + opt->type = QTYPE_QSTRING;
>>> + opt->u.s = g_strdup("");
>>> + *tls_opt = opt;
>>> +}
>>
>> I'd prefer something like
>>
>> if (!opt || opt->type == QTYPE_QSTRING) {
>> return;
>> }
>> qobject_unref(opt->u.n);
>> opt->type = QTYPE_QSTRING;
>> opt->u.s = g_strdup("");
>> *tls_opt = opt;
>>
>> But this is clearly a matter of taste.
This is better indeed. I was moving back-and-forth between
implementations and the code ended up a bit weird. Thanks!
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 16/24] migration: Add capabilities into MigrationParameters
2025-07-01 8:25 ` Markus Armbruster
@ 2025-07-04 13:15 ` Fabiano Rosas
2025-07-04 14:04 ` Markus Armbruster
0 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-07-04 13:15 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, berrange, Peter Xu, Eric Blake
Markus Armbruster <armbru@redhat.com> writes:
> Fabiano Rosas <farosas@suse.de> writes:
>
>> Add capabilities to MigrationParameters. This structure will hold all
>> migration options. Capabilities will go away in the next patch.
>>
>> Also add capabilities to MigrationParameter as the enum needs to be
>> kept in sync with MigrationParameters. This affects the parsing of
>> migration HMP commands so make the necessary additions there too.
>>
>> From this point on, both QMP and HMP versions of
>> migrate-set-parameters and query-migrate-parameters gain the ability
>> to work with capabilities.
>>
>> With MigrationParameters now having members for each capability, the
>> migration capabilities commands (query-migrate-capabilities,
>> migrate-set-capabilities) will soon be deprecated. Add a set of
>> helpers to convert between the old MigrationCapability representation
>> and the new representation as members of MigrationParameters.
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>
> [...]
>
>> diff --git a/qapi/migration.json b/qapi/migration.json
>> index 40e00fb86e..3d3f5624c5 100644
>> --- a/qapi/migration.json
>> +++ b/qapi/migration.json
>> @@ -763,7 +763,14 @@
>> 'vcpu-dirty-limit',
>> 'mode',
>> 'zero-page-detection',
>> - 'direct-io'] }
>> + 'direct-io', 'xbzrle', 'rdma-pin-all', 'auto-converge',
>> + 'zero-blocks', 'events', 'postcopy-ram', 'x-colo',
>> + 'release-ram', 'return-path', 'pause-before-switchover',
>> + 'multifd', 'dirty-bitmaps', 'postcopy-blocktime',
>> + 'late-block-activate', 'x-ignore-shared',
>> + 'validate-uuid', 'background-snapshot',
>> + 'zero-copy-send', 'postcopy-preempt',
>> + 'switchover-ack', 'dirty-limit', 'mapped-ram' ] }
>
> This is MigrateParameter. Different order than in MigrationParameters.
> Intentional?
>
I think you mean the pre-existing difference in the order of the
compression options multifd-*-level? I'll fix that.
If it's something else, it eludes my gaze.
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 16/24] migration: Add capabilities into MigrationParameters
2025-07-04 13:15 ` Fabiano Rosas
@ 2025-07-04 14:04 ` Markus Armbruster
2025-07-04 14:48 ` Fabiano Rosas
0 siblings, 1 reply; 73+ messages in thread
From: Markus Armbruster @ 2025-07-04 14:04 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, Peter Xu, Eric Blake
Fabiano Rosas <farosas@suse.de> writes:
> Markus Armbruster <armbru@redhat.com> writes:
>
>> Fabiano Rosas <farosas@suse.de> writes:
>>
>>> Add capabilities to MigrationParameters. This structure will hold all
>>> migration options. Capabilities will go away in the next patch.
>>>
>>> Also add capabilities to MigrationParameter as the enum needs to be
>>> kept in sync with MigrationParameters. This affects the parsing of
>>> migration HMP commands so make the necessary additions there too.
>>>
>>> From this point on, both QMP and HMP versions of
>>> migrate-set-parameters and query-migrate-parameters gain the ability
>>> to work with capabilities.
>>>
>>> With MigrationParameters now having members for each capability, the
>>> migration capabilities commands (query-migrate-capabilities,
>>> migrate-set-capabilities) will soon be deprecated. Add a set of
>>> helpers to convert between the old MigrationCapability representation
>>> and the new representation as members of MigrationParameters.
>>>
>>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>>
>> [...]
>>
>>> diff --git a/qapi/migration.json b/qapi/migration.json
>>> index 40e00fb86e..3d3f5624c5 100644
>>> --- a/qapi/migration.json
>>> +++ b/qapi/migration.json
>>> @@ -763,7 +763,14 @@
>>> 'vcpu-dirty-limit',
>>> 'mode',
>>> 'zero-page-detection',
>>> - 'direct-io'] }
>>> + 'direct-io', 'xbzrle', 'rdma-pin-all', 'auto-converge',
>>> + 'zero-blocks', 'events', 'postcopy-ram', 'x-colo',
>>> + 'release-ram', 'return-path', 'pause-before-switchover',
>>> + 'multifd', 'dirty-bitmaps', 'postcopy-blocktime',
>>> + 'late-block-activate', 'x-ignore-shared',
>>> + 'validate-uuid', 'background-snapshot',
>>> + 'zero-copy-send', 'postcopy-preempt',
>>> + 'switchover-ack', 'dirty-limit', 'mapped-ram' ] }
>>
>> This is MigrateParameter. Different order than in MigrationParameters.
>> Intentional?
>>
>
> I think you mean the pre-existing difference in the order of the
> compression options multifd-*-level? I'll fix that.
I noticed the new members are in a different order than in
MigrationParameters. I didn't notice the existing members differ, too.
> If it's something else, it eludes my gaze.
No.
Thanks!
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 16/24] migration: Add capabilities into MigrationParameters
2025-07-04 14:04 ` Markus Armbruster
@ 2025-07-04 14:48 ` Fabiano Rosas
2025-07-04 15:04 ` Markus Armbruster
0 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-07-04 14:48 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, berrange, Peter Xu, Eric Blake
Markus Armbruster <armbru@redhat.com> writes:
> Fabiano Rosas <farosas@suse.de> writes:
>
>> Markus Armbruster <armbru@redhat.com> writes:
>>
>>> Fabiano Rosas <farosas@suse.de> writes:
>>>
>>>> Add capabilities to MigrationParameters. This structure will hold all
>>>> migration options. Capabilities will go away in the next patch.
>>>>
>>>> Also add capabilities to MigrationParameter as the enum needs to be
>>>> kept in sync with MigrationParameters. This affects the parsing of
>>>> migration HMP commands so make the necessary additions there too.
>>>>
>>>> From this point on, both QMP and HMP versions of
>>>> migrate-set-parameters and query-migrate-parameters gain the ability
>>>> to work with capabilities.
>>>>
>>>> With MigrationParameters now having members for each capability, the
>>>> migration capabilities commands (query-migrate-capabilities,
>>>> migrate-set-capabilities) will soon be deprecated. Add a set of
>>>> helpers to convert between the old MigrationCapability representation
>>>> and the new representation as members of MigrationParameters.
>>>>
>>>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>>>
>>> [...]
>>>
>>>> diff --git a/qapi/migration.json b/qapi/migration.json
>>>> index 40e00fb86e..3d3f5624c5 100644
>>>> --- a/qapi/migration.json
>>>> +++ b/qapi/migration.json
>>>> @@ -763,7 +763,14 @@
>>>> 'vcpu-dirty-limit',
>>>> 'mode',
>>>> 'zero-page-detection',
>>>> - 'direct-io'] }
>>>> + 'direct-io', 'xbzrle', 'rdma-pin-all', 'auto-converge',
>>>> + 'zero-blocks', 'events', 'postcopy-ram', 'x-colo',
>>>> + 'release-ram', 'return-path', 'pause-before-switchover',
>>>> + 'multifd', 'dirty-bitmaps', 'postcopy-blocktime',
>>>> + 'late-block-activate', 'x-ignore-shared',
>>>> + 'validate-uuid', 'background-snapshot',
>>>> + 'zero-copy-send', 'postcopy-preempt',
>>>> + 'switchover-ack', 'dirty-limit', 'mapped-ram' ] }
>>>
>>> This is MigrateParameter. Different order than in MigrationParameters.
>>> Intentional?
>>>
>>
>> I think you mean the pre-existing difference in the order of the
>> compression options multifd-*-level? I'll fix that.
>
> I noticed the new members are in a different order than in
> MigrationParameters. I didn't notice the existing members differ, too.
>
Sorry, I don't see it, we must be looking at different things.
>> If it's something else, it eludes my gaze.
>
> No.
>
> Thanks!
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 16/24] migration: Add capabilities into MigrationParameters
2025-07-04 14:48 ` Fabiano Rosas
@ 2025-07-04 15:04 ` Markus Armbruster
0 siblings, 0 replies; 73+ messages in thread
From: Markus Armbruster @ 2025-07-04 15:04 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, Peter Xu, Eric Blake
Fabiano Rosas <farosas@suse.de> writes:
>> Markus Armbruster <armbru@redhat.com> writes:
>
>> Fabiano Rosas <farosas@suse.de> writes:
>>
>>> Markus Armbruster <armbru@redhat.com> writes:
>>>
>>>> Fabiano Rosas <farosas@suse.de> writes:
>>>>
>>>>> Add capabilities to MigrationParameters. This structure will hold all
>>>>> migration options. Capabilities will go away in the next patch.
>>>>>
>>>>> Also add capabilities to MigrationParameter as the enum needs to be
>>>>> kept in sync with MigrationParameters. This affects the parsing of
>>>>> migration HMP commands so make the necessary additions there too.
>>>>>
>>>>> From this point on, both QMP and HMP versions of
>>>>> migrate-set-parameters and query-migrate-parameters gain the ability
>>>>> to work with capabilities.
>>>>>
>>>>> With MigrationParameters now having members for each capability, the
>>>>> migration capabilities commands (query-migrate-capabilities,
>>>>> migrate-set-capabilities) will soon be deprecated. Add a set of
>>>>> helpers to convert between the old MigrationCapability representation
>>>>> and the new representation as members of MigrationParameters.
>>>>>
>>>>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>>>>
>>>> [...]
>>>>
>>>>> diff --git a/qapi/migration.json b/qapi/migration.json
>>>>> index 40e00fb86e..3d3f5624c5 100644
>>>>> --- a/qapi/migration.json
>>>>> +++ b/qapi/migration.json
>>>>> @@ -763,7 +763,14 @@
>>>>> 'vcpu-dirty-limit',
>>>>> 'mode',
>>>>> 'zero-page-detection',
>>>>> - 'direct-io'] }
>>>>> + 'direct-io', 'xbzrle', 'rdma-pin-all', 'auto-converge',
>>>>> + 'zero-blocks', 'events', 'postcopy-ram', 'x-colo',
>>>>> + 'release-ram', 'return-path', 'pause-before-switchover',
>>>>> + 'multifd', 'dirty-bitmaps', 'postcopy-blocktime',
>>>>> + 'late-block-activate', 'x-ignore-shared',
>>>>> + 'validate-uuid', 'background-snapshot',
>>>>> + 'zero-copy-send', 'postcopy-preempt',
>>>>> + 'switchover-ack', 'dirty-limit', 'mapped-ram' ] }
>>>>
>>>> This is MigrateParameter. Different order than in MigrationParameters.
>>>> Intentional?
>>>>
>>>
>>> I think you mean the pre-existing difference in the order of the
>>> compression options multifd-*-level? I'll fix that.
>>
>> I noticed the new members are in a different order than in
>> MigrationParameters. I didn't notice the existing members differ, too.
>>
>
> Sorry, I don't see it, we must be looking at different things.
Misunderstanding? Quite possibly on my part!
Let's keep the members of MigrationParameter in the same order as the
members of MigrationParameters. In case they already are: nevermind!
>
>>> If it's something else, it eludes my gaze.
>>
>> No.
>>
>> Thanks!
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 03/24] migration: Normalize tls arguments
2025-07-04 13:12 ` Fabiano Rosas
@ 2025-07-04 15:37 ` Peter Xu
2025-08-20 15:45 ` Fabiano Rosas
0 siblings, 1 reply; 73+ messages in thread
From: Peter Xu @ 2025-07-04 15:37 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: Markus Armbruster, qemu-devel, berrange, Eric Blake
On Fri, Jul 04, 2025 at 10:12:33AM -0300, Fabiano Rosas wrote:
[...]
> >>> +static void tls_opt_to_str(StrOrNull **tls_opt)
> >>> +{
> >>> + StrOrNull *opt = *tls_opt;
> >>> +
> >>> + if (!opt) {
> >>> + return;
> >>
> >> ... it can also be null.
> >>
> >
> > Hmm, I'll have to double check, but with the StrOrNull property being
> > initialized, NULL should not be possible. This looks like a mistake.
> >
>
> The code is correct, this is coming from the QAPI, so it could be NULL
> in case the user hasn't provided the option. I'll use your suggested
> wording and the code suggestion as well.
One more trivial question:
>
> >> Maybe
> >>
> >> /* Normalize QTYPE_QNULL to QTYPE_QSTRING "" */
> >>
> >>> + }
> >>> +
> >>> + switch (opt->type) {
> >>> + case QTYPE_QSTRING:
> >>> + return;
> >>> + case QTYPE_QNULL:
> >>> + qobject_unref(opt->u.n);
> >>> + break;
> >>> + default:
> >>> + g_assert_not_reached();
> >>> + }
> >>> +
> >>> + opt->type = QTYPE_QSTRING;
> >>> + opt->u.s = g_strdup("");
> >>> + *tls_opt = opt;
Does tls_opt ever change? I wonder if this line is not needed, instead
tls_opt_to_str() can take an "StrOrNull *opt" directly.
> >>> +}
> >>
> >> I'd prefer something like
> >>
> >> if (!opt || opt->type == QTYPE_QSTRING) {
> >> return;
> >> }
> >> qobject_unref(opt->u.n);
> >> opt->type = QTYPE_QSTRING;
> >> opt->u.s = g_strdup("");
> >> *tls_opt = opt;
> >>
> >> But this is clearly a matter of taste.
>
> This is better indeed. I was moving back-and-forth between
> implementations and the code ended up a bit weird. Thanks!
>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 04/24] migration: Remove MigrateSetParameters
2025-06-30 19:58 ` [PATCH v2 04/24] migration: Remove MigrateSetParameters Fabiano Rosas
2025-07-01 8:00 ` Markus Armbruster
@ 2025-07-04 15:39 ` Peter Xu
1 sibling, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-07-04 15:39 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Eric Blake
On Mon, Jun 30, 2025 at 04:58:53PM -0300, Fabiano Rosas wrote:
> Now that the TLS options have been made the same between
> migrate-set-parameters and query-migrate-parameters, a single type can
> be used. Remove MigrateSetParameters.
>
> The TLS options documentation from MigrationParameters were replaced
> with the ones from MigrateSetParameters which was more complete.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Acked-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 05/24] qapi/migration: Don't document MigrationParameter
2025-06-30 19:58 ` [PATCH v2 05/24] qapi/migration: Don't document MigrationParameter Fabiano Rosas
2025-07-01 8:04 ` Markus Armbruster
@ 2025-07-04 15:40 ` Peter Xu
1 sibling, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-07-04 15:40 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Eric Blake
On Mon, Jun 30, 2025 at 04:58:54PM -0300, Fabiano Rosas wrote:
> The MigrationParameter (singular) enumeration is not part of the
> migration QMP API, it's only used for nicely converting HMP strings
> into MigrationParameters (plural) members and for providing readline
> completion.
>
> Documenting this enum only serves to duplicate documentation between
> MigrationParameter and MigrationParameters.
>
> Add an exception to QAPIs pragma.json and stop documenting it.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Acked-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 07/24] migration: Add a flag to track block-bitmap-mapping input
2025-06-30 19:58 ` [PATCH v2 07/24] migration: Add a flag to track block-bitmap-mapping input Fabiano Rosas
@ 2025-07-04 15:42 ` Peter Xu
0 siblings, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-07-04 15:42 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Kevin Wolf
On Mon, Jun 30, 2025 at 04:58:56PM -0300, Fabiano Rosas wrote:
> The QAPI converts an empty list on the block-bitmap-mapping input into
> a NULL BitmapMigrationNodeAliasList. The empty list is a valid input
> for the block-bitmap-mapping option, so commit 3cba22c9ad ("migration:
> Fix block_bitmap_mapping migration") started using the
> s->parameters.has_block_bitmap_mapping field to tell when the user has
> passed in an empty list vs. when no list has been passed at all.
>
> Using s->parameters.has_block_bitmap_mapping field is only possible
> because MigrationParameters has had its members made optional due to
> historical reasons.
>
> In order to make improvements to the way configuration options are set
> for a migration, we'd like to reduce the open-coded usage of the has_*
> fields of the global configuration object (s->parameters).
>
> Add a separate boolean to track the status of the block_bitmap_mapping
> option.
>
> No functional change intended.
>
> (this was verified to not regress iotest 300, which is the test that
> 3cba22c9ad refers to)
>
> CC: Kevin Wolf <kwolf@redhat.com>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Acked-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 09/24] migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE
2025-06-30 19:58 ` [PATCH v2 09/24] migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE Fabiano Rosas
@ 2025-07-04 16:04 ` Peter Xu
0 siblings, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-07-04 16:04 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru
On Mon, Jun 30, 2025 at 04:58:58PM -0300, Fabiano Rosas wrote:
> The QERR_INVALID_PARAMETER_VALUE macro is documented as not to be used
> in new code. Remove the usage from migration/options.c.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 11/24] migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters
2025-06-30 19:59 ` [PATCH v2 11/24] migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters Fabiano Rosas
@ 2025-07-04 16:11 ` Peter Xu
0 siblings, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-07-04 16:11 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru
On Mon, Jun 30, 2025 at 04:59:00PM -0300, Fabiano Rosas wrote:
> QAPI_CLONE_MEMBERS is a better option than copying parameters one by
> one because it operates on the entire struct and follows pointers. It
> also avoids the need to alter this function every time a new parameter
> is added.
>
> For this to work, the has_* fields of s->parameters need to be already
> set beforehand, so move migrate_mark_all_params_present() to the init
> routine.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 16/24] migration: Add capabilities into MigrationParameters
2025-06-30 19:59 ` [PATCH v2 16/24] migration: Add capabilities into MigrationParameters Fabiano Rosas
2025-07-01 8:25 ` Markus Armbruster
@ 2025-07-04 16:33 ` Peter Xu
1 sibling, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-07-04 16:33 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Eric Blake
On Mon, Jun 30, 2025 at 04:59:05PM -0300, Fabiano Rosas wrote:
> Add capabilities to MigrationParameters. This structure will hold all
> migration options. Capabilities will go away in the next patch.
>
> Also add capabilities to MigrationParameter as the enum needs to be
> kept in sync with MigrationParameters. This affects the parsing of
> migration HMP commands so make the necessary additions there too.
>
> From this point on, both QMP and HMP versions of
> migrate-set-parameters and query-migrate-parameters gain the ability
> to work with capabilities.
>
> With MigrationParameters now having members for each capability, the
> migration capabilities commands (query-migrate-capabilities,
> migrate-set-capabilities) will soon be deprecated. Add a set of
> helpers to convert between the old MigrationCapability representation
> and the new representation as members of MigrationParameters.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Acked-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 13/24] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply
2025-06-30 19:59 ` [PATCH v2 13/24] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply Fabiano Rosas
@ 2025-08-13 19:05 ` Peter Xu
2025-08-14 15:04 ` Fabiano Rosas
0 siblings, 1 reply; 73+ messages in thread
From: Peter Xu @ 2025-08-13 19:05 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru
On Mon, Jun 30, 2025 at 04:59:02PM -0300, Fabiano Rosas wrote:
> Instead of setting parameters one by one, use the temporary object,
> which already contains the current migration parameters plus the new
> ones and was just validated by migration_params_check(). Use cloning
> to overwrite it.
>
> This avoids the need to alter this function every time a new parameter
> is added.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> migration/options.c | 123 +++-----------------------------------------
> 1 file changed, 7 insertions(+), 116 deletions(-)
>
> diff --git a/migration/options.c b/migration/options.c
> index 4564db77f2..6619b5f21a 100644
> --- a/migration/options.c
> +++ b/migration/options.c
> @@ -13,6 +13,7 @@
>
> #include "qemu/osdep.h"
> #include "qemu/error-report.h"
> +#include "qemu/main-loop.h"
> #include "exec/target_page.h"
> #include "qapi/clone-visitor.h"
> #include "qapi/error.h"
> @@ -1341,123 +1342,13 @@ static void migrate_params_test_apply(MigrationParameters *params,
> static void migrate_params_apply(MigrationParameters *params)
> {
> MigrationState *s = migrate_get_current();
> + MigrationParameters *cur = &s->parameters;
>
> - /* TODO use QAPI_CLONE() instead of duplicating it inline */
> + assert(bql_locked());
>
> - if (params->has_throttle_trigger_threshold) {
> - s->parameters.throttle_trigger_threshold = params->throttle_trigger_threshold;
> - }
> -
> - if (params->has_cpu_throttle_initial) {
> - s->parameters.cpu_throttle_initial = params->cpu_throttle_initial;
> - }
> -
> - if (params->has_cpu_throttle_increment) {
> - s->parameters.cpu_throttle_increment = params->cpu_throttle_increment;
> - }
> -
> - if (params->has_cpu_throttle_tailslow) {
> - s->parameters.cpu_throttle_tailslow = params->cpu_throttle_tailslow;
> - }
> -
> - if (params->tls_creds) {
> - qapi_free_StrOrNull(s->parameters.tls_creds);
> - s->parameters.tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
> - }
> -
> - if (params->tls_hostname) {
> - qapi_free_StrOrNull(s->parameters.tls_hostname);
> - s->parameters.tls_hostname = QAPI_CLONE(StrOrNull,
> - params->tls_hostname);
> - }
> -
> - if (params->tls_authz) {
> - qapi_free_StrOrNull(s->parameters.tls_authz);
> - s->parameters.tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
> - }
> -
> - if (params->has_max_bandwidth) {
> - s->parameters.max_bandwidth = params->max_bandwidth;
> - }
> -
> - if (params->has_avail_switchover_bandwidth) {
> - s->parameters.avail_switchover_bandwidth = params->avail_switchover_bandwidth;
> - }
> -
> - if (params->has_downtime_limit) {
> - s->parameters.downtime_limit = params->downtime_limit;
> - }
> -
> - if (params->has_x_checkpoint_delay) {
> - s->parameters.x_checkpoint_delay = params->x_checkpoint_delay;
> - }
> -
> - if (params->has_multifd_channels) {
> - s->parameters.multifd_channels = params->multifd_channels;
> - }
> - if (params->has_multifd_compression) {
> - s->parameters.multifd_compression = params->multifd_compression;
> - }
> - if (params->has_multifd_qatzip_level) {
> - s->parameters.multifd_qatzip_level = params->multifd_qatzip_level;
> - }
> - if (params->has_multifd_zlib_level) {
> - s->parameters.multifd_zlib_level = params->multifd_zlib_level;
> - }
> - if (params->has_multifd_zstd_level) {
> - s->parameters.multifd_zstd_level = params->multifd_zstd_level;
> - }
> - if (params->has_xbzrle_cache_size) {
> - s->parameters.xbzrle_cache_size = params->xbzrle_cache_size;
> - }
> - if (params->has_max_postcopy_bandwidth) {
> - s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
> - }
> - if (params->has_max_cpu_throttle) {
> - s->parameters.max_cpu_throttle = params->max_cpu_throttle;
> - }
> - if (params->has_announce_initial) {
> - s->parameters.announce_initial = params->announce_initial;
> - }
> - if (params->has_announce_max) {
> - s->parameters.announce_max = params->announce_max;
> - }
> - if (params->has_announce_rounds) {
> - s->parameters.announce_rounds = params->announce_rounds;
> - }
> - if (params->has_announce_step) {
> - s->parameters.announce_step = params->announce_step;
> - }
> -
> - if (params->has_block_bitmap_mapping) {
> - qapi_free_BitmapMigrationNodeAliasList(
> - s->parameters.block_bitmap_mapping);
> -
> - s->has_block_bitmap_mapping = true;
> - s->parameters.block_bitmap_mapping =
> - QAPI_CLONE(BitmapMigrationNodeAliasList,
> - params->block_bitmap_mapping);
> - }
> -
> - if (params->has_x_vcpu_dirty_limit_period) {
> - s->parameters.x_vcpu_dirty_limit_period =
> - params->x_vcpu_dirty_limit_period;
> - }
> - if (params->has_vcpu_dirty_limit) {
> - s->parameters.vcpu_dirty_limit = params->vcpu_dirty_limit;
> - }
> -
> - if (params->has_mode) {
> - s->parameters.mode = params->mode;
> - }
> -
> - if (params->has_zero_page_detection) {
> - s->parameters.zero_page_detection = params->zero_page_detection;
> - }
> -
> - if (params->has_direct_io) {
> - s->parameters.direct_io = params->direct_io;
> - }
> + migrate_tls_opts_free(cur);
> + qapi_free_BitmapMigrationNodeAliasList(cur->block_bitmap_mapping);
So we free these without resetting the pointers. Now, for example,
cur->tls_creds can point to garbage. Then..
> + QAPI_CLONE_MEMBERS(MigrationParameters, cur, params);
How does this patch guarantee cur->tls_creds's garbage pointer being
updated? What if params->tls_creds is NULL? Could it?
> }
>
> void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
> @@ -1487,7 +1378,7 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
> }
>
> if (migrate_params_check(&tmp, errp)) {
> - migrate_params_apply(params);
> + migrate_params_apply(&tmp);
> migrate_post_update_params(params, errp);
> }
>
> --
> 2.35.3
>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 14/24] migration: Use visitors in migrate_params_test_apply
2025-06-30 19:59 ` [PATCH v2 14/24] migration: Use visitors in migrate_params_test_apply Fabiano Rosas
@ 2025-08-13 20:05 ` Peter Xu
2025-08-14 15:10 ` Fabiano Rosas
0 siblings, 1 reply; 73+ messages in thread
From: Peter Xu @ 2025-08-13 20:05 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru
On Mon, Jun 30, 2025 at 04:59:03PM -0300, Fabiano Rosas wrote:
> Convert the code in migrate_params_test_apply() from an open-coded
> copy of every migration parameter to a copy using visitors. The
> current code has conditionals for each parameter's has_* field, which
> is exactly what the visitors do.
>
> This hides the details of QAPI from the migration code and avoids the
> need to update migrate_params_test_apply() every time a new migration
> parameter is added. Both were very confusing and while the visitor
> code can become a bit involved, there is no need for new contributors
> to ever touch it.
>
> Change the name of the function to a more direct reference of what it
> does: merging the user params with the temporary copy.
>
> Move the QAPI_CLONE_MEMBERS into the caller, so QAPI_CLONE can be used
> and there's no need to allocate memory in the migration
> code. Similarly, turn 'tmp' into a pointer so the proper qapi_free_
> routine can be used.
>
> An extra call to migrate_mark_all_params_present() is now needed
> because the visitors update the has_ field for non-present fields, but
> we actually want them all set so migrate_params_apply() can copy all
> of them.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> migration/options.c | 157 +++++++++++++++-----------------------------
> 1 file changed, 54 insertions(+), 103 deletions(-)
>
> diff --git a/migration/options.c b/migration/options.c
> index 6619b5f21a..695bec5b8f 100644
> --- a/migration/options.c
> +++ b/migration/options.c
> @@ -20,6 +20,10 @@
> #include "qapi/qapi-commands-migration.h"
> #include "qapi/qapi-visit-migration.h"
> #include "qapi/qmp/qerror.h"
> +#include "qapi/qobject-input-visitor.h"
> +#include "qapi/qobject-output-visitor.h"
> +#include "qapi/visitor.h"
> +#include "qobject/qdict.h"
> #include "qobject/qnull.h"
> #include "system/runstate.h"
> #include "migration/colo.h"
> @@ -1223,120 +1227,63 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
> return true;
> }
>
> -static void migrate_params_test_apply(MigrationParameters *params,
> - MigrationParameters *dest)
> +static bool migrate_params_merge(MigrationParameters *dst,
> + MigrationParameters *src, Error **errp)
> {
> - MigrationState *s = migrate_get_current();
> + QObject *ret_out = NULL;
> + Visitor *v;
> + bool ok;
>
> - QAPI_CLONE_MEMBERS(MigrationParameters, dest, &s->parameters);
> -
> - if (params->has_throttle_trigger_threshold) {
> - dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
> - }
> -
> - if (params->has_cpu_throttle_initial) {
> - dest->cpu_throttle_initial = params->cpu_throttle_initial;
> - }
> -
> - if (params->has_cpu_throttle_increment) {
> - dest->cpu_throttle_increment = params->cpu_throttle_increment;
> + /* free memory from pointers that are about to be assigned */
> + if (src->has_block_bitmap_mapping) {
> + qapi_free_BitmapMigrationNodeAliasList(dst->block_bitmap_mapping);
There're quite a few similar cases like this one in this series (including
the rest below parameters below), where we free stuff but keep the dangling
pointer around for a while (..hopefully!)..
Should we still try to reset the pointers? Am I the only one that is
nervous with it?
> }
>
> - if (params->has_cpu_throttle_tailslow) {
> - dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow;
> + if (src->tls_creds) {
> + qapi_free_StrOrNull(dst->tls_creds);
> }
>
> - if (params->tls_creds) {
> - qapi_free_StrOrNull(dest->tls_creds);
> - dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
> + if (src->tls_hostname) {
> + qapi_free_StrOrNull(dst->tls_hostname);
> }
>
> - if (params->tls_hostname) {
> - qapi_free_StrOrNull(dest->tls_hostname);
> - dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
> + if (src->tls_authz) {
> + qapi_free_StrOrNull(dst->tls_authz);
> }
>
> - if (params->tls_authz) {
> - qapi_free_StrOrNull(dest->tls_authz);
> - dest->tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
> + /* read in from src */
> + v = qobject_output_visitor_new(&ret_out);
> + ok = visit_type_MigrationParameters(v, NULL, &src, errp);
> + if (!ok) {
> + goto out;
> }
> + visit_complete(v, &ret_out);
> + visit_free(v);
>
> - if (params->has_max_bandwidth) {
> - dest->max_bandwidth = params->max_bandwidth;
> + /*
> + * Write to dst but leave existing fields intact (except for has_*
> + * which will be updated according to their presence in src).
> + */
> + v = qobject_input_visitor_new(ret_out);
> + ok = visit_start_struct(v, NULL, NULL, 0, errp);
> + if (!ok) {
> + goto out;
> }
> -
> - if (params->has_avail_switchover_bandwidth) {
> - dest->avail_switchover_bandwidth = params->avail_switchover_bandwidth;
> + ok = visit_type_MigrationParameters_members(v, dst, errp);
> + if (!ok) {
> + goto out;
> }
> -
> - if (params->has_downtime_limit) {
> - dest->downtime_limit = params->downtime_limit;
> + ok = visit_check_struct(v, errp);
> + visit_end_struct(v, NULL);
> + if (!ok) {
> + goto out;
> }
>
> - if (params->has_x_checkpoint_delay) {
> - dest->x_checkpoint_delay = params->x_checkpoint_delay;
> - }
> +out:
> + visit_free(v);
> + qobject_unref(ret_out);
IIUC this is essential the trick we used to play before QAPI_CLONE, before
commit a15fcc3cf69e.
https://lore.kernel.org/all/1465490926-28625-15-git-send-email-eblake@redhat.com/
Yes, looks similar..
QAPI_CLONE_MEMBERS() will copy everything, which we do not want here. We
only want to copy where has_* is set. So it's indeed a sligntly different
request versus the current clone API.
IIUC that can be implemented using a similar qapi clone visitor, however
instead of g_memdup() on the structs/lists first (or in the case of
QAPI_CLONE_MEMBERS, we did *dst=*src), we lazy copy all the fields.
I wished this is a generic API we could use. I think it means we'll
maintain this ourselves. Maybe it's OK.
>
> - if (params->has_multifd_channels) {
> - dest->multifd_channels = params->multifd_channels;
> - }
> - if (params->has_multifd_compression) {
> - dest->multifd_compression = params->multifd_compression;
> - }
> - if (params->has_multifd_qatzip_level) {
> - dest->multifd_qatzip_level = params->multifd_qatzip_level;
> - }
> - if (params->has_multifd_zlib_level) {
> - dest->multifd_zlib_level = params->multifd_zlib_level;
> - }
> - if (params->has_multifd_zstd_level) {
> - dest->multifd_zstd_level = params->multifd_zstd_level;
> - }
> - if (params->has_xbzrle_cache_size) {
> - dest->xbzrle_cache_size = params->xbzrle_cache_size;
> - }
> - if (params->has_max_postcopy_bandwidth) {
> - dest->max_postcopy_bandwidth = params->max_postcopy_bandwidth;
> - }
> - if (params->has_max_cpu_throttle) {
> - dest->max_cpu_throttle = params->max_cpu_throttle;
> - }
> - if (params->has_announce_initial) {
> - dest->announce_initial = params->announce_initial;
> - }
> - if (params->has_announce_max) {
> - dest->announce_max = params->announce_max;
> - }
> - if (params->has_announce_rounds) {
> - dest->announce_rounds = params->announce_rounds;
> - }
> - if (params->has_announce_step) {
> - dest->announce_step = params->announce_step;
> - }
> -
> - if (params->has_block_bitmap_mapping) {
> - dest->block_bitmap_mapping = params->block_bitmap_mapping;
> - }
> -
> - if (params->has_x_vcpu_dirty_limit_period) {
> - dest->x_vcpu_dirty_limit_period =
> - params->x_vcpu_dirty_limit_period;
> - }
> - if (params->has_vcpu_dirty_limit) {
> - dest->vcpu_dirty_limit = params->vcpu_dirty_limit;
> - }
> -
> - if (params->has_mode) {
> - dest->mode = params->mode;
> - }
> -
> - if (params->has_zero_page_detection) {
> - dest->zero_page_detection = params->zero_page_detection;
> - }
> -
> - if (params->has_direct_io) {
> - dest->direct_io = params->direct_io;
> - }
> + return ok;
> }
>
> static void migrate_params_apply(MigrationParameters *params)
> @@ -1353,7 +1300,9 @@ static void migrate_params_apply(MigrationParameters *params)
>
> void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
> {
> - MigrationParameters tmp;
> + MigrationState *s = migrate_get_current();
> + g_autoptr(MigrationParameters) tmp = QAPI_CLONE(MigrationParameters,
> + &s->parameters);
>
> /*
> * Convert QTYPE_QNULL and NULL to the empty string (""). Even
> @@ -1367,7 +1316,9 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
> tls_opt_to_str(¶ms->tls_hostname);
> tls_opt_to_str(¶ms->tls_authz);
>
> - migrate_params_test_apply(params, &tmp);
> + if (!migrate_params_merge(tmp, params, errp)) {
> + return;
> + }
>
> /*
> * Mark block_bitmap_mapping as present now while we have the
> @@ -1377,10 +1328,10 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
> migrate_get_current()->has_block_bitmap_mapping = true;
> }
>
> - if (migrate_params_check(&tmp, errp)) {
> - migrate_params_apply(&tmp);
> + if (migrate_params_check(tmp, errp)) {
> + /* mark all present, so they're all copied */
> + migrate_mark_all_params_present(tmp);
Ah, I just asked a question in the previous patch on what happens if some
of the fields will be present. Looks like this line is the answer?
This isn't very obvious. Maybe some comment in migrate_params_apply()
would slightly help (which mentions it must be used when all parameters are
set)? Or some way to assert it?
> + migrate_params_apply(tmp);
> migrate_post_update_params(params, errp);
> }
> -
> - migrate_tls_opts_free(&tmp);
> }
> --
> 2.35.3
>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 15/24] migration: Cleanup hmp_info_migrate_parameters
2025-06-30 19:59 ` [PATCH v2 15/24] migration: Cleanup hmp_info_migrate_parameters Fabiano Rosas
@ 2025-08-13 20:40 ` Peter Xu
0 siblings, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-08-13 20:40 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru
On Mon, Jun 30, 2025 at 04:59:04PM -0300, Fabiano Rosas wrote:
> Do a cleanup of hmp_info_migrate_parameters() before adding more lines
> into it:
>
> - Make sure every parameter asserts that the has_* field is
> set. qmp_query_migrate_parameters should have set them all. (except
> for block-bitmap-mapping)
>
> - Remove the if (params), qmp_query_migrate_parameters never returns
> NULL.
>
> - Add a macro to encapsulate boilerplate.
>
> - Line breaks for legibility.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 17/24] migration: Remove s->capabilities
2025-06-30 19:59 ` [PATCH v2 17/24] migration: Remove s->capabilities Fabiano Rosas
@ 2025-08-13 20:48 ` Peter Xu
0 siblings, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-08-13 20:48 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru
On Mon, Jun 30, 2025 at 04:59:06PM -0300, Fabiano Rosas wrote:
> Last patch added capabilities to s->parameters. Now we can replace all
> instances of s->capabilities with s->parameters:
>
> - The -global properties now get set directly in s->parameters.
>
> - Accessors from options.c now read from s->parameters.
>
> - migrate_caps_check() now takes a MigrationParameters object. The
> function is still kept around because migrate-set-capabilities will
> still use it.
>
> - The machinery for background-snapshot compatibility check goes
> away. We can check each capability by name (if s->parameters.cap ...)
>
> - savevm uses the helper functions introduced in the last patch to do
> validation of capabilities found on the migration stream.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands
2025-06-30 19:59 ` [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands Fabiano Rosas
2025-07-01 8:30 ` Markus Armbruster
2025-07-01 8:38 ` Jiri Denemark
@ 2025-08-13 20:50 ` Peter Xu
2 siblings, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-08-13 20:50 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, devel, Eric Blake
On Mon, Jun 30, 2025 at 04:59:07PM -0300, Fabiano Rosas wrote:
> The concept of capabilities is being merged into the concept of
> parameters. From now on, the commands that handle capabilities are
> deprecated in favor of the commands that handle parameters.
>
> Affected commands:
>
> - migrate-set-capabilities
> - query-migrate-capabilities
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> docs/about/deprecated.rst | 12 ++++++++++++
> migration/migration-hmp-cmds.c | 6 ++++++
> qapi/migration.json | 16 ++++++++++++++--
> 3 files changed, 32 insertions(+), 2 deletions(-)
>
> diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
> index 42037131de..15474833ea 100644
> --- a/docs/about/deprecated.rst
> +++ b/docs/about/deprecated.rst
> @@ -605,3 +605,15 @@ command documentation for details on the ``fdset`` usage.
>
> The ``zero-blocks`` capability was part of the block migration which
> doesn't exist anymore since it was removed in QEMU v9.1.
> +
> +``migrate-set-capabilities`` command (since 10.1)
> +'''''''''''''''''''''''''''''''''''''''''''''''''
> +
> +This command was deprecated. Use ``migrate-set-parameters`` instead
> +which now supports setting capabilities.
> +
> +``query-migrate-capabilities`` command (since 10.1)
> +'''''''''''''''''''''''''''''''''''''''''''''''''''
Don't forget to update the versions.
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 19/24] migration: Store the initial values used for s->parameters
2025-06-30 19:59 ` [PATCH v2 19/24] migration: Store the initial values used for s->parameters Fabiano Rosas
@ 2025-08-13 21:09 ` Peter Xu
0 siblings, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-08-13 21:09 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru
On Mon, Jun 30, 2025 at 04:59:08PM -0300, Fabiano Rosas wrote:
> Each migration parameters has a default value, store them for later
> use in resetting s->parameters. Values overridden via the command line
> with the debugging option -global migration.<param> will be included.
>
> Make the structure const and change the appropriate signatures to make
> sure its values are not changed by accident. Some functions take two
> MigrationParameters pointers and it's easy to confuse them.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 20/24] migration: Allow migrate commands to provide the migration config
2025-06-30 19:59 ` [PATCH v2 20/24] migration: Allow migrate commands to provide the migration config Fabiano Rosas
2025-07-01 8:35 ` Markus Armbruster
@ 2025-08-13 21:27 ` Peter Xu
2025-08-14 15:13 ` Fabiano Rosas
1 sibling, 1 reply; 73+ messages in thread
From: Peter Xu @ 2025-08-13 21:27 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Eric Blake, Paolo Bonzini
On Mon, Jun 30, 2025 at 04:59:09PM -0300, Fabiano Rosas wrote:
> Allow the migrate and migrate_incoming commands to pass the migration
> configuration options all at once, dispensing the use of
> migrate-set-parameters and migrate-set-capabilities.
>
> The motivation of this is to simplify the interface with the
> management layer and avoid the usage of several command invocations to
> configure a migration. It also avoids stale parameters from a previous
> migration to influence the current migration.
>
> The options that are changed during the migration can still be set
> with the existing commands.
>
> The order of precedence is:
>
> 'config' argument > -global migration cmdline > migrate-set-parameters
> > defaults (migration_properties)
Did you make the 2nd/3rd the wrong way?
config > migrate-set-parameters > -global cmdlines > defaults
>
> I.e. the config takes precedence over all, values not present in the
> config assume the default values. The -global migration command line
> option allows the defaults to be overridden for debug.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Other than that:
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 21/24] tests/qtest/migration: Take reference when passing %p to qtest_qmp
2025-06-30 19:59 ` [PATCH v2 21/24] tests/qtest/migration: Take reference when passing %p to qtest_qmp Fabiano Rosas
@ 2025-08-13 22:22 ` Peter Xu
2025-08-21 17:20 ` Fabiano Rosas
0 siblings, 1 reply; 73+ messages in thread
From: Peter Xu @ 2025-08-13 22:22 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini
On Mon, Jun 30, 2025 at 04:59:10PM -0300, Fabiano Rosas wrote:
> The documentation of qobject_from_jsonv() states that it takes
> ownership of any %p arguments passed in.
>
> Next patches will add config-passing to the tests, so take an extra
> reference in the migrate_qmp* functions to ensure the config is not
> freed from under us.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> tests/qtest/migration/migration-qmp.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
> index fb59741b2c..d82ac8c750 100644
> --- a/tests/qtest/migration/migration-qmp.c
> +++ b/tests/qtest/migration/migration-qmp.c
> @@ -97,7 +97,8 @@ void migrate_qmp_fail(QTestState *who, const char *uri,
> }
>
> err = qtest_qmp_assert_failure_ref(
> - who, "{ 'execute': 'migrate', 'arguments': %p}", args);
> + who, "{ 'execute': 'migrate', 'arguments': %p}",
> + qdict_clone_shallow(args));
>
> g_assert(qdict_haskey(err, "desc"));
>
> @@ -136,7 +137,8 @@ void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
> }
>
> qtest_qmp_assert_success(who,
> - "{ 'execute': 'migrate', 'arguments': %p}", args);
> + "{ 'execute': 'migrate', 'arguments': %p}",
> + qdict_clone_shallow(args));
> }
>
> void migrate_set_capability(QTestState *who, const char *capability,
> @@ -174,7 +176,7 @@ void migrate_incoming_qmp(QTestState *to, const char *uri, QObject *channels,
> migrate_set_capability(to, "events", true);
>
> rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
> - args);
> + qdict_clone_shallow(args));
Isn't it intentional to pass over the ownership in the three places here?
I don't see otherwise where args got freed.
OTOH, I saw there're yet another three similar usages of %p in framework.c:
x1:migration [migration-params-caps-no-config]$ git grep -A1 %p framework.c
framework.c: migrate_qmp_fail(from, args->connect_uri, NULL, "{ 'config': %p }",
framework.c- args->start.config);
--
framework.c: migrate_qmp(from, to, args->connect_uri, NULL, "{ 'config': %p }",
framework.c- args->start.config);
--
framework.c: migrate_incoming_qmp(to, args->connect_uri, NULL, "{ 'config': %p }",
framework.c- args->start.config);
They seem to be suspecious instead, as they seem to have lost ownership of
args->start.config, so args->start.config can start to point to garbage?
>
> if (!qdict_haskey(rsp, "return")) {
> g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true);
> --
> 2.35.3
>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 22/24] tests/qtest/migration: Adapt the capabilities helper to take a config
2025-06-30 19:59 ` [PATCH v2 22/24] tests/qtest/migration: Adapt the capabilities helper to take a config Fabiano Rosas
@ 2025-08-14 14:02 ` Peter Xu
0 siblings, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-08-14 14:02 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini
On Mon, Jun 30, 2025 at 04:59:11PM -0300, Fabiano Rosas wrote:
> Allow migrate_start_set_capabilities() to set the config object
> instead of setting the capabilities via calls to
> migrate-set-capabilities.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> tests/qtest/migration/framework.c | 31 +++++++++++++++++++++++++++++++
> tests/qtest/migration/framework.h | 1 +
> 2 files changed, 32 insertions(+)
>
> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> index 407c9023c0..9ff5576328 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -211,6 +211,37 @@ static QList *migrate_start_get_qmp_capabilities(const MigrateStart *args)
> static void migrate_start_set_capabilities(QTestState *from, QTestState *to,
> MigrateStart *args)
> {
> + if (args->config) {
> + const char *cap_multifd;
> + bool multifd;
> +
> + for (uint8_t i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
> + const char *cap = MigrationCapability_lookup.array[i];
> +
> + if (!args->caps[i]) {
> + continue;
> + }
> +
> + qdict_put_bool(args->config, cap, true);
> + }
> +
> + if (!args->defer_target_connect) {
> + qdict_put_bool(args->config, "events", true);
> + }
This will disable events on src too when defer_target_connect is set.
Maybe it's ok to just not test "events" on src for those (almost cpr ones),
but maybe worth mentioning if so.
> +
> + cap_multifd = MigrationCapability_str(MIGRATION_CAPABILITY_MULTIFD);
> + multifd = qdict_get_try_bool(args->config, cap_multifd, false);
I get you, but when args->cap[] is still around it's a bit weird to not
just use args->cap[MIGRATION_CAPABILITY_MULTIFD].
I also saw the next patch that we'll also support both "if (config)
... else ...". If we decide to switchover at some point, shall we have one
patch converting all existing usages (including removing args->cap[]) to
use ->config?
The only outliers should be the parameters we set only after QMP migrate /
migrate_incoming.
> +
> + if (multifd) {
> + qdict_put_int(args->config, "multifd-channels",
> + MULTIFD_TEST_CHANNELS);
> + qdict_put_int(args->config, "multifd-channels",
> + MULTIFD_TEST_CHANNELS);
> + }
> +
> + return;
> + }
> +
> /*
> * MigrationCapability_lookup and MIGRATION_CAPABILITY_ constants
> * are from qapi-types-migration.h.
> diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
> index 01e425e64e..9b281d6757 100644
> --- a/tests/qtest/migration/framework.h
> +++ b/tests/qtest/migration/framework.h
> @@ -128,6 +128,7 @@ typedef struct {
> * migration_set_capabilities().
> */
> bool caps[MIGRATION_CAPABILITY__MAX];
> + QDict *config;
> } MigrateStart;
>
> typedef enum PostcopyRecoveryFailStage {
> --
> 2.35.3
>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 24/24] tests/qtest/migration: Pass the migration config to file tests
2025-06-30 19:59 ` [PATCH v2 24/24] tests/qtest/migration: Pass the migration config to file tests Fabiano Rosas
@ 2025-08-14 14:24 ` Peter Xu
2025-08-14 15:30 ` Fabiano Rosas
0 siblings, 1 reply; 73+ messages in thread
From: Peter Xu @ 2025-08-14 14:24 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini
On Mon, Jun 30, 2025 at 04:59:13PM -0300, Fabiano Rosas wrote:
> Use the existing file tests to test the new way of passing parameters
> to the migration via the config argument to qmp_migrate*.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> tests/qtest/migration/file-tests.c | 68 +++++++++++----------------
> tests/qtest/migration/framework.c | 9 ++--
> tests/qtest/migration/precopy-tests.c | 1 +
> 3 files changed, 34 insertions(+), 44 deletions(-)
>
> diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c
> index 4d78ce0855..656d6527e8 100644
> --- a/tests/qtest/migration/file-tests.c
> +++ b/tests/qtest/migration/file-tests.c
> @@ -27,6 +27,7 @@ static void test_precopy_file(void)
> MigrateCommon args = {
> .connect_uri = uri,
> .listen_uri = "defer",
> + .start.config = qdict_new(),
> };
>
> test_file_common(&args, true);
> @@ -74,6 +75,7 @@ static void test_precopy_file_offset_fdset(void)
> .connect_uri = uri,
> .listen_uri = "defer",
> .start_hook = migrate_hook_start_file_offset_fdset,
> + .start.config = qdict_new(),
> };
>
> test_file_common(&args, false);
> @@ -88,6 +90,7 @@ static void test_precopy_file_offset(void)
> MigrateCommon args = {
> .connect_uri = uri,
> .listen_uri = "defer",
> + .start.config = qdict_new(),
> };
>
> test_file_common(&args, false);
> @@ -102,6 +105,7 @@ static void test_precopy_file_offset_bad(void)
> .connect_uri = uri,
> .listen_uri = "defer",
> .result = MIG_TEST_QMP_ERROR,
> + .start.config = qdict_new(),
> };
>
> test_file_common(&args, false);
> @@ -114,11 +118,10 @@ static void test_precopy_file_mapped_ram_live(void)
> MigrateCommon args = {
> .connect_uri = uri,
> .listen_uri = "defer",
> - .start = {
> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> - },
> + .start.config = qdict_new(),
> };
>
> + qdict_put_bool(args.start.config, "mapped-ram", true);
> test_file_common(&args, false);
> }
>
> @@ -129,11 +132,9 @@ static void test_precopy_file_mapped_ram(void)
> MigrateCommon args = {
> .connect_uri = uri,
> .listen_uri = "defer",
> - .start = {
> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> - },
> + .start.config = qdict_new(),
> };
> -
> + qdict_put_bool(args.start.config, "mapped-ram", true);
> test_file_common(&args, true);
> }
>
> @@ -144,12 +145,11 @@ static void test_multifd_file_mapped_ram_live(void)
> MigrateCommon args = {
> .connect_uri = uri,
> .listen_uri = "defer",
> - .start = {
> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> - },
> + .start.config = qdict_new(),
> };
>
> + qdict_put_bool(args.start.config, "mapped-ram", true);
> + qdict_put_bool(args.start.config, "multifd", true);
> test_file_common(&args, false);
> }
>
> @@ -160,24 +160,13 @@ static void test_multifd_file_mapped_ram(void)
> MigrateCommon args = {
> .connect_uri = uri,
> .listen_uri = "defer",
> - .start = {
> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> - },
> + .start.config = qdict_new(),
> };
> -
> + qdict_put_bool(args.start.config, "mapped-ram", true);
> + qdict_put_bool(args.start.config, "multifd", true);
> test_file_common(&args, true);
> }
>
> -static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from,
> - QTestState *to)
> -{
> - migrate_set_parameter_bool(from, "direct-io", true);
> - migrate_set_parameter_bool(to, "direct-io", true);
> -
> - return NULL;
> -}
> -
> static void test_multifd_file_mapped_ram_dio(void)
> {
> g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
> @@ -185,13 +174,13 @@ static void test_multifd_file_mapped_ram_dio(void)
> MigrateCommon args = {
> .connect_uri = uri,
> .listen_uri = "defer",
> - .start_hook = migrate_hook_start_multifd_mapped_ram_dio,
> - .start = {
> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
> - },
> + .start.config = qdict_new(),
> };
>
> + qdict_put_bool(args.start.config, "direct-io", true);
So the start_hook doesn't take args so we need to duplicate all these
direct-io setups in each test.. I assume not a big deal so it's fine, but
this is slightly going backward for sure..
What's your plan in mind on the tests? Looks like you want to keep both
ways in tests/, only use it in some tests to cover both paths (and you
chose file-tests to start testing config)? Or is this only an example and
you plan to convert more?
> + qdict_put_bool(args.start.config, "mapped-ram", true);
> + qdict_put_bool(args.start.config, "multifd", true);
> +
> if (!probe_o_direct_support(tmpfs)) {
> g_test_skip("Filesystem does not support O_DIRECT");
> return;
> @@ -235,9 +224,6 @@ static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from,
> fdset_add_fds(from, file, O_WRONLY, 2, true);
> fdset_add_fds(to, file, O_RDONLY, 2, true);
>
> - migrate_set_parameter_bool(from, "direct-io", true);
> - migrate_set_parameter_bool(to, "direct-io", true);
> -
> return NULL;
> }
>
> @@ -261,12 +247,11 @@ static void test_multifd_file_mapped_ram_fdset(void)
> .listen_uri = "defer",
> .start_hook = migrate_hook_start_multifd_mapped_ram_fdset,
> .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
> - .start = {
> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
> - },
> + .start.config = qdict_new(),
> };
>
> + qdict_put_bool(args.start.config, "mapped-ram", true);
> + qdict_put_bool(args.start.config, "multifd", true);
> test_file_common(&args, true);
> }
>
> @@ -279,12 +264,13 @@ static void test_multifd_file_mapped_ram_fdset_dio(void)
> .listen_uri = "defer",
> .start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio,
> .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
> - .start = {
> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
> - },
> + .start.config = qdict_new(),
> };
>
> + qdict_put_bool(args.start.config, "direct-io", true);
> + qdict_put_bool(args.start.config, "mapped-ram", true);
> + qdict_put_bool(args.start.config, "multifd", true);
> +
> if (!probe_o_direct_support(tmpfs)) {
> g_test_skip("Filesystem does not support O_DIRECT");
> return;
> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> index 5025299d6a..37c5c884af 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -974,18 +974,21 @@ void test_file_common(MigrateCommon *args, bool stop_src)
> }
>
> if (args->result == MIG_TEST_QMP_ERROR) {
> - migrate_qmp_fail(from, args->connect_uri, NULL, "{}");
> + migrate_qmp_fail(from, args->connect_uri, NULL, "{ 'config': %p }",
> + args->start.config);
> goto finish;
> }
>
> - migrate_qmp(from, to, args->connect_uri, NULL, "{}");
> + migrate_qmp(from, to, args->connect_uri, NULL, "{ 'config': %p }",
> + args->start.config);
> wait_for_migration_complete(from);
>
> /*
> * We need to wait for the source to finish before starting the
> * destination.
> */
> - migrate_incoming_qmp(to, args->connect_uri, NULL, "{}");
> + migrate_incoming_qmp(to, args->connect_uri, NULL, "{ 'config': %p }",
> + args->start.config);
> wait_for_migration_complete(to);
>
> if (stop_src) {
> diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
> index 35d4274c69..9606dc1d02 100644
> --- a/tests/qtest/migration/precopy-tests.c
> +++ b/tests/qtest/migration/precopy-tests.c
> @@ -338,6 +338,7 @@ static void test_precopy_fd_file(void)
> .connect_uri = "fd:fd-mig",
> .start_hook = migrate_hook_start_precopy_fd_file,
> .end_hook = migrate_hook_end_fd,
> + .start.config = qdict_new(),
> };
> test_file_common(&args, true);
> }
> --
> 2.35.3
>
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 13/24] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply
2025-08-13 19:05 ` Peter Xu
@ 2025-08-14 15:04 ` Fabiano Rosas
0 siblings, 0 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-08-14 15:04 UTC (permalink / raw)
To: Peter Xu; +Cc: qemu-devel, berrange, armbru
Peter Xu <peterx@redhat.com> writes:
> On Mon, Jun 30, 2025 at 04:59:02PM -0300, Fabiano Rosas wrote:
>> Instead of setting parameters one by one, use the temporary object,
>> which already contains the current migration parameters plus the new
>> ones and was just validated by migration_params_check(). Use cloning
>> to overwrite it.
>>
>> This avoids the need to alter this function every time a new parameter
>> is added.
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> ---
>> migration/options.c | 123 +++-----------------------------------------
>> 1 file changed, 7 insertions(+), 116 deletions(-)
>>
>> diff --git a/migration/options.c b/migration/options.c
>> index 4564db77f2..6619b5f21a 100644
>> --- a/migration/options.c
>> +++ b/migration/options.c
>> @@ -13,6 +13,7 @@
>>
>> #include "qemu/osdep.h"
>> #include "qemu/error-report.h"
>> +#include "qemu/main-loop.h"
>> #include "exec/target_page.h"
>> #include "qapi/clone-visitor.h"
>> #include "qapi/error.h"
>> @@ -1341,123 +1342,13 @@ static void migrate_params_test_apply(MigrationParameters *params,
>> static void migrate_params_apply(MigrationParameters *params)
>> {
>> MigrationState *s = migrate_get_current();
>> + MigrationParameters *cur = &s->parameters;
>>
>> - /* TODO use QAPI_CLONE() instead of duplicating it inline */
>> + assert(bql_locked());
>>
>> - if (params->has_throttle_trigger_threshold) {
>> - s->parameters.throttle_trigger_threshold = params->throttle_trigger_threshold;
>> - }
>> -
>> - if (params->has_cpu_throttle_initial) {
>> - s->parameters.cpu_throttle_initial = params->cpu_throttle_initial;
>> - }
>> -
>> - if (params->has_cpu_throttle_increment) {
>> - s->parameters.cpu_throttle_increment = params->cpu_throttle_increment;
>> - }
>> -
>> - if (params->has_cpu_throttle_tailslow) {
>> - s->parameters.cpu_throttle_tailslow = params->cpu_throttle_tailslow;
>> - }
>> -
>> - if (params->tls_creds) {
>> - qapi_free_StrOrNull(s->parameters.tls_creds);
>> - s->parameters.tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
>> - }
>> -
>> - if (params->tls_hostname) {
>> - qapi_free_StrOrNull(s->parameters.tls_hostname);
>> - s->parameters.tls_hostname = QAPI_CLONE(StrOrNull,
>> - params->tls_hostname);
>> - }
>> -
>> - if (params->tls_authz) {
>> - qapi_free_StrOrNull(s->parameters.tls_authz);
>> - s->parameters.tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
>> - }
>> -
>> - if (params->has_max_bandwidth) {
>> - s->parameters.max_bandwidth = params->max_bandwidth;
>> - }
>> -
>> - if (params->has_avail_switchover_bandwidth) {
>> - s->parameters.avail_switchover_bandwidth = params->avail_switchover_bandwidth;
>> - }
>> -
>> - if (params->has_downtime_limit) {
>> - s->parameters.downtime_limit = params->downtime_limit;
>> - }
>> -
>> - if (params->has_x_checkpoint_delay) {
>> - s->parameters.x_checkpoint_delay = params->x_checkpoint_delay;
>> - }
>> -
>> - if (params->has_multifd_channels) {
>> - s->parameters.multifd_channels = params->multifd_channels;
>> - }
>> - if (params->has_multifd_compression) {
>> - s->parameters.multifd_compression = params->multifd_compression;
>> - }
>> - if (params->has_multifd_qatzip_level) {
>> - s->parameters.multifd_qatzip_level = params->multifd_qatzip_level;
>> - }
>> - if (params->has_multifd_zlib_level) {
>> - s->parameters.multifd_zlib_level = params->multifd_zlib_level;
>> - }
>> - if (params->has_multifd_zstd_level) {
>> - s->parameters.multifd_zstd_level = params->multifd_zstd_level;
>> - }
>> - if (params->has_xbzrle_cache_size) {
>> - s->parameters.xbzrle_cache_size = params->xbzrle_cache_size;
>> - }
>> - if (params->has_max_postcopy_bandwidth) {
>> - s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
>> - }
>> - if (params->has_max_cpu_throttle) {
>> - s->parameters.max_cpu_throttle = params->max_cpu_throttle;
>> - }
>> - if (params->has_announce_initial) {
>> - s->parameters.announce_initial = params->announce_initial;
>> - }
>> - if (params->has_announce_max) {
>> - s->parameters.announce_max = params->announce_max;
>> - }
>> - if (params->has_announce_rounds) {
>> - s->parameters.announce_rounds = params->announce_rounds;
>> - }
>> - if (params->has_announce_step) {
>> - s->parameters.announce_step = params->announce_step;
>> - }
>> -
>> - if (params->has_block_bitmap_mapping) {
>> - qapi_free_BitmapMigrationNodeAliasList(
>> - s->parameters.block_bitmap_mapping);
>> -
>> - s->has_block_bitmap_mapping = true;
>> - s->parameters.block_bitmap_mapping =
>> - QAPI_CLONE(BitmapMigrationNodeAliasList,
>> - params->block_bitmap_mapping);
>> - }
>> -
>> - if (params->has_x_vcpu_dirty_limit_period) {
>> - s->parameters.x_vcpu_dirty_limit_period =
>> - params->x_vcpu_dirty_limit_period;
>> - }
>> - if (params->has_vcpu_dirty_limit) {
>> - s->parameters.vcpu_dirty_limit = params->vcpu_dirty_limit;
>> - }
>> -
>> - if (params->has_mode) {
>> - s->parameters.mode = params->mode;
>> - }
>> -
>> - if (params->has_zero_page_detection) {
>> - s->parameters.zero_page_detection = params->zero_page_detection;
>> - }
>> -
>> - if (params->has_direct_io) {
>> - s->parameters.direct_io = params->direct_io;
>> - }
>> + migrate_tls_opts_free(cur);
>> + qapi_free_BitmapMigrationNodeAliasList(cur->block_bitmap_mapping);
>
> So we free these without resetting the pointers. Now, for example,
> cur->tls_creds can point to garbage. Then..
>
>> + QAPI_CLONE_MEMBERS(MigrationParameters, cur, params);
>
> How does this patch guarantee cur->tls_creds's garbage pointer being
> updated? What if params->tls_creds is NULL? Could it?
>
As you've spotted later in the series, all callers of
migrate_params_apply() provide a MigrationParameters struct with all
has_* fields set.
>> }
>>
>> void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
>> @@ -1487,7 +1378,7 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
>> }
>>
>> if (migrate_params_check(&tmp, errp)) {
>> - migrate_params_apply(params);
>> + migrate_params_apply(&tmp);
>> migrate_post_update_params(params, errp);
>> }
>>
>> --
>> 2.35.3
>>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 14/24] migration: Use visitors in migrate_params_test_apply
2025-08-13 20:05 ` Peter Xu
@ 2025-08-14 15:10 ` Fabiano Rosas
2025-08-14 19:40 ` Peter Xu
0 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-08-14 15:10 UTC (permalink / raw)
To: Peter Xu; +Cc: qemu-devel, berrange, armbru
Peter Xu <peterx@redhat.com> writes:
> On Mon, Jun 30, 2025 at 04:59:03PM -0300, Fabiano Rosas wrote:
>> Convert the code in migrate_params_test_apply() from an open-coded
>> copy of every migration parameter to a copy using visitors. The
>> current code has conditionals for each parameter's has_* field, which
>> is exactly what the visitors do.
>>
>> This hides the details of QAPI from the migration code and avoids the
>> need to update migrate_params_test_apply() every time a new migration
>> parameter is added. Both were very confusing and while the visitor
>> code can become a bit involved, there is no need for new contributors
>> to ever touch it.
>>
>> Change the name of the function to a more direct reference of what it
>> does: merging the user params with the temporary copy.
>>
>> Move the QAPI_CLONE_MEMBERS into the caller, so QAPI_CLONE can be used
>> and there's no need to allocate memory in the migration
>> code. Similarly, turn 'tmp' into a pointer so the proper qapi_free_
>> routine can be used.
>>
>> An extra call to migrate_mark_all_params_present() is now needed
>> because the visitors update the has_ field for non-present fields, but
>> we actually want them all set so migrate_params_apply() can copy all
>> of them.
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> ---
>> migration/options.c | 157 +++++++++++++++-----------------------------
>> 1 file changed, 54 insertions(+), 103 deletions(-)
>>
>> diff --git a/migration/options.c b/migration/options.c
>> index 6619b5f21a..695bec5b8f 100644
>> --- a/migration/options.c
>> +++ b/migration/options.c
>> @@ -20,6 +20,10 @@
>> #include "qapi/qapi-commands-migration.h"
>> #include "qapi/qapi-visit-migration.h"
>> #include "qapi/qmp/qerror.h"
>> +#include "qapi/qobject-input-visitor.h"
>> +#include "qapi/qobject-output-visitor.h"
>> +#include "qapi/visitor.h"
>> +#include "qobject/qdict.h"
>> #include "qobject/qnull.h"
>> #include "system/runstate.h"
>> #include "migration/colo.h"
>> @@ -1223,120 +1227,63 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
>> return true;
>> }
>>
>> -static void migrate_params_test_apply(MigrationParameters *params,
>> - MigrationParameters *dest)
>> +static bool migrate_params_merge(MigrationParameters *dst,
>> + MigrationParameters *src, Error **errp)
>> {
>> - MigrationState *s = migrate_get_current();
>> + QObject *ret_out = NULL;
>> + Visitor *v;
>> + bool ok;
>>
>> - QAPI_CLONE_MEMBERS(MigrationParameters, dest, &s->parameters);
>> -
>> - if (params->has_throttle_trigger_threshold) {
>> - dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
>> - }
>> -
>> - if (params->has_cpu_throttle_initial) {
>> - dest->cpu_throttle_initial = params->cpu_throttle_initial;
>> - }
>> -
>> - if (params->has_cpu_throttle_increment) {
>> - dest->cpu_throttle_increment = params->cpu_throttle_increment;
>> + /* free memory from pointers that are about to be assigned */
>> + if (src->has_block_bitmap_mapping) {
>> + qapi_free_BitmapMigrationNodeAliasList(dst->block_bitmap_mapping);
>
> There're quite a few similar cases like this one in this series (including
> the rest below parameters below), where we free stuff but keep the dangling
> pointer around for a while (..hopefully!)..
>
> Should we still try to reset the pointers? Am I the only one that is
> nervous with it?
>
Yeah, no worries, I can clear them all just to be sure.
>> }
>>
>> - if (params->has_cpu_throttle_tailslow) {
>> - dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow;
>> + if (src->tls_creds) {
>> + qapi_free_StrOrNull(dst->tls_creds);
>> }
>>
>> - if (params->tls_creds) {
>> - qapi_free_StrOrNull(dest->tls_creds);
>> - dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
>> + if (src->tls_hostname) {
>> + qapi_free_StrOrNull(dst->tls_hostname);
>> }
>>
>> - if (params->tls_hostname) {
>> - qapi_free_StrOrNull(dest->tls_hostname);
>> - dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
>> + if (src->tls_authz) {
>> + qapi_free_StrOrNull(dst->tls_authz);
>> }
>>
>> - if (params->tls_authz) {
>> - qapi_free_StrOrNull(dest->tls_authz);
>> - dest->tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
>> + /* read in from src */
>> + v = qobject_output_visitor_new(&ret_out);
>> + ok = visit_type_MigrationParameters(v, NULL, &src, errp);
>> + if (!ok) {
>> + goto out;
>> }
>> + visit_complete(v, &ret_out);
>> + visit_free(v);
>>
>> - if (params->has_max_bandwidth) {
>> - dest->max_bandwidth = params->max_bandwidth;
>> + /*
>> + * Write to dst but leave existing fields intact (except for has_*
>> + * which will be updated according to their presence in src).
>> + */
>> + v = qobject_input_visitor_new(ret_out);
>> + ok = visit_start_struct(v, NULL, NULL, 0, errp);
>> + if (!ok) {
>> + goto out;
>> }
>> -
>> - if (params->has_avail_switchover_bandwidth) {
>> - dest->avail_switchover_bandwidth = params->avail_switchover_bandwidth;
>> + ok = visit_type_MigrationParameters_members(v, dst, errp);
>> + if (!ok) {
>> + goto out;
>> }
>> -
>> - if (params->has_downtime_limit) {
>> - dest->downtime_limit = params->downtime_limit;
>> + ok = visit_check_struct(v, errp);
>> + visit_end_struct(v, NULL);
>> + if (!ok) {
>> + goto out;
>> }
>>
>> - if (params->has_x_checkpoint_delay) {
>> - dest->x_checkpoint_delay = params->x_checkpoint_delay;
>> - }
>> +out:
>> + visit_free(v);
>> + qobject_unref(ret_out);
>
> IIUC this is essential the trick we used to play before QAPI_CLONE, before
> commit a15fcc3cf69e.
>
> https://lore.kernel.org/all/1465490926-28625-15-git-send-email-eblake@redhat.com/
>
> Yes, looks similar..
>
> QAPI_CLONE_MEMBERS() will copy everything, which we do not want here. We
> only want to copy where has_* is set. So it's indeed a sligntly different
> request versus the current clone API.
>
> IIUC that can be implemented using a similar qapi clone visitor, however
> instead of g_memdup() on the structs/lists first (or in the case of
> QAPI_CLONE_MEMBERS, we did *dst=*src), we lazy copy all the fields.
>
> I wished this is a generic API we could use. I think it means we'll
> maintain this ourselves. Maybe it's OK.
>
I'm not sure how easy it is to provide a generic API for this. I don't
think there's much space for this code to change anyway, so is fine to
keep it in migration. I'll try to implement a
QAPI_CLONE_PRESENT_MEMBERS, let's see.
>>
>> - if (params->has_multifd_channels) {
>> - dest->multifd_channels = params->multifd_channels;
>> - }
>> - if (params->has_multifd_compression) {
>> - dest->multifd_compression = params->multifd_compression;
>> - }
>> - if (params->has_multifd_qatzip_level) {
>> - dest->multifd_qatzip_level = params->multifd_qatzip_level;
>> - }
>> - if (params->has_multifd_zlib_level) {
>> - dest->multifd_zlib_level = params->multifd_zlib_level;
>> - }
>> - if (params->has_multifd_zstd_level) {
>> - dest->multifd_zstd_level = params->multifd_zstd_level;
>> - }
>> - if (params->has_xbzrle_cache_size) {
>> - dest->xbzrle_cache_size = params->xbzrle_cache_size;
>> - }
>> - if (params->has_max_postcopy_bandwidth) {
>> - dest->max_postcopy_bandwidth = params->max_postcopy_bandwidth;
>> - }
>> - if (params->has_max_cpu_throttle) {
>> - dest->max_cpu_throttle = params->max_cpu_throttle;
>> - }
>> - if (params->has_announce_initial) {
>> - dest->announce_initial = params->announce_initial;
>> - }
>> - if (params->has_announce_max) {
>> - dest->announce_max = params->announce_max;
>> - }
>> - if (params->has_announce_rounds) {
>> - dest->announce_rounds = params->announce_rounds;
>> - }
>> - if (params->has_announce_step) {
>> - dest->announce_step = params->announce_step;
>> - }
>> -
>> - if (params->has_block_bitmap_mapping) {
>> - dest->block_bitmap_mapping = params->block_bitmap_mapping;
>> - }
>> -
>> - if (params->has_x_vcpu_dirty_limit_period) {
>> - dest->x_vcpu_dirty_limit_period =
>> - params->x_vcpu_dirty_limit_period;
>> - }
>> - if (params->has_vcpu_dirty_limit) {
>> - dest->vcpu_dirty_limit = params->vcpu_dirty_limit;
>> - }
>> -
>> - if (params->has_mode) {
>> - dest->mode = params->mode;
>> - }
>> -
>> - if (params->has_zero_page_detection) {
>> - dest->zero_page_detection = params->zero_page_detection;
>> - }
>> -
>> - if (params->has_direct_io) {
>> - dest->direct_io = params->direct_io;
>> - }
>> + return ok;
>> }
>>
>> static void migrate_params_apply(MigrationParameters *params)
>> @@ -1353,7 +1300,9 @@ static void migrate_params_apply(MigrationParameters *params)
>>
>> void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
>> {
>> - MigrationParameters tmp;
>> + MigrationState *s = migrate_get_current();
>> + g_autoptr(MigrationParameters) tmp = QAPI_CLONE(MigrationParameters,
>> + &s->parameters);
>>
>> /*
>> * Convert QTYPE_QNULL and NULL to the empty string (""). Even
>> @@ -1367,7 +1316,9 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
>> tls_opt_to_str(¶ms->tls_hostname);
>> tls_opt_to_str(¶ms->tls_authz);
>>
>> - migrate_params_test_apply(params, &tmp);
>> + if (!migrate_params_merge(tmp, params, errp)) {
>> + return;
>> + }
>>
>> /*
>> * Mark block_bitmap_mapping as present now while we have the
>> @@ -1377,10 +1328,10 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
>> migrate_get_current()->has_block_bitmap_mapping = true;
>> }
>>
>> - if (migrate_params_check(&tmp, errp)) {
>> - migrate_params_apply(&tmp);
>> + if (migrate_params_check(tmp, errp)) {
>> + /* mark all present, so they're all copied */
>> + migrate_mark_all_params_present(tmp);
>
> Ah, I just asked a question in the previous patch on what happens if some
> of the fields will be present. Looks like this line is the answer?
>
Yes, it's either here, or via migrate_param_init().
> This isn't very obvious. Maybe some comment in migrate_params_apply()
> would slightly help (which mentions it must be used when all parameters are
> set)? Or some way to assert it?
>
Yep, I'll add more safeguards.
>> + migrate_params_apply(tmp);
>> migrate_post_update_params(params, errp);
>> }
>> -
>> - migrate_tls_opts_free(&tmp);
>> }
>> --
>> 2.35.3
>>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 20/24] migration: Allow migrate commands to provide the migration config
2025-08-13 21:27 ` Peter Xu
@ 2025-08-14 15:13 ` Fabiano Rosas
0 siblings, 0 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-08-14 15:13 UTC (permalink / raw)
To: Peter Xu; +Cc: qemu-devel, berrange, armbru, Eric Blake, Paolo Bonzini
Peter Xu <peterx@redhat.com> writes:
> On Mon, Jun 30, 2025 at 04:59:09PM -0300, Fabiano Rosas wrote:
>> Allow the migrate and migrate_incoming commands to pass the migration
>> configuration options all at once, dispensing the use of
>> migrate-set-parameters and migrate-set-capabilities.
>>
>> The motivation of this is to simplify the interface with the
>> management layer and avoid the usage of several command invocations to
>> configure a migration. It also avoids stale parameters from a previous
>> migration to influence the current migration.
>>
>> The options that are changed during the migration can still be set
>> with the existing commands.
>>
>> The order of precedence is:
>>
>> 'config' argument > -global migration cmdline > migrate-set-parameters
>> > defaults (migration_properties)
>
> Did you make the 2nd/3rd the wrong way?
>
> config > migrate-set-parameters > -global cmdlines > defaults
>
Good catch. Thanks!
>>
>> I.e. the config takes precedence over all, values not present in the
>> config assume the default values. The -global migration command line
>> option allows the defaults to be overridden for debug.
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>
> Other than that:
>
> Reviewed-by: Peter Xu <peterx@redhat.com>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 24/24] tests/qtest/migration: Pass the migration config to file tests
2025-08-14 14:24 ` Peter Xu
@ 2025-08-14 15:30 ` Fabiano Rosas
2025-08-14 19:45 ` Peter Xu
0 siblings, 1 reply; 73+ messages in thread
From: Fabiano Rosas @ 2025-08-14 15:30 UTC (permalink / raw)
To: Peter Xu; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini
Peter Xu <peterx@redhat.com> writes:
> On Mon, Jun 30, 2025 at 04:59:13PM -0300, Fabiano Rosas wrote:
>> Use the existing file tests to test the new way of passing parameters
>> to the migration via the config argument to qmp_migrate*.
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> ---
>> tests/qtest/migration/file-tests.c | 68 +++++++++++----------------
>> tests/qtest/migration/framework.c | 9 ++--
>> tests/qtest/migration/precopy-tests.c | 1 +
>> 3 files changed, 34 insertions(+), 44 deletions(-)
>>
>> diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c
>> index 4d78ce0855..656d6527e8 100644
>> --- a/tests/qtest/migration/file-tests.c
>> +++ b/tests/qtest/migration/file-tests.c
>> @@ -27,6 +27,7 @@ static void test_precopy_file(void)
>> MigrateCommon args = {
>> .connect_uri = uri,
>> .listen_uri = "defer",
>> + .start.config = qdict_new(),
>> };
>>
>> test_file_common(&args, true);
>> @@ -74,6 +75,7 @@ static void test_precopy_file_offset_fdset(void)
>> .connect_uri = uri,
>> .listen_uri = "defer",
>> .start_hook = migrate_hook_start_file_offset_fdset,
>> + .start.config = qdict_new(),
>> };
>>
>> test_file_common(&args, false);
>> @@ -88,6 +90,7 @@ static void test_precopy_file_offset(void)
>> MigrateCommon args = {
>> .connect_uri = uri,
>> .listen_uri = "defer",
>> + .start.config = qdict_new(),
>> };
>>
>> test_file_common(&args, false);
>> @@ -102,6 +105,7 @@ static void test_precopy_file_offset_bad(void)
>> .connect_uri = uri,
>> .listen_uri = "defer",
>> .result = MIG_TEST_QMP_ERROR,
>> + .start.config = qdict_new(),
>> };
>>
>> test_file_common(&args, false);
>> @@ -114,11 +118,10 @@ static void test_precopy_file_mapped_ram_live(void)
>> MigrateCommon args = {
>> .connect_uri = uri,
>> .listen_uri = "defer",
>> - .start = {
>> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
>> - },
>> + .start.config = qdict_new(),
>> };
>>
>> + qdict_put_bool(args.start.config, "mapped-ram", true);
>> test_file_common(&args, false);
>> }
>>
>> @@ -129,11 +132,9 @@ static void test_precopy_file_mapped_ram(void)
>> MigrateCommon args = {
>> .connect_uri = uri,
>> .listen_uri = "defer",
>> - .start = {
>> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
>> - },
>> + .start.config = qdict_new(),
>> };
>> -
>> + qdict_put_bool(args.start.config, "mapped-ram", true);
>> test_file_common(&args, true);
>> }
>>
>> @@ -144,12 +145,11 @@ static void test_multifd_file_mapped_ram_live(void)
>> MigrateCommon args = {
>> .connect_uri = uri,
>> .listen_uri = "defer",
>> - .start = {
>> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
>> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
>> - },
>> + .start.config = qdict_new(),
>> };
>>
>> + qdict_put_bool(args.start.config, "mapped-ram", true);
>> + qdict_put_bool(args.start.config, "multifd", true);
>> test_file_common(&args, false);
>> }
>>
>> @@ -160,24 +160,13 @@ static void test_multifd_file_mapped_ram(void)
>> MigrateCommon args = {
>> .connect_uri = uri,
>> .listen_uri = "defer",
>> - .start = {
>> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
>> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
>> - },
>> + .start.config = qdict_new(),
>> };
>> -
>> + qdict_put_bool(args.start.config, "mapped-ram", true);
>> + qdict_put_bool(args.start.config, "multifd", true);
>> test_file_common(&args, true);
>> }
>>
>> -static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from,
>> - QTestState *to)
>> -{
>> - migrate_set_parameter_bool(from, "direct-io", true);
>> - migrate_set_parameter_bool(to, "direct-io", true);
>> -
>> - return NULL;
>> -}
>> -
>> static void test_multifd_file_mapped_ram_dio(void)
>> {
>> g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
>> @@ -185,13 +174,13 @@ static void test_multifd_file_mapped_ram_dio(void)
>> MigrateCommon args = {
>> .connect_uri = uri,
>> .listen_uri = "defer",
>> - .start_hook = migrate_hook_start_multifd_mapped_ram_dio,
>> - .start = {
>> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
>> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
>> - },
>> + .start.config = qdict_new(),
>> };
>>
>> + qdict_put_bool(args.start.config, "direct-io", true);
>
> So the start_hook doesn't take args so we need to duplicate all these
> direct-io setups in each test.. I assume not a big deal so it's fine, but
> this is slightly going backward for sure..
>
I'm not sure it is. Having to go follow the hooks is confusing,
specially when hook names start to get similar. Having the test provide
everything it needs right here is clearer. Also, maintenance of the
hooks is a pain when it comes to code conflicts. I'd like to see less
hooks overall.
> What's your plan in mind on the tests? Looks like you want to keep both
> ways in tests/, only use it in some tests to cover both paths (and you
> chose file-tests to start testing config)? Or is this only an example and
> you plan to convert more?
>
Yes the idea is to cover both paths and I chose file-tests for config
arbitrarily.
>
> + qdict_put_bool(args.start.config, "mapped-ram", true);
>> + qdict_put_bool(args.start.config, "multifd", true);
>> +
>> if (!probe_o_direct_support(tmpfs)) {
>> g_test_skip("Filesystem does not support O_DIRECT");
>> return;
>> @@ -235,9 +224,6 @@ static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from,
>> fdset_add_fds(from, file, O_WRONLY, 2, true);
>> fdset_add_fds(to, file, O_RDONLY, 2, true);
>>
>> - migrate_set_parameter_bool(from, "direct-io", true);
>> - migrate_set_parameter_bool(to, "direct-io", true);
>> -
>> return NULL;
>> }
>>
>> @@ -261,12 +247,11 @@ static void test_multifd_file_mapped_ram_fdset(void)
>> .listen_uri = "defer",
>> .start_hook = migrate_hook_start_multifd_mapped_ram_fdset,
>> .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
>> - .start = {
>> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
>> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
>> - },
>> + .start.config = qdict_new(),
>> };
>>
>> + qdict_put_bool(args.start.config, "mapped-ram", true);
>> + qdict_put_bool(args.start.config, "multifd", true);
>> test_file_common(&args, true);
>> }
>>
>> @@ -279,12 +264,13 @@ static void test_multifd_file_mapped_ram_fdset_dio(void)
>> .listen_uri = "defer",
>> .start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio,
>> .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
>> - .start = {
>> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
>> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
>> - },
>> + .start.config = qdict_new(),
>> };
>>
>> + qdict_put_bool(args.start.config, "direct-io", true);
>> + qdict_put_bool(args.start.config, "mapped-ram", true);
>> + qdict_put_bool(args.start.config, "multifd", true);
>> +
>> if (!probe_o_direct_support(tmpfs)) {
>> g_test_skip("Filesystem does not support O_DIRECT");
>> return;
>> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
>> index 5025299d6a..37c5c884af 100644
>> --- a/tests/qtest/migration/framework.c
>> +++ b/tests/qtest/migration/framework.c
>> @@ -974,18 +974,21 @@ void test_file_common(MigrateCommon *args, bool stop_src)
>> }
>>
>> if (args->result == MIG_TEST_QMP_ERROR) {
>> - migrate_qmp_fail(from, args->connect_uri, NULL, "{}");
>> + migrate_qmp_fail(from, args->connect_uri, NULL, "{ 'config': %p }",
>> + args->start.config);
>> goto finish;
>> }
>>
>> - migrate_qmp(from, to, args->connect_uri, NULL, "{}");
>> + migrate_qmp(from, to, args->connect_uri, NULL, "{ 'config': %p }",
>> + args->start.config);
>> wait_for_migration_complete(from);
>>
>> /*
>> * We need to wait for the source to finish before starting the
>> * destination.
>> */
>> - migrate_incoming_qmp(to, args->connect_uri, NULL, "{}");
>> + migrate_incoming_qmp(to, args->connect_uri, NULL, "{ 'config': %p }",
>> + args->start.config);
>> wait_for_migration_complete(to);
>>
>> if (stop_src) {
>> diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
>> index 35d4274c69..9606dc1d02 100644
>> --- a/tests/qtest/migration/precopy-tests.c
>> +++ b/tests/qtest/migration/precopy-tests.c
>> @@ -338,6 +338,7 @@ static void test_precopy_fd_file(void)
>> .connect_uri = "fd:fd-mig",
>> .start_hook = migrate_hook_start_precopy_fd_file,
>> .end_hook = migrate_hook_end_fd,
>> + .start.config = qdict_new(),
>> };
>> test_file_common(&args, true);
>> }
>> --
>> 2.35.3
>>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 14/24] migration: Use visitors in migrate_params_test_apply
2025-08-14 15:10 ` Fabiano Rosas
@ 2025-08-14 19:40 ` Peter Xu
0 siblings, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-08-14 19:40 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru
On Thu, Aug 14, 2025 at 12:10:01PM -0300, Fabiano Rosas wrote:
> > IIUC this is essential the trick we used to play before QAPI_CLONE, before
> > commit a15fcc3cf69e.
> >
> > https://lore.kernel.org/all/1465490926-28625-15-git-send-email-eblake@redhat.com/
> >
> > Yes, looks similar..
> >
> > QAPI_CLONE_MEMBERS() will copy everything, which we do not want here. We
> > only want to copy where has_* is set. So it's indeed a sligntly different
> > request versus the current clone API.
> >
> > IIUC that can be implemented using a similar qapi clone visitor, however
> > instead of g_memdup() on the structs/lists first (or in the case of
> > QAPI_CLONE_MEMBERS, we did *dst=*src), we lazy copy all the fields.
> >
> > I wished this is a generic API we could use. I think it means we'll
> > maintain this ourselves. Maybe it's OK.
> >
>
> I'm not sure how easy it is to provide a generic API for this. I don't
> think there's much space for this code to change anyway, so is fine to
> keep it in migration. I'll try to implement a
> QAPI_CLONE_PRESENT_MEMBERS, let's see.
The new visitor will slightly improve readability on what this code is
doing. But yeah, feel free to choose whatever you see fit when repost (and
if the code will be kept as-is, please consider adding some comments to
help future readers).
Thanks,
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 24/24] tests/qtest/migration: Pass the migration config to file tests
2025-08-14 15:30 ` Fabiano Rosas
@ 2025-08-14 19:45 ` Peter Xu
0 siblings, 0 replies; 73+ messages in thread
From: Peter Xu @ 2025-08-14 19:45 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini
On Thu, Aug 14, 2025 at 12:30:00PM -0300, Fabiano Rosas wrote:
> Peter Xu <peterx@redhat.com> writes:
>
> > On Mon, Jun 30, 2025 at 04:59:13PM -0300, Fabiano Rosas wrote:
> >> Use the existing file tests to test the new way of passing parameters
> >> to the migration via the config argument to qmp_migrate*.
> >>
> >> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> >> ---
> >> tests/qtest/migration/file-tests.c | 68 +++++++++++----------------
> >> tests/qtest/migration/framework.c | 9 ++--
> >> tests/qtest/migration/precopy-tests.c | 1 +
> >> 3 files changed, 34 insertions(+), 44 deletions(-)
> >>
> >> diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c
> >> index 4d78ce0855..656d6527e8 100644
> >> --- a/tests/qtest/migration/file-tests.c
> >> +++ b/tests/qtest/migration/file-tests.c
> >> @@ -27,6 +27,7 @@ static void test_precopy_file(void)
> >> MigrateCommon args = {
> >> .connect_uri = uri,
> >> .listen_uri = "defer",
> >> + .start.config = qdict_new(),
> >> };
> >>
> >> test_file_common(&args, true);
> >> @@ -74,6 +75,7 @@ static void test_precopy_file_offset_fdset(void)
> >> .connect_uri = uri,
> >> .listen_uri = "defer",
> >> .start_hook = migrate_hook_start_file_offset_fdset,
> >> + .start.config = qdict_new(),
> >> };
> >>
> >> test_file_common(&args, false);
> >> @@ -88,6 +90,7 @@ static void test_precopy_file_offset(void)
> >> MigrateCommon args = {
> >> .connect_uri = uri,
> >> .listen_uri = "defer",
> >> + .start.config = qdict_new(),
> >> };
> >>
> >> test_file_common(&args, false);
> >> @@ -102,6 +105,7 @@ static void test_precopy_file_offset_bad(void)
> >> .connect_uri = uri,
> >> .listen_uri = "defer",
> >> .result = MIG_TEST_QMP_ERROR,
> >> + .start.config = qdict_new(),
> >> };
> >>
> >> test_file_common(&args, false);
> >> @@ -114,11 +118,10 @@ static void test_precopy_file_mapped_ram_live(void)
> >> MigrateCommon args = {
> >> .connect_uri = uri,
> >> .listen_uri = "defer",
> >> - .start = {
> >> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> >> - },
> >> + .start.config = qdict_new(),
> >> };
> >>
> >> + qdict_put_bool(args.start.config, "mapped-ram", true);
> >> test_file_common(&args, false);
> >> }
> >>
> >> @@ -129,11 +132,9 @@ static void test_precopy_file_mapped_ram(void)
> >> MigrateCommon args = {
> >> .connect_uri = uri,
> >> .listen_uri = "defer",
> >> - .start = {
> >> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> >> - },
> >> + .start.config = qdict_new(),
> >> };
> >> -
> >> + qdict_put_bool(args.start.config, "mapped-ram", true);
> >> test_file_common(&args, true);
> >> }
> >>
> >> @@ -144,12 +145,11 @@ static void test_multifd_file_mapped_ram_live(void)
> >> MigrateCommon args = {
> >> .connect_uri = uri,
> >> .listen_uri = "defer",
> >> - .start = {
> >> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
> >> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> >> - },
> >> + .start.config = qdict_new(),
> >> };
> >>
> >> + qdict_put_bool(args.start.config, "mapped-ram", true);
> >> + qdict_put_bool(args.start.config, "multifd", true);
> >> test_file_common(&args, false);
> >> }
> >>
> >> @@ -160,24 +160,13 @@ static void test_multifd_file_mapped_ram(void)
> >> MigrateCommon args = {
> >> .connect_uri = uri,
> >> .listen_uri = "defer",
> >> - .start = {
> >> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
> >> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> >> - },
> >> + .start.config = qdict_new(),
> >> };
> >> -
> >> + qdict_put_bool(args.start.config, "mapped-ram", true);
> >> + qdict_put_bool(args.start.config, "multifd", true);
> >> test_file_common(&args, true);
> >> }
> >>
> >> -static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from,
> >> - QTestState *to)
> >> -{
> >> - migrate_set_parameter_bool(from, "direct-io", true);
> >> - migrate_set_parameter_bool(to, "direct-io", true);
> >> -
> >> - return NULL;
> >> -}
> >> -
> >> static void test_multifd_file_mapped_ram_dio(void)
> >> {
> >> g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
> >> @@ -185,13 +174,13 @@ static void test_multifd_file_mapped_ram_dio(void)
> >> MigrateCommon args = {
> >> .connect_uri = uri,
> >> .listen_uri = "defer",
> >> - .start_hook = migrate_hook_start_multifd_mapped_ram_dio,
> >> - .start = {
> >> - .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
> >> - .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
> >> - },
> >> + .start.config = qdict_new(),
> >> };
> >>
> >> + qdict_put_bool(args.start.config, "direct-io", true);
> >
> > So the start_hook doesn't take args so we need to duplicate all these
> > direct-io setups in each test.. I assume not a big deal so it's fine, but
> > this is slightly going backward for sure..
> >
>
> I'm not sure it is. Having to go follow the hooks is confusing,
> specially when hook names start to get similar. Having the test provide
> everything it needs right here is clearer. Also, maintenance of the
> hooks is a pain when it comes to code conflicts. I'd like to see less
> hooks overall.
IMHO it depends. If a hook can greatly dedup code, then I'll go for it.
This one only contains a dio setup, definitely not a huge deal.
>
> > What's your plan in mind on the tests? Looks like you want to keep both
> > ways in tests/, only use it in some tests to cover both paths (and you
> > chose file-tests to start testing config)? Or is this only an example and
> > you plan to convert more?
> >
>
> Yes the idea is to cover both paths and I chose file-tests for config
> arbitrarily.
But then file-tests lose the old coverage on using migrate-set-*.
IMHO, we could choose one that will be the officially suggested way, then
let all tests to use it. With that, we can duplicate one or a few tests to
cover the not-suggested way.
So if "config" is the suggested way, we could make all tests moving over to
"config", then add only one or a few tests to cover migrate-set-parameters?
--
Peter Xu
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 03/24] migration: Normalize tls arguments
2025-07-04 15:37 ` Peter Xu
@ 2025-08-20 15:45 ` Fabiano Rosas
0 siblings, 0 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-08-20 15:45 UTC (permalink / raw)
To: Peter Xu; +Cc: Markus Armbruster, qemu-devel, berrange, Eric Blake
Peter Xu <peterx@redhat.com> writes:
> On Fri, Jul 04, 2025 at 10:12:33AM -0300, Fabiano Rosas wrote:
>
> [...]
>
>> >>> +static void tls_opt_to_str(StrOrNull **tls_opt)
>> >>> +{
>> >>> + StrOrNull *opt = *tls_opt;
>> >>> +
>> >>> + if (!opt) {
>> >>> + return;
>> >>
>> >> ... it can also be null.
>> >>
>> >
>> > Hmm, I'll have to double check, but with the StrOrNull property being
>> > initialized, NULL should not be possible. This looks like a mistake.
>> >
>>
>> The code is correct, this is coming from the QAPI, so it could be NULL
>> in case the user hasn't provided the option. I'll use your suggested
>> wording and the code suggestion as well.
>
> One more trivial question:
>
>>
>> >> Maybe
>> >>
>> >> /* Normalize QTYPE_QNULL to QTYPE_QSTRING "" */
>> >>
>> >>> + }
>> >>> +
>> >>> + switch (opt->type) {
>> >>> + case QTYPE_QSTRING:
>> >>> + return;
>> >>> + case QTYPE_QNULL:
>> >>> + qobject_unref(opt->u.n);
>> >>> + break;
>> >>> + default:
>> >>> + g_assert_not_reached();
>> >>> + }
>> >>> +
>> >>> + opt->type = QTYPE_QSTRING;
>> >>> + opt->u.s = g_strdup("");
>> >>> + *tls_opt = opt;
>
> Does tls_opt ever change? I wonder if this line is not needed, instead
> tls_opt_to_str() can take an "StrOrNull *opt" directly.
>
Well spotted!
>> >>> +}
>> >>
>> >> I'd prefer something like
>> >>
>> >> if (!opt || opt->type == QTYPE_QSTRING) {
>> >> return;
>> >> }
>> >> qobject_unref(opt->u.n);
>> >> opt->type = QTYPE_QSTRING;
>> >> opt->u.s = g_strdup("");
>> >> *tls_opt = opt;
>> >>
>> >> But this is clearly a matter of taste.
>>
>> This is better indeed. I was moving back-and-forth between
>> implementations and the code ended up a bit weird. Thanks!
>>
^ permalink raw reply [flat|nested] 73+ messages in thread
* Re: [PATCH v2 21/24] tests/qtest/migration: Take reference when passing %p to qtest_qmp
2025-08-13 22:22 ` Peter Xu
@ 2025-08-21 17:20 ` Fabiano Rosas
0 siblings, 0 replies; 73+ messages in thread
From: Fabiano Rosas @ 2025-08-21 17:20 UTC (permalink / raw)
To: Peter Xu; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini
Peter Xu <peterx@redhat.com> writes:
> On Mon, Jun 30, 2025 at 04:59:10PM -0300, Fabiano Rosas wrote:
>> The documentation of qobject_from_jsonv() states that it takes
>> ownership of any %p arguments passed in.
>>
>> Next patches will add config-passing to the tests, so take an extra
>> reference in the migrate_qmp* functions to ensure the config is not
>> freed from under us.
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> ---
>> tests/qtest/migration/migration-qmp.c | 8 +++++---
>> 1 file changed, 5 insertions(+), 3 deletions(-)
>>
>> diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
>> index fb59741b2c..d82ac8c750 100644
>> --- a/tests/qtest/migration/migration-qmp.c
>> +++ b/tests/qtest/migration/migration-qmp.c
>> @@ -97,7 +97,8 @@ void migrate_qmp_fail(QTestState *who, const char *uri,
>> }
>>
>> err = qtest_qmp_assert_failure_ref(
>> - who, "{ 'execute': 'migrate', 'arguments': %p}", args);
>> + who, "{ 'execute': 'migrate', 'arguments': %p}",
>> + qdict_clone_shallow(args));
>>
>> g_assert(qdict_haskey(err, "desc"));
>>
>> @@ -136,7 +137,8 @@ void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
>> }
>>
>> qtest_qmp_assert_success(who,
>> - "{ 'execute': 'migrate', 'arguments': %p}", args);
>> + "{ 'execute': 'migrate', 'arguments': %p}",
>> + qdict_clone_shallow(args));
>> }
>>
>> void migrate_set_capability(QTestState *who, const char *capability,
>> @@ -174,7 +176,7 @@ void migrate_incoming_qmp(QTestState *to, const char *uri, QObject *channels,
>> migrate_set_capability(to, "events", true);
>>
>> rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
>> - args);
>> + qdict_clone_shallow(args));
>
> Isn't it intentional to pass over the ownership in the three places here?
> I don't see otherwise where args got freed.
>
Hmm, I think I remember the issue being that qobject_from_jsonv() freed
before the object it reached QMP, so indeed this needs to be freed
before the migrate_qmp functions return.
I don't really understand why ASAN didn't spot it though. I'll fix, thanks!
> OTOH, I saw there're yet another three similar usages of %p in framework.c:
>
> x1:migration [migration-params-caps-no-config]$ git grep -A1 %p framework.c
> framework.c: migrate_qmp_fail(from, args->connect_uri, NULL, "{ 'config': %p }",
> framework.c- args->start.config);
> --
> framework.c: migrate_qmp(from, to, args->connect_uri, NULL, "{ 'config': %p }",
> framework.c- args->start.config);
> --
> framework.c: migrate_incoming_qmp(to, args->connect_uri, NULL, "{ 'config': %p }",
> framework.c- args->start.config);
>
> They seem to be suspecious instead, as they seem to have lost ownership of
> args->start.config, so args->start.config can start to point to garbage?
>
>>
>> if (!qdict_haskey(rsp, "return")) {
>> g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true);
>> --
>> 2.35.3
>>
^ permalink raw reply [flat|nested] 73+ messages in thread
end of thread, other threads:[~2025-08-21 17:21 UTC | newest]
Thread overview: 73+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-30 19:58 [PATCH v2 00/24] migration: Unify capabilities and parameters Fabiano Rosas
2025-06-30 19:58 ` [PATCH v2 01/24] migration: Fix leak of block_bitmap_mapping Fabiano Rosas
2025-07-01 6:12 ` Markus Armbruster
2025-07-03 21:31 ` Peter Xu
2025-07-04 5:09 ` Markus Armbruster
2025-06-30 19:58 ` [PATCH v2 02/24] migration: Add a qdev property for StrOrNull Fabiano Rosas
2025-07-01 6:38 ` Markus Armbruster
2025-07-03 22:32 ` Peter Xu
2025-07-04 12:58 ` Fabiano Rosas
2025-06-30 19:58 ` [PATCH v2 03/24] migration: Normalize tls arguments Fabiano Rosas
2025-07-01 7:46 ` Markus Armbruster
2025-07-01 14:20 ` Fabiano Rosas
2025-07-04 13:12 ` Fabiano Rosas
2025-07-04 15:37 ` Peter Xu
2025-08-20 15:45 ` Fabiano Rosas
2025-06-30 19:58 ` [PATCH v2 04/24] migration: Remove MigrateSetParameters Fabiano Rosas
2025-07-01 8:00 ` Markus Armbruster
2025-07-03 19:34 ` Fabiano Rosas
2025-07-04 4:25 ` Markus Armbruster
2025-07-04 15:39 ` Peter Xu
2025-06-30 19:58 ` [PATCH v2 05/24] qapi/migration: Don't document MigrationParameter Fabiano Rosas
2025-07-01 8:04 ` Markus Armbruster
2025-07-04 15:40 ` Peter Xu
2025-06-30 19:58 ` [PATCH v2 06/24] migration: Run a post update routine after setting parameters Fabiano Rosas
2025-06-30 19:58 ` [PATCH v2 07/24] migration: Add a flag to track block-bitmap-mapping input Fabiano Rosas
2025-07-04 15:42 ` Peter Xu
2025-06-30 19:58 ` [PATCH v2 08/24] migration: Remove checks for s->parameters has_* fields Fabiano Rosas
2025-06-30 19:58 ` [PATCH v2 09/24] migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE Fabiano Rosas
2025-07-04 16:04 ` Peter Xu
2025-06-30 19:58 ` [PATCH v2 10/24] migration: Extract code to mark all parameters as present Fabiano Rosas
2025-06-30 19:59 ` [PATCH v2 11/24] migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters Fabiano Rosas
2025-07-04 16:11 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 12/24] migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply Fabiano Rosas
2025-06-30 19:59 ` [PATCH v2 13/24] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply Fabiano Rosas
2025-08-13 19:05 ` Peter Xu
2025-08-14 15:04 ` Fabiano Rosas
2025-06-30 19:59 ` [PATCH v2 14/24] migration: Use visitors in migrate_params_test_apply Fabiano Rosas
2025-08-13 20:05 ` Peter Xu
2025-08-14 15:10 ` Fabiano Rosas
2025-08-14 19:40 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 15/24] migration: Cleanup hmp_info_migrate_parameters Fabiano Rosas
2025-08-13 20:40 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 16/24] migration: Add capabilities into MigrationParameters Fabiano Rosas
2025-07-01 8:25 ` Markus Armbruster
2025-07-04 13:15 ` Fabiano Rosas
2025-07-04 14:04 ` Markus Armbruster
2025-07-04 14:48 ` Fabiano Rosas
2025-07-04 15:04 ` Markus Armbruster
2025-07-04 16:33 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 17/24] migration: Remove s->capabilities Fabiano Rosas
2025-08-13 20:48 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 18/24] qapi/migration: Deprecate capabilities commands Fabiano Rosas
2025-07-01 8:30 ` Markus Armbruster
2025-07-01 8:38 ` Jiri Denemark
2025-07-01 9:00 ` Peter Krempa
2025-07-01 9:10 ` Daniel P. Berrangé
2025-08-13 20:50 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 19/24] migration: Store the initial values used for s->parameters Fabiano Rosas
2025-08-13 21:09 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 20/24] migration: Allow migrate commands to provide the migration config Fabiano Rosas
2025-07-01 8:35 ` Markus Armbruster
2025-08-13 21:27 ` Peter Xu
2025-08-14 15:13 ` Fabiano Rosas
2025-06-30 19:59 ` [PATCH v2 21/24] tests/qtest/migration: Take reference when passing %p to qtest_qmp Fabiano Rosas
2025-08-13 22:22 ` Peter Xu
2025-08-21 17:20 ` Fabiano Rosas
2025-06-30 19:59 ` [PATCH v2 22/24] tests/qtest/migration: Adapt the capabilities helper to take a config Fabiano Rosas
2025-08-14 14:02 ` Peter Xu
2025-06-30 19:59 ` [PATCH v2 23/24] tests/qtest/migration: Adapt convergence routines to config Fabiano Rosas
2025-06-30 19:59 ` [PATCH v2 24/24] tests/qtest/migration: Pass the migration config to file tests Fabiano Rosas
2025-08-14 14:24 ` Peter Xu
2025-08-14 15:30 ` Fabiano Rosas
2025-08-14 19:45 ` Peter Xu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).