Skip to content

Commit

Permalink
Page request: Process incoming page request
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
dagrh authored and Juan Quintela committed Nov 10, 2015
1 parent 1e2d90e commit 6c595cd
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 1 deletion.
22 changes: 22 additions & 0 deletions include/migration/migration.h
Expand Up @@ -105,6 +105,18 @@ MigrationIncomingState *migration_incoming_get_current(void);
MigrationIncomingState *migration_incoming_state_new(QEMUFile *f);
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
{
int64_t bandwidth_limit;
Expand Down Expand Up @@ -141,6 +153,12 @@ struct MigrationState

/* Flag set once the migration thread is running (and needs joining) */
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);
Expand Down Expand Up @@ -288,6 +306,10 @@ void savevm_skip_configuration(void);
int global_state_store(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);
/* Set the state and return the old state */
PostcopyState postcopy_state_set(PostcopyState new_state);
Expand Down
31 changes: 30 additions & 1 deletion migration/migration.c
Expand Up @@ -21,16 +21,18 @@
#include "sysemu/sysemu.h"
#include "block/block.h"
#include "qapi/qmp/qerror.h"
#include "qapi/util.h"
#include "qemu/sockets.h"
#include "qemu/rcu.h"
#include "migration/block.h"
#include "migration/postcopy-ram.h"
#include "qemu/thread.h"
#include "qmp-commands.h"
#include "trace.h"
#include "qapi/util.h"
#include "qapi-event.h"
#include "qom/cpu.h"
#include "exec/memory.h"
#include "exec/address-spaces.h"

#define MAX_THROTTLE (32 << 20) /* Migration transfer speed throttling */

Expand Down Expand Up @@ -72,6 +74,7 @@ static PostcopyState incoming_postcopy_state;
/* For outgoing */
MigrationState *migrate_get_current(void)
{
static bool once;
static MigrationState current_migration = {
.state = MIGRATION_STATUS_NONE,
.bandwidth_limit = MAX_THROTTLE,
Expand All @@ -89,6 +92,10 @@ MigrationState *migrate_get_current(void)
DEFAULT_MIGRATE_X_CPU_THROTTLE_INCREMENT,
};

if (!once) {
qemu_mutex_init(&current_migration.src_page_req_mutex);
once = true;
}
return &current_migration;
}

Expand Down Expand Up @@ -771,6 +778,8 @@ static void migrate_fd_cleanup(void *opaque)
qemu_bh_delete(s->cleanup_bh);
s->cleanup_bh = NULL;

flush_page_queue(s);

if (s->file) {
trace_migrate_fd_cleanup();
qemu_mutex_unlock_iothread();
Expand Down Expand Up @@ -903,6 +912,8 @@ MigrationState *migrate_init(const MigrationParams *params)
s->bandwidth_limit = bandwidth_limit;
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);
return s;
}
Expand Down Expand Up @@ -1193,7 +1204,25 @@ static struct rp_cmd_args {
static void migrate_handle_rp_req_pages(MigrationState *ms, const char* rbname,
ram_addr_t start, size_t len)
{
long our_host_ps = getpagesize();

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);
}
}

/*
Expand Down
85 changes: 85 additions & 0 deletions migration/ram.c
Expand Up @@ -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
*
Expand Down
1 change: 1 addition & 0 deletions trace-events
Expand Up @@ -1256,6 +1256,7 @@ migration_bitmap_sync_start(void) ""
migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64""
migration_throttle(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
disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d"
Expand Down

0 comments on commit 6c595cd

Please sign in to comment.