Page request: Process incoming page request
On receiving MIG_RPCOMM_REQ_PAGES look up the address and queue the page. Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Reviewed-by: Amit Shah <amit.shah@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com>
This commit is contained in:
		
							parent
							
								
									1e2d90ebc5
								
							
						
					
					
						commit
						6c595cdee1
					
				@ -105,6 +105,18 @@ MigrationIncomingState *migration_incoming_get_current(void);
 | 
				
			|||||||
MigrationIncomingState *migration_incoming_state_new(QEMUFile *f);
 | 
					MigrationIncomingState *migration_incoming_state_new(QEMUFile *f);
 | 
				
			||||||
void migration_incoming_state_destroy(void);
 | 
					void migration_incoming_state_destroy(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * An outstanding page request, on the source, having been received
 | 
				
			||||||
 | 
					 * and queued
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct MigrationSrcPageRequest {
 | 
				
			||||||
 | 
					    RAMBlock *rb;
 | 
				
			||||||
 | 
					    hwaddr    offset;
 | 
				
			||||||
 | 
					    hwaddr    len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QSIMPLEQ_ENTRY(MigrationSrcPageRequest) next_req;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct MigrationState
 | 
					struct MigrationState
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int64_t bandwidth_limit;
 | 
					    int64_t bandwidth_limit;
 | 
				
			||||||
@ -141,6 +153,12 @@ struct MigrationState
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* Flag set once the migration thread is running (and needs joining) */
 | 
					    /* Flag set once the migration thread is running (and needs joining) */
 | 
				
			||||||
    bool migration_thread_running;
 | 
					    bool migration_thread_running;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Queue of outstanding page requests from the destination */
 | 
				
			||||||
 | 
					    QemuMutex src_page_req_mutex;
 | 
				
			||||||
 | 
					    QSIMPLEQ_HEAD(src_page_requests, MigrationSrcPageRequest) src_page_requests;
 | 
				
			||||||
 | 
					    /* The RAMBlock used in the last src_page_request */
 | 
				
			||||||
 | 
					    RAMBlock *last_req_rb;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void process_incoming_migration(QEMUFile *f);
 | 
					void process_incoming_migration(QEMUFile *f);
 | 
				
			||||||
@ -288,6 +306,10 @@ void savevm_skip_configuration(void);
 | 
				
			|||||||
int global_state_store(void);
 | 
					int global_state_store(void);
 | 
				
			||||||
void global_state_store_running(void);
 | 
					void global_state_store_running(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void flush_page_queue(MigrationState *ms);
 | 
				
			||||||
 | 
					int ram_save_queue_pages(MigrationState *ms, const char *rbname,
 | 
				
			||||||
 | 
					                         ram_addr_t start, ram_addr_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PostcopyState postcopy_state_get(void);
 | 
					PostcopyState postcopy_state_get(void);
 | 
				
			||||||
/* Set the state and return the old state */
 | 
					/* Set the state and return the old state */
 | 
				
			||||||
PostcopyState postcopy_state_set(PostcopyState new_state);
 | 
					PostcopyState postcopy_state_set(PostcopyState new_state);
 | 
				
			||||||
 | 
				
			|||||||
@ -21,6 +21,7 @@
 | 
				
			|||||||
#include "sysemu/sysemu.h"
 | 
					#include "sysemu/sysemu.h"
 | 
				
			||||||
#include "block/block.h"
 | 
					#include "block/block.h"
 | 
				
			||||||
#include "qapi/qmp/qerror.h"
 | 
					#include "qapi/qmp/qerror.h"
 | 
				
			||||||
 | 
					#include "qapi/util.h"
 | 
				
			||||||
#include "qemu/sockets.h"
 | 
					#include "qemu/sockets.h"
 | 
				
			||||||
#include "qemu/rcu.h"
 | 
					#include "qemu/rcu.h"
 | 
				
			||||||
#include "migration/block.h"
 | 
					#include "migration/block.h"
 | 
				
			||||||
@ -28,9 +29,10 @@
 | 
				
			|||||||
#include "qemu/thread.h"
 | 
					#include "qemu/thread.h"
 | 
				
			||||||
#include "qmp-commands.h"
 | 
					#include "qmp-commands.h"
 | 
				
			||||||
#include "trace.h"
 | 
					#include "trace.h"
 | 
				
			||||||
#include "qapi/util.h"
 | 
					 | 
				
			||||||
#include "qapi-event.h"
 | 
					#include "qapi-event.h"
 | 
				
			||||||
#include "qom/cpu.h"
 | 
					#include "qom/cpu.h"
 | 
				
			||||||
 | 
					#include "exec/memory.h"
 | 
				
			||||||
 | 
					#include "exec/address-spaces.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_THROTTLE  (32 << 20)      /* Migration transfer speed throttling */
 | 
					#define MAX_THROTTLE  (32 << 20)      /* Migration transfer speed throttling */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -72,6 +74,7 @@ static PostcopyState incoming_postcopy_state;
 | 
				
			|||||||
/* For outgoing */
 | 
					/* For outgoing */
 | 
				
			||||||
MigrationState *migrate_get_current(void)
 | 
					MigrationState *migrate_get_current(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    static bool once;
 | 
				
			||||||
    static MigrationState current_migration = {
 | 
					    static MigrationState current_migration = {
 | 
				
			||||||
        .state = MIGRATION_STATUS_NONE,
 | 
					        .state = MIGRATION_STATUS_NONE,
 | 
				
			||||||
        .bandwidth_limit = MAX_THROTTLE,
 | 
					        .bandwidth_limit = MAX_THROTTLE,
 | 
				
			||||||
@ -89,6 +92,10 @@ MigrationState *migrate_get_current(void)
 | 
				
			|||||||
                DEFAULT_MIGRATE_X_CPU_THROTTLE_INCREMENT,
 | 
					                DEFAULT_MIGRATE_X_CPU_THROTTLE_INCREMENT,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!once) {
 | 
				
			||||||
 | 
					        qemu_mutex_init(¤t_migration.src_page_req_mutex);
 | 
				
			||||||
 | 
					        once = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return ¤t_migration;
 | 
					    return ¤t_migration;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -771,6 +778,8 @@ static void migrate_fd_cleanup(void *opaque)
 | 
				
			|||||||
    qemu_bh_delete(s->cleanup_bh);
 | 
					    qemu_bh_delete(s->cleanup_bh);
 | 
				
			||||||
    s->cleanup_bh = NULL;
 | 
					    s->cleanup_bh = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flush_page_queue(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->file) {
 | 
					    if (s->file) {
 | 
				
			||||||
        trace_migrate_fd_cleanup();
 | 
					        trace_migrate_fd_cleanup();
 | 
				
			||||||
        qemu_mutex_unlock_iothread();
 | 
					        qemu_mutex_unlock_iothread();
 | 
				
			||||||
@ -903,6 +912,8 @@ MigrationState *migrate_init(const MigrationParams *params)
 | 
				
			|||||||
    s->bandwidth_limit = bandwidth_limit;
 | 
					    s->bandwidth_limit = bandwidth_limit;
 | 
				
			||||||
    migrate_set_state(s, MIGRATION_STATUS_NONE, MIGRATION_STATUS_SETUP);
 | 
					    migrate_set_state(s, MIGRATION_STATUS_NONE, MIGRATION_STATUS_SETUP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QSIMPLEQ_INIT(&s->src_page_requests);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 | 
					    s->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 | 
				
			||||||
    return s;
 | 
					    return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1193,7 +1204,25 @@ static struct rp_cmd_args {
 | 
				
			|||||||
static void migrate_handle_rp_req_pages(MigrationState *ms, const char* rbname,
 | 
					static void migrate_handle_rp_req_pages(MigrationState *ms, const char* rbname,
 | 
				
			||||||
                                       ram_addr_t start, size_t len)
 | 
					                                       ram_addr_t start, size_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    long our_host_ps = getpagesize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    trace_migrate_handle_rp_req_pages(rbname, start, len);
 | 
					    trace_migrate_handle_rp_req_pages(rbname, start, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Since we currently insist on matching page sizes, just sanity check
 | 
				
			||||||
 | 
					     * we're being asked for whole host pages.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (start & (our_host_ps-1) ||
 | 
				
			||||||
 | 
					       (len & (our_host_ps-1))) {
 | 
				
			||||||
 | 
					        error_report("%s: Misaligned page request, start: " RAM_ADDR_FMT
 | 
				
			||||||
 | 
					                     " len: %zd", __func__, start, len);
 | 
				
			||||||
 | 
					        mark_source_rp_bad(ms);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ram_save_queue_pages(ms, rbname, start, len)) {
 | 
				
			||||||
 | 
					        mark_source_rp_bad(ms);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
				
			|||||||
@ -1015,6 +1015,91 @@ static bool find_dirty_block(QEMUFile *f, PageSearchStatus *pss,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * flush_page_queue: Flush any remaining pages in the ram request queue
 | 
				
			||||||
 | 
					 *    it should be empty at the end anyway, but in error cases there may be
 | 
				
			||||||
 | 
					 *    some left.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * ms: MigrationState
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void flush_page_queue(MigrationState *ms)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct MigrationSrcPageRequest *mspr, *next_mspr;
 | 
				
			||||||
 | 
					    /* This queue generally should be empty - but in the case of a failed
 | 
				
			||||||
 | 
					     * migration might have some droppings in.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    rcu_read_lock();
 | 
				
			||||||
 | 
					    QSIMPLEQ_FOREACH_SAFE(mspr, &ms->src_page_requests, next_req, next_mspr) {
 | 
				
			||||||
 | 
					        memory_region_unref(mspr->rb->mr);
 | 
				
			||||||
 | 
					        QSIMPLEQ_REMOVE_HEAD(&ms->src_page_requests, next_req);
 | 
				
			||||||
 | 
					        g_free(mspr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    rcu_read_unlock();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Queue the pages for transmission, e.g. a request from postcopy destination
 | 
				
			||||||
 | 
					 *   ms: MigrationStatus in which the queue is held
 | 
				
			||||||
 | 
					 *   rbname: The RAMBlock the request is for - may be NULL (to mean reuse last)
 | 
				
			||||||
 | 
					 *   start: Offset from the start of the RAMBlock
 | 
				
			||||||
 | 
					 *   len: Length (in bytes) to send
 | 
				
			||||||
 | 
					 *   Return: 0 on success
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int ram_save_queue_pages(MigrationState *ms, const char *rbname,
 | 
				
			||||||
 | 
					                         ram_addr_t start, ram_addr_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    RAMBlock *ramblock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rcu_read_lock();
 | 
				
			||||||
 | 
					    if (!rbname) {
 | 
				
			||||||
 | 
					        /* Reuse last RAMBlock */
 | 
				
			||||||
 | 
					        ramblock = ms->last_req_rb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!ramblock) {
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					             * Shouldn't happen, we can't reuse the last RAMBlock if
 | 
				
			||||||
 | 
					             * it's the 1st request.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            error_report("ram_save_queue_pages no previous block");
 | 
				
			||||||
 | 
					            goto err;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        ramblock = qemu_ram_block_by_name(rbname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!ramblock) {
 | 
				
			||||||
 | 
					            /* We shouldn't be asked for a non-existent RAMBlock */
 | 
				
			||||||
 | 
					            error_report("ram_save_queue_pages no block '%s'", rbname);
 | 
				
			||||||
 | 
					            goto err;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ms->last_req_rb = ramblock;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    trace_ram_save_queue_pages(ramblock->idstr, start, len);
 | 
				
			||||||
 | 
					    if (start+len > ramblock->used_length) {
 | 
				
			||||||
 | 
					        error_report("%s request overrun start=%zx len=%zx blocklen=%zx",
 | 
				
			||||||
 | 
					                     __func__, start, len, ramblock->used_length);
 | 
				
			||||||
 | 
					        goto err;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct MigrationSrcPageRequest *new_entry =
 | 
				
			||||||
 | 
					        g_malloc0(sizeof(struct MigrationSrcPageRequest));
 | 
				
			||||||
 | 
					    new_entry->rb = ramblock;
 | 
				
			||||||
 | 
					    new_entry->offset = start;
 | 
				
			||||||
 | 
					    new_entry->len = len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memory_region_ref(ramblock->mr);
 | 
				
			||||||
 | 
					    qemu_mutex_lock(&ms->src_page_req_mutex);
 | 
				
			||||||
 | 
					    QSIMPLEQ_INSERT_TAIL(&ms->src_page_requests, new_entry, next_req);
 | 
				
			||||||
 | 
					    qemu_mutex_unlock(&ms->src_page_req_mutex);
 | 
				
			||||||
 | 
					    rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
					    rcu_read_unlock();
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * ram_find_and_save_block: Finds a dirty page and sends it to f
 | 
					 * ram_find_and_save_block: Finds a dirty page and sends it to f
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
				
			|||||||
@ -1256,6 +1256,7 @@ migration_bitmap_sync_start(void) ""
 | 
				
			|||||||
migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64""
 | 
					migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64""
 | 
				
			||||||
migration_throttle(void) ""
 | 
					migration_throttle(void) ""
 | 
				
			||||||
ram_postcopy_send_discard_bitmap(void) ""
 | 
					ram_postcopy_send_discard_bitmap(void) ""
 | 
				
			||||||
 | 
					ram_save_queue_pages(const char *rbname, size_t start, size_t len) "%s: start: %zx len: %zx"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# hw/display/qxl.c
 | 
					# hw/display/qxl.c
 | 
				
			||||||
disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d"
 | 
					disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user