@ -92,7 +92,7 @@ enum mig_rp_message_type {
static MigrationState * current_migration ;
static MigrationIncomingState * current_incoming ;
static GSList * migration_blockers ;
static GSList * migration_blockers [ MIG_MODE__MAX ] ;
static bool migration_object_check ( MigrationState * ms , Error * * errp ) ;
static int migration_maybe_pause ( MigrationState * s ,
@ -1043,7 +1043,7 @@ static void fill_source_migration_info(MigrationInfo *info)
{
MigrationState * s = migrate_get_current ( ) ;
int state = qatomic_read ( & s - > state ) ;
GSList * cur_blocker = migration_blockers ;
GSList * cur_blocker = migration_blockers [ migrate_mode ( ) ] ;
info - > blocked_reasons = NULL ;
@ -1507,38 +1507,105 @@ int migrate_init(MigrationState *s, Error **errp)
return 0 ;
}
int migrate_add_blocker_internal ( Error * * reasonp , Error * * errp )
static bool is_busy ( Error * * reasonp , Error * * errp )
{
ERRP_GUARD ( ) ;
/* Snapshots are similar to migrations, so check RUN_STATE_SAVE_VM too. */
if ( runstate_check ( RUN_STATE_SAVE_VM ) | | ! migration_is_idle ( ) ) {
error_propagate_prepend ( errp , * reasonp ,
" disallowing migration blocker "
" (migration/snapshot in progress) for: " ) ;
* reasonp = NULL ;
return - EBUSY ;
return true ;
}
migration_blockers = g_slist_prepend ( migration_blockers , * reasonp ) ;
return 0 ;
return false ;
}
int migrate_ add_ block er ( Error * * reasonp , Error * * errp )
stat ic bool is_only_ migratable( Error * * reasonp , Error * * errp , int modes )
{
if ( only_migratable ) {
ERRP_GUARD ( ) ;
if ( only_migratable & & ( modes & BIT ( MIG_MODE_NORMAL ) ) ) {
error_propagate_prepend ( errp , * reasonp ,
" disallowing migration blocker "
" (--only-migratable) for: " ) ;
* reasonp = NULL ;
return true ;
}
return false ;
}
static int get_modes ( MigMode mode , va_list ap )
{
int modes = 0 ;
while ( mode ! = - 1 & & mode ! = MIG_MODE_ALL ) {
assert ( mode > = MIG_MODE_NORMAL & & mode < MIG_MODE__MAX ) ;
modes | = BIT ( mode ) ;
mode = va_arg ( ap , MigMode ) ;
}
if ( mode = = MIG_MODE_ALL ) {
modes = BIT ( MIG_MODE__MAX ) - 1 ;
}
return modes ;
}
static int add_blockers ( Error * * reasonp , Error * * errp , int modes )
{
for ( MigMode mode = 0 ; mode < MIG_MODE__MAX ; mode + + ) {
if ( modes & BIT ( mode ) ) {
migration_blockers [ mode ] = g_slist_prepend ( migration_blockers [ mode ] ,
* reasonp ) ;
}
}
return 0 ;
}
int migrate_add_blocker ( Error * * reasonp , Error * * errp )
{
return migrate_add_blocker_modes ( reasonp , errp , MIG_MODE_ALL ) ;
}
int migrate_add_blocker_normal ( Error * * reasonp , Error * * errp )
{
return migrate_add_blocker_modes ( reasonp , errp , MIG_MODE_NORMAL , - 1 ) ;
}
int migrate_add_blocker_modes ( Error * * reasonp , Error * * errp , MigMode mode , . . . )
{
int modes ;
va_list ap ;
va_start ( ap , mode ) ;
modes = get_modes ( mode , ap ) ;
va_end ( ap ) ;
if ( is_only_migratable ( reasonp , errp , modes ) ) {
return - EACCES ;
} else if ( is_busy ( reasonp , errp ) ) {
return - EBUSY ;
}
return add_blockers ( reasonp , errp , modes ) ;
}
return migrate_add_blocker_internal ( reasonp , errp ) ;
int migrate_add_blocker_internal ( Error * * reasonp , Error * * errp )
{
int modes = BIT ( MIG_MODE__MAX ) - 1 ;
if ( is_busy ( reasonp , errp ) ) {
return - EBUSY ;
}
return add_blockers ( reasonp , errp , modes ) ;
}
void migrate_del_blocker ( Error * * reasonp )
{
if ( * reasonp ) {
migration_blockers = g_slist_remove ( migration_blockers , * reasonp ) ;
for ( MigMode mode = 0 ; mode < MIG_MODE__MAX ; mode + + ) {
migration_blockers [ mode ] = g_slist_remove ( migration_blockers [ mode ] ,
* reasonp ) ;
}
error_free ( * reasonp ) ;
* reasonp = NULL ;
}
@ -1634,12 +1701,14 @@ void qmp_migrate_pause(Error **errp)
bool migration_is_blocked ( Error * * errp )
{
GSList * blockers = migration_blockers [ migrate_mode ( ) ] ;
if ( qemu_savevm_state_blocked ( errp ) ) {
return true ;
}
if ( migration_ blockers) {
error_propagate ( errp , error_copy ( migration_ blockers- > data ) ) ;
if ( blockers ) {
error_propagate ( errp , error_copy ( blockers - > data ) ) ;
return true ;
}