From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50275) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yi4HT-0007K6-Sp for qemu-devel@nongnu.org; Tue, 14 Apr 2015 13:05:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Yi4HR-0002zN-KD for qemu-devel@nongnu.org; Tue, 14 Apr 2015 13:05:47 -0400 Received: from mx1.redhat.com ([209.132.183.28]:44250) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yi4HR-0002z7-BL for qemu-devel@nongnu.org; Tue, 14 Apr 2015 13:05:45 -0400 From: "Dr. David Alan Gilbert (git)" Date: Tue, 14 Apr 2015 18:04:01 +0100 Message-Id: <1429031053-4454-36-git-send-email-dgilbert@redhat.com> In-Reply-To: <1429031053-4454-1-git-send-email-dgilbert@redhat.com> References: <1429031053-4454-1-git-send-email-dgilbert@redhat.com> Subject: [Qemu-devel] [PATCH v6 35/47] Page request: Process incoming page request List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: aarcange@redhat.com, yamahata@private.email.ne.jp, quintela@redhat.com, amit.shah@redhat.com, pbonzini@redhat.com, david@gibson.dropbear.id.au, yayanghy@cn.fujitsu.com From: "Dr. David Alan Gilbert" On receiving MIG_RPCOMM_REQ_PAGES look up the address and queue the page. Signed-off-by: Dr. David Alan Gilbert --- arch_init.c | 64 ++++++++++++++++++++++++++++++++++++++++++- include/exec/cpu-all.h | 2 -- include/migration/migration.h | 21 ++++++++++++++ include/qemu/typedefs.h | 1 + migration/migration.c | 31 +++++++++++++++++++++ trace-events | 1 + 6 files changed, 117 insertions(+), 3 deletions(-) diff --git a/arch_init.c b/arch_init.c index 2c937d1..48403f3 100644 --- a/arch_init.c +++ b/arch_init.c @@ -715,7 +715,69 @@ static int ram_save_page(QEMUFile *f, RAMBlock* block, ram_addr_t offset, return pages; } -/** +/* + * 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 = ram_find_block(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; + } + } + 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; + ms->last_req_rb = ramblock; + + qemu_mutex_lock(&ms->src_page_req_mutex); + memory_region_ref(ramblock->mr); + 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 * * Called within an RCU critical section. diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index ac06c67..1f336e6 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -266,8 +266,6 @@ CPUArchState *cpu_copy(CPUArchState *env); /* memory API */ -typedef struct RAMBlock RAMBlock; - struct RAMBlock { struct rcu_head rcu; struct MemoryRegion *mr; diff --git a/include/migration/migration.h b/include/migration/migration.h index 37bd54a..75c3299 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -88,6 +88,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; @@ -130,6 +142,12 @@ struct MigrationState * of the postcopy phase */ unsigned long *sentmap; + + /* 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); @@ -259,6 +277,9 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, ram_addr_t offset, size_t size, uint64_t *bytes_sent); +int ram_save_queue_pages(MigrationState *ms, const char *rbname, + ram_addr_t start, ram_addr_t len); + PostcopyState postcopy_state_get(MigrationIncomingState *mis); /* Set the state and return the old state */ diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 5f130fe..61b5b46 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -72,6 +72,7 @@ typedef struct QEMUSGList QEMUSGList; typedef struct QEMUSizedBuffer QEMUSizedBuffer; typedef struct QEMUTimerListGroup QEMUTimerListGroup; typedef struct QEMUTimer QEMUTimer; +typedef struct RAMBlock RAMBlock; typedef struct Range Range; typedef struct SerialState SerialState; typedef struct SHPCDevice SHPCDevice; diff --git a/migration/migration.c b/migration/migration.c index 41f377c..2509798 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -26,6 +26,8 @@ #include "qemu/thread.h" #include "qmp-commands.h" #include "trace.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" #define MAX_THROTTLE (32 << 20) /* Migration speed throttling */ @@ -496,6 +498,15 @@ static void migrate_fd_cleanup(void *opaque) migrate_fd_cleanup_src_rp(s); + /* This queue generally should be empty - but in the case of a failed + * migration might have some droppings in. + */ + struct MigrationSrcPageRequest *mspr, *next_mspr; + QSIMPLEQ_FOREACH_SAFE(mspr, &s->src_page_requests, next_req, next_mspr) { + QSIMPLEQ_REMOVE_HEAD(&s->src_page_requests, next_req); + g_free(mspr); + } + if (s->file) { trace_migrate_fd_cleanup(); qemu_mutex_unlock_iothread(); @@ -614,6 +625,9 @@ MigrationState *migrate_init(const MigrationParams *params) s->state = MIGRATION_STATUS_SETUP; trace_migrate_set_state(MIGRATION_STATUS_SETUP); + qemu_mutex_init(&s->src_page_req_mutex); + QSIMPLEQ_INIT(&s->src_page_requests); + s->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); return s; } @@ -842,6 +856,23 @@ static void migrate_handle_rp_req_pages(MigrationState *ms, const char* rbname, ram_addr_t start, ram_addr_t len) { trace_migrate_handle_rp_req_pages(rbname, start, len); + + /* Round everything up to our host page size */ + long our_host_ps = getpagesize(); + if (start & (our_host_ps-1)) { + long roundings = start & (our_host_ps-1); + start -= roundings; + len += roundings; + } + if (len & (our_host_ps-1)) { + long roundings = len & (our_host_ps-1); + len -= roundings; + len += our_host_ps; + } + + if (ram_save_queue_pages(ms, rbname, start, len)) { + source_return_path_bad(ms); + } } /* diff --git a/trace-events b/trace-events index 8379c1f..3792d2e 100644 --- a/trace-events +++ b/trace-events @@ -1220,6 +1220,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" -- 2.1.0