QEMU supports a migration parameter to determine whether zero-page checking should be performed and if yes, where it should be performed (i.e., in the main migration thread or multifd threads). Add support for this in libvirt in the form of a boolean VIR_MIGRATE_PARAM_ZERO_PAGE_DETECTION migration parameter. Setting this to true with multifd will offload the check to multifd threads. Without multifd enabled, the check will happen in the main migration thread. Setting this to false disables zero-page checking. When the parameter is not set, QEMU's default is kept. Signed-off-by: Tejus GK <tejus.gk@nutanix.com> --- docs/manpages/virsh.rst | 6 ++++++ include/libvirt/libvirt-domain.h | 16 ++++++++++++++++ src/qemu/qemu_migration.c | 1 + src/qemu/qemu_migration_params.c | 30 ++++++++++++++++++++++++++++++ src/qemu/qemu_migration_params.h | 1 + tools/virsh-domain.c | 11 +++++++++++ 6 files changed, 65 insertions(+) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index f533a10776..b5a796a00a 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -3802,6 +3802,7 @@ migrate [--bandwidth bandwidth] [--tls-destination hostname] [--disks-uri URI] [--copy-storage-synchronous-writes] [--available-switchover-bandwidth bandwidth] + [--zero-page-detection] Migrate domain to another host. Add *--live* for live migration; <--p2p> for peer-2-peer migration; *--direct* for direct migration; or *--tunnelled* @@ -3953,6 +3954,11 @@ parallel connections. The number of such connections can be set using network link between the source and the target and thus speeding up the migration. +*--zero-page-detection* requests pages containing only zeros to be detected by +the parallel migration threads rather than the main migration thread. Without +*--parallel*, zero pages are detected by the main migration thread. When the +option is not set, the hypervisor default is used. + Running migration can be canceled by interrupting virsh (usually using ``Ctrl-C``) or by ``domjobabort`` command sent from another virsh instance. diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 9ee153c6eb..0e68a572c3 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -1468,6 +1468,22 @@ typedef enum { */ # define VIR_MIGRATE_PARAM_TLS_DESTINATION "tls.destination" +/** + * VIR_MIGRATE_PARAM_ZERO_PAGE_DETECTION: + * + * virDomainMigrate* params field: whether zero page detection should be + * performed during migration. As VIR_TYPED_PARAM_BOOLEAN. + * + * When enabled with parallel migration, zero pages are detected by the multifd + * threads rather than the main migration thread. When enabled without parallel + * migration, zero pages are detected by the main migration thread. + * When disabled, zero pages are transferred as normal pages. + * When not set, the hypervisor default is used. + * + * Since: 12.9.0 + */ +# define VIR_MIGRATE_PARAM_ZERO_PAGE_DETECTION "zero_page_detection" + /* Domain migration. */ virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, unsigned long flags, const char *dname, diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 76661de09a..13113ceaff 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -110,6 +110,7 @@ const virTypedParamValidationTemplate qemuMigrationParametersValidation[] = { { VIR_MIGRATE_PARAM_TLS_DESTINATION, VIR_TYPED_PARAM_STRING }, { VIR_MIGRATE_PARAM_DISKS_URI, VIR_TYPED_PARAM_STRING }, { VIR_MIGRATE_PARAM_BANDWIDTH_AVAIL_SWITCHOVER, VIR_TYPED_PARAM_ULLONG }, + { VIR_MIGRATE_PARAM_ZERO_PAGE_DETECTION, VIR_TYPED_PARAM_BOOLEAN }, { "", 0 } }; diff --git a/src/qemu/qemu_migration_params.c b/src/qemu/qemu_migration_params.c index dd47516742..e1ead04068 100644 --- a/src/qemu/qemu_migration_params.c +++ b/src/qemu/qemu_migration_params.c @@ -131,6 +131,7 @@ VIR_ENUM_IMPL(qemuMigrationParam, "multifd-zstd-level", "avail-switchover-bandwidth", "direct-io", + "zero-page-detection", ); typedef struct _qemuMigrationParamsAlwaysOnItem qemuMigrationParamsAlwaysOnItem; @@ -332,6 +333,9 @@ static const qemuMigrationParamInfoItem qemuMigrationParamInfo[] = { [QEMU_MIGRATION_PARAM_DIRECT_IO] = { .type = QEMU_MIGRATION_PARAM_TYPE_BOOL, }, + [QEMU_MIGRATION_PARAM_ZERO_PAGE_DETECTION] = { + .type = QEMU_MIGRATION_PARAM_TYPE_STRING, + }, }; G_STATIC_ASSERT(G_N_ELEMENTS(qemuMigrationParamInfo) == QEMU_MIGRATION_PARAM_LAST); @@ -692,6 +696,29 @@ qemuMigrationParamsSetCompression(virTypedParameterPtr params, } +static int +qemuMigrationParamsSetZeroPageDetection(virTypedParameterPtr params, + int nparams, + qemuMigrationParams *migParams) +{ + int zeroPageDetection; + int rc; + + if ((rc = virTypedParamsGetBoolean(params, nparams, + VIR_MIGRATE_PARAM_ZERO_PAGE_DETECTION, + &zeroPageDetection)) < 0) + return -1; + + if (rc == 1) { + migParams->params[QEMU_MIGRATION_PARAM_ZERO_PAGE_DETECTION].value.s = + g_strdup(zeroPageDetection ? "multifd" : "none"); + migParams->params[QEMU_MIGRATION_PARAM_ZERO_PAGE_DETECTION].set = true; + } + + return 0; +} + + void qemuMigrationParamsSetBlockDirtyBitmapMapping(qemuMigrationParams *migParams, virJSONValue **params) @@ -792,6 +819,9 @@ qemuMigrationParamsFromFlags(virTypedParameterPtr params, if (qemuMigrationParamsSetCompression(params, nparams, flags, migParams) < 0) return NULL; + if (qemuMigrationParamsSetZeroPageDetection(params, nparams, migParams) < 0) + return NULL; + return g_steal_pointer(&migParams); } diff --git a/src/qemu/qemu_migration_params.h b/src/qemu/qemu_migration_params.h index b7a829b85a..131fe82fc0 100644 --- a/src/qemu/qemu_migration_params.h +++ b/src/qemu/qemu_migration_params.h @@ -67,6 +67,7 @@ typedef enum { QEMU_MIGRATION_PARAM_MULTIFD_ZSTD_LEVEL, QEMU_MIGRATION_PARAM_AVAIL_SWITCHOVER_BANDWIDTH, QEMU_MIGRATION_PARAM_DIRECT_IO, + QEMU_MIGRATION_PARAM_ZERO_PAGE_DETECTION, QEMU_MIGRATION_PARAM_LAST } qemuMigrationParam; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 2c64f19a19..18854ad0c3 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -11432,6 +11432,10 @@ static const vshCmdOptDef opts_migrate[] = { .type = VSH_OT_INT, .help = N_("bandwidth (in MiB/s) available for the final phase of migration") }, + {.name = "zero-page-detection", + .type = VSH_OT_BOOL, + .help = N_("enable zero page detection in parallel migration threads") + }, {.name = NULL} }; @@ -11733,6 +11737,13 @@ doMigrate(void *opaque) goto save_error; } + if (vshCommandOptBool(cmd, "zero-page-detection")) { + if (virTypedParamsAddBoolean(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_ZERO_PAGE_DETECTION, + true) < 0) + goto save_error; + } + if ((rv = vshCommandOptInt(ctl, cmd, "comp-zlib-level", &intOpt)) < 0) { goto out; } else if (rv > 0) { -- 2.43.7