migration: introduce 'background-snapshot' migration capability

Add new capability to 'qapi/migration.json' schema.
Update migrate_caps_check() to validate enabled capability set
against introduced one. Perform checks for required kernel features
and compatibility with guest memory backends.

Signed-off-by: Andrey Gruzdev <andrey.gruzdev@virtuozzo.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Acked-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20210129101407.103458-2-andrey.gruzdev@virtuozzo.com>
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
This commit is contained in:
Andrey Gruzdev 2021-01-29 13:14:03 +03:00 committed by Dr. David Alan Gilbert
parent 1dfafcbd39
commit 6e8c25b4c6
5 changed files with 134 additions and 1 deletions

View File

@ -58,6 +58,7 @@
#include "qemu/queue.h" #include "qemu/queue.h"
#include "multifd.h" #include "multifd.h"
#include "qemu/yank.h" #include "qemu/yank.h"
#include "sysemu/cpus.h"
#ifdef CONFIG_VFIO #ifdef CONFIG_VFIO
#include "hw/vfio/vfio-common.h" #include "hw/vfio/vfio-common.h"
@ -134,6 +135,38 @@ enum mig_rp_message_type {
MIG_RP_MSG_MAX MIG_RP_MSG_MAX
}; };
/* 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_COMPRESS,
MIGRATION_CAPABILITY_XBZRLE,
MIGRATION_CAPABILITY_X_COLO,
MIGRATION_CAPABILITY_VALIDATE_UUID);
/* When we add fault tolerance, we could have several /* When we add fault tolerance, we could have several
migrations at once. For now we don't need to add migrations at once. For now we don't need to add
dynamic creation of migration */ dynamic creation of migration */
@ -1089,6 +1122,31 @@ static void fill_source_migration_info(MigrationInfo *info)
info->status = s->state; info->status = s->state;
} }
typedef enum WriteTrackingSupport {
WT_SUPPORT_UNKNOWN = 0,
WT_SUPPORT_ABSENT,
WT_SUPPORT_AVAILABLE,
WT_SUPPORT_COMPATIBLE
} WriteTrackingSupport;
static
WriteTrackingSupport migrate_query_write_tracking(void)
{
/* Check if kernel supports required UFFD features */
if (!ram_write_tracking_available()) {
return WT_SUPPORT_ABSENT;
}
/*
* Check if current memory configuration is
* compatible with required UFFD features.
*/
if (!ram_write_tracking_compatible()) {
return WT_SUPPORT_AVAILABLE;
}
return WT_SUPPORT_COMPATIBLE;
}
/** /**
* @migration_caps_check - check capability validity * @migration_caps_check - check capability validity
* *
@ -1150,6 +1208,39 @@ static bool migrate_caps_check(bool *cap_list,
} }
} }
if (cap_list[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) {
WriteTrackingSupport wt_support;
int idx;
/*
* Check if 'background-snapshot' capability is supported by
* host kernel and compatible with guest memory configuration.
*/
wt_support = migrate_query_write_tracking();
if (wt_support < WT_SUPPORT_AVAILABLE) {
error_setg(errp, "Background-snapshot is not supported by host kernel");
return false;
}
if (wt_support < WT_SUPPORT_COMPATIBLE) {
error_setg(errp, "Background-snapshot is not compatible "
"with guest memory configuration");
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 (cap_list[incomp_cap]) {
error_setg(errp,
"Background-snapshot is not compatible with %s",
MigrationCapability_str(incomp_cap));
return false;
}
}
}
return true; return true;
} }
@ -2491,6 +2582,15 @@ bool migrate_use_block_incremental(void)
return s->parameters.block_incremental; return s->parameters.block_incremental;
} }
bool migrate_background_snapshot(void)
{
MigrationState *s;
s = migrate_get_current();
return s->enabled_capabilities[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT];
}
/* migration thread support */ /* migration thread support */
/* /*
* Something bad happened to the RP stream, mark an error * Something bad happened to the RP stream, mark an error
@ -3784,6 +3884,8 @@ static Property migration_properties[] = {
DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK), DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK),
DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH), 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-multifd", MIGRATION_CAPABILITY_MULTIFD),
DEFINE_PROP_MIG_CAP("x-background-snapshot",
MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };

View File

@ -341,6 +341,7 @@ int migrate_compress_wait_thread(void);
int migrate_decompress_threads(void); int migrate_decompress_threads(void);
bool migrate_use_events(void); bool migrate_use_events(void);
bool migrate_postcopy_blocktime(void); bool migrate_postcopy_blocktime(void);
bool migrate_background_snapshot(void);
/* Sending on the return path - generic and then for each message type */ /* Sending on the return path - generic and then for each message type */
void migrate_send_rp_shut(MigrationIncomingState *mis, void migrate_send_rp_shut(MigrationIncomingState *mis,

View File

@ -3788,6 +3788,27 @@ static int ram_resume_prepare(MigrationState *s, void *opaque)
return 0; return 0;
} }
/* ram_write_tracking_available: check if kernel supports required UFFD features
*
* Returns true if supports, false otherwise
*/
bool ram_write_tracking_available(void)
{
/* TODO: implement */
return false;
}
/* ram_write_tracking_compatible: check if guest configuration is
* compatible with 'write-tracking'
*
* Returns true if compatible, false otherwise
*/
bool ram_write_tracking_compatible(void)
{
/* TODO: implement */
return false;
}
static SaveVMHandlers savevm_ram_handlers = { static SaveVMHandlers savevm_ram_handlers = {
.save_setup = ram_save_setup, .save_setup = ram_save_setup,
.save_live_iterate = ram_save_iterate, .save_live_iterate = ram_save_iterate,

View File

@ -79,4 +79,8 @@ void colo_flush_ram_cache(void);
void colo_release_ram_cache(void); void colo_release_ram_cache(void);
void colo_incoming_start_dirty_log(void); void colo_incoming_start_dirty_log(void);
/* Background snapshot */
bool ram_write_tracking_available(void);
bool ram_write_tracking_compatible(void);
#endif #endif

View File

@ -442,6 +442,11 @@
# @validate-uuid: Send the UUID of the source to allow the destination # @validate-uuid: Send the UUID of the source to allow the destination
# to ensure it is the same. (since 4.2) # 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)
#
# Since: 1.2 # Since: 1.2
## ##
{ 'enum': 'MigrationCapability', { 'enum': 'MigrationCapability',
@ -449,7 +454,7 @@
'compress', 'events', 'postcopy-ram', 'x-colo', 'release-ram', 'compress', 'events', 'postcopy-ram', 'x-colo', 'release-ram',
'block', 'return-path', 'pause-before-switchover', 'multifd', 'block', 'return-path', 'pause-before-switchover', 'multifd',
'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate', 'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate',
'x-ignore-shared', 'validate-uuid' ] } 'x-ignore-shared', 'validate-uuid', 'background-snapshot'] }
## ##
# @MigrationCapabilityStatus: # @MigrationCapabilityStatus: