@ -95,6 +95,9 @@ enum mig_rp_message_type {
MIG_RP_MSG_MAX
} ;
/* Migration channel types */
enum { CH_MAIN , CH_MULTIFD , CH_POSTCOPY } ;
/* When we add fault tolerance, we could have several
migrations at once . For now we don ' t need to add
dynamic creation of migration */
@ -941,9 +944,8 @@ static void migration_incoming_setup(QEMUFile *f)
{
MigrationIncomingState * mis = migration_incoming_get_current ( ) ;
if ( ! mis - > from_src_file ) {
mis - > from_src_file = f ;
}
assert ( ! mis - > from_src_file ) ;
mis - > from_src_file = f ;
qemu_file_set_blocking ( f , false ) ;
}
@ -995,28 +997,19 @@ void migration_fd_process_incoming(QEMUFile *f)
migration_incoming_process ( ) ;
}
/*
* Returns true when we want to start a new incoming migration process ,
* false otherwise .
*/
static bool migration_should_start_incoming ( bool main_channel )
static bool migration_has_main_and_multifd_channels ( void )
{
/* Multifd doesn't start unless all channels are established */
if ( migrate_multifd ( ) ) {
return migration_has_all_channels ( ) ;
MigrationIncomingState * mis = migration_incoming_get_current ( ) ;
if ( ! mis - > from_src_file ) {
/* main channel not established */
return false ;
}
/* Preempt channel only starts when the main channel is created */
if ( migrate_postcopy_preempt ( ) ) {
return main_channel ;
if ( migrate_multifd ( ) & & ! multifd_recv_all_channels_created ( ) ) {
return false ;
}
/*
* For all the rest types of migration , we should only reach here when
* it ' s the main channel that ' s being created , and we should always
* proceed with this channel .
*/
assert ( main_channel ) ;
/* main and all multifd channels are established */
return true ;
}
@ -1025,59 +1018,81 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
MigrationIncomingState * mis = migration_incoming_get_current ( ) ;
Error * local_err = NULL ;
QEMUFile * f ;
bool default_channel = true ;
uint8_t channel ;
uint32_t channel_magic = 0 ;
int ret = 0 ;
if ( migrate_multifd ( ) & & ! migrate_mapped_ram ( ) & &
! migrate_postcopy_ram ( ) & &
qio_channel_has_feature ( ioc , QIO_CHANNEL_FEATURE_READ_MSG_PEEK ) ) {
/*
* With multiple channels , it is possible that we receive channels
* out of order on destination side , causing incorrect mapping of
* source channels on destination side . Check channel MAGIC to
* decide type of channel . Please note this is best effort , postcopy
* preempt channel does not send any magic number so avoid it for
* postcopy live migration . Also tls live migration already does
* tls handshake while initializing main channel so with tls this
* issue is not possible .
*/
ret = migration_channel_read_peek ( ioc , ( void * ) & channel_magic ,
sizeof ( channel_magic ) , errp ) ;
if ( ! migration_has_main_and_multifd_channels ( ) ) {
if ( qio_channel_has_feature ( ioc , QIO_CHANNEL_FEATURE_READ_MSG_PEEK ) ) {
/*
* With multiple channels , it is possible that we receive channels
* out of order on destination side , causing incorrect mapping of
* source channels on destination side . Check channel MAGIC to
* decide type of channel . Please note this is best effort ,
* postcopy preempt channel does not send any magic number so
* avoid it for postcopy live migration . Also tls live migration
* already does tls handshake while initializing main channel so
* with tls this issue is not possible .
*/
ret = migration_channel_read_peek ( ioc , ( void * ) & channel_magic ,
sizeof ( channel_magic ) , errp ) ;
if ( ret ! = 0 ) {
return ;
}
if ( ret ! = 0 ) {
channel_magic = be32_to_cpu ( channel_magic ) ;
if ( channel_magic = = QEMU_VM_FILE_MAGIC ) {
channel = CH_MAIN ;
} else if ( channel_magic = = MULTIFD_MAGIC ) {
assert ( migrate_multifd ( ) ) ;
channel = CH_MULTIFD ;
} else if ( ! mis - > from_src_file & &
mis - > state = = MIGRATION_STATUS_POSTCOPY_PAUSED ) {
/* reconnect main channel for postcopy recovery */
channel = CH_MAIN ;
} else {
error_setg ( errp , " unknown channel magic: %u " , channel_magic ) ;
return ;
}
} else if ( mis - > from_src_file & & migrate_multifd ( ) ) {
/*
* Non - peekable channels like tls / file are processed as
* multifd channels when multifd is enabled .
*/
channel = CH_MULTIFD ;
} else if ( ! mis - > from_src_file ) {
channel = CH_MAIN ;
} else {
error_setg ( errp , " non-peekable channel used without multifd " ) ;
return ;
}
default_channel = ( channel_magic = = cpu_to_be32 ( QEMU_VM_FILE_MAGIC ) ) ;
} else {
default_channel = ! mis - > from_src_file ;
assert ( migrate_postcopy_preempt ( ) ) ;
channel = CH_POSTCOPY ;
}
if ( multifd_recv_setup ( errp ) ! = 0 ) {
return ;
}
if ( default_channel ) {
if ( channel = = CH_MAIN ) {
f = qemu_file_new_input ( ioc ) ;
migration_incoming_setup ( f ) ;
} else {
} else if ( channel = = CH_MULTIFD ) {
/* Multiple connections */
assert ( migration_needs_multiple_sockets ( ) ) ;
if ( migrate_multifd ( ) ) {
multifd_recv_new_channel ( ioc , & local_err ) ;
} else {
assert ( migrate_postcopy_preempt ( ) ) ;
f = qemu_file_new_input ( ioc ) ;
postcopy_preempt_new_channel ( mis , f ) ;
}
multifd_recv_new_channel ( ioc , & local_err ) ;
if ( local_err ) {
error_propagate ( errp , local_err ) ;
return ;
}
} else if ( channel = = CH_POSTCOPY ) {
assert ( ! mis - > postcopy_qemufile_dst ) ;
f = qemu_file_new_input ( ioc ) ;
postcopy_preempt_new_channel ( mis , f ) ;
return ;
}
if ( migration_should_start_incoming ( default_channel ) ) {
if ( migration_has_main_and_multifd_channels ( ) ) {
/* If it's a recovery, we're done */
if ( postcopy_try_recover ( ) ) {
return ;
@ -1094,18 +1109,13 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
*/
bool migration_has_all_channels ( void )
{
MigrationIncomingState * mis = migration_incoming_get_current ( ) ;
if ( ! mis - > from_src_file ) {
if ( ! migration_has_main_and_multifd_channels ( ) ) {
return false ;
}
if ( migrate_multifd ( ) ) {
return multifd_recv_all_channels_created ( ) ;
}
if ( migrate_postcopy_preempt ( ) ) {
return mis - > postcopy_qemufile_dst ! = NULL ;
MigrationIncomingState * mis = migration_incoming_get_current ( ) ;
if ( migrate_postcopy_preempt ( ) & & ! mis - > postcopy_qemufile_dst ) {
return false ;
}
return true ;