Add qemu_savevm_state_complete_postcopy
Add qemu_savevm_state_complete_postcopy to complement qemu_savevm_state_complete_precopy together with a new save_live_complete_postcopy method on devices. The save_live_complete_precopy method is called on all devices during a precopy migration, and all non-postcopy devices during a postcopy migration at the transition. The save_live_complete_postcopy method is called at the end of postcopy for all postcopiable devices. Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Reviewed-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com>
This commit is contained in:
		
							parent
							
								
									8421b205dd
								
							
						
					
					
						commit
						763c906b0e
					
				| 
						 | 
				
			
			@ -40,6 +40,7 @@ typedef struct SaveVMHandlers {
 | 
			
		|||
    SaveStateHandler *save_state;
 | 
			
		||||
 | 
			
		||||
    void (*cleanup)(void *opaque);
 | 
			
		||||
    int (*save_live_complete_postcopy)(QEMUFile *f, void *opaque);
 | 
			
		||||
    int (*save_live_complete_precopy)(QEMUFile *f, void *opaque);
 | 
			
		||||
 | 
			
		||||
    /* This runs both outside and inside the iothread lock.  */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -111,6 +111,7 @@ void qemu_savevm_state_begin(QEMUFile *f,
 | 
			
		|||
void qemu_savevm_state_header(QEMUFile *f);
 | 
			
		||||
int qemu_savevm_state_iterate(QEMUFile *f);
 | 
			
		||||
void qemu_savevm_state_cleanup(void);
 | 
			
		||||
void qemu_savevm_state_complete_postcopy(QEMUFile *f);
 | 
			
		||||
void qemu_savevm_state_complete_precopy(QEMUFile *f);
 | 
			
		||||
void qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size,
 | 
			
		||||
                               uint64_t *res_non_postcopiable,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1704,6 +1704,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
 | 
			
		|||
static SaveVMHandlers savevm_ram_handlers = {
 | 
			
		||||
    .save_live_setup = ram_save_setup,
 | 
			
		||||
    .save_live_iterate = ram_save_iterate,
 | 
			
		||||
    .save_live_complete_postcopy = ram_save_complete,
 | 
			
		||||
    .save_live_complete_precopy = ram_save_complete,
 | 
			
		||||
    .save_live_pending = ram_save_pending,
 | 
			
		||||
    .load_state = ram_load,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -978,19 +978,61 @@ static bool should_send_vmdesc(void)
 | 
			
		|||
    return !machine->suppress_vmdesc && !in_postcopy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Calls the save_live_complete_postcopy methods
 | 
			
		||||
 * causing the last few pages to be sent immediately and doing any associated
 | 
			
		||||
 * cleanup.
 | 
			
		||||
 * Note postcopy also calls qemu_savevm_state_complete_precopy to complete
 | 
			
		||||
 * all the other devices, but that happens at the point we switch to postcopy.
 | 
			
		||||
 */
 | 
			
		||||
void qemu_savevm_state_complete_postcopy(QEMUFile *f)
 | 
			
		||||
{
 | 
			
		||||
    SaveStateEntry *se;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
 | 
			
		||||
        if (!se->ops || !se->ops->save_live_complete_postcopy) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (se->ops && se->ops->is_active) {
 | 
			
		||||
            if (!se->ops->is_active(se->opaque)) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        trace_savevm_section_start(se->idstr, se->section_id);
 | 
			
		||||
        /* Section type */
 | 
			
		||||
        qemu_put_byte(f, QEMU_VM_SECTION_END);
 | 
			
		||||
        qemu_put_be32(f, se->section_id);
 | 
			
		||||
 | 
			
		||||
        ret = se->ops->save_live_complete_postcopy(f, se->opaque);
 | 
			
		||||
        trace_savevm_section_end(se->idstr, se->section_id, ret);
 | 
			
		||||
        save_section_footer(f, se);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            qemu_file_set_error(f, ret);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qemu_put_byte(f, QEMU_VM_EOF);
 | 
			
		||||
    qemu_fflush(f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qemu_savevm_state_complete_precopy(QEMUFile *f)
 | 
			
		||||
{
 | 
			
		||||
    QJSON *vmdesc;
 | 
			
		||||
    int vmdesc_len;
 | 
			
		||||
    SaveStateEntry *se;
 | 
			
		||||
    int ret;
 | 
			
		||||
    bool in_postcopy = migration_in_postcopy(migrate_get_current());
 | 
			
		||||
 | 
			
		||||
    trace_savevm_state_complete_precopy();
 | 
			
		||||
 | 
			
		||||
    cpu_synchronize_all_states();
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
 | 
			
		||||
        if (!se->ops || !se->ops->save_live_complete_precopy) {
 | 
			
		||||
        if (!se->ops ||
 | 
			
		||||
            (in_postcopy && se->ops->save_live_complete_postcopy) ||
 | 
			
		||||
            !se->ops->save_live_complete_precopy) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (se->ops && se->ops->is_active) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1039,7 +1081,10 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f)
 | 
			
		|||
        save_section_footer(f, se);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qemu_put_byte(f, QEMU_VM_EOF);
 | 
			
		||||
    if (!in_postcopy) {
 | 
			
		||||
        /* Postcopy stream will still be going */
 | 
			
		||||
        qemu_put_byte(f, QEMU_VM_EOF);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    json_end_array(vmdesc);
 | 
			
		||||
    qjson_finish(vmdesc);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue