summaryrefslogtreecommitdiffstats
path: root/migration/ram.c
diff options
context:
space:
mode:
Diffstat (limited to 'migration/ram.c')
-rw-r--r--migration/ram.c64
1 files changed, 35 insertions, 29 deletions
diff --git a/migration/ram.c b/migration/ram.c
index 781f0745dc..170e522a1f 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -3185,12 +3185,14 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
*
* Returns a pointer from within the RCU-protected ram_list.
*
+ * @mis: the migration incoming state pointer
* @f: QEMUFile where to read the data from
* @flags: Page flags (mostly to see if it's a continuation of previous block)
*/
-static inline RAMBlock *ram_block_from_stream(QEMUFile *f, int flags)
+static inline RAMBlock *ram_block_from_stream(MigrationIncomingState *mis,
+ QEMUFile *f, int flags)
{
- static RAMBlock *block;
+ RAMBlock *block = mis->last_recv_block;
char id[256];
uint8_t len;
@@ -3217,6 +3219,8 @@ static inline RAMBlock *ram_block_from_stream(QEMUFile *f, int flags)
return NULL;
}
+ mis->last_recv_block = block;
+
return block;
}
@@ -3641,11 +3645,8 @@ static int ram_load_postcopy(QEMUFile *f)
bool place_needed = false;
bool matches_target_page_size = false;
MigrationIncomingState *mis = migration_incoming_get_current();
- /* Temporary page that is later 'placed' */
- void *postcopy_host_page = mis->postcopy_tmp_page;
- void *host_page = NULL;
- bool all_zero = true;
- int target_pages = 0;
+ /* Currently we only use channel 0. TODO: use all the channels */
+ PostcopyTmpPage *tmp_page = &mis->postcopy_tmp_pages[0];
while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) {
ram_addr_t addr;
@@ -3672,7 +3673,7 @@ static int ram_load_postcopy(QEMUFile *f)
trace_ram_load_postcopy_loop((uint64_t)addr, flags);
if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE |
RAM_SAVE_FLAG_COMPRESS_PAGE)) {
- block = ram_block_from_stream(f, flags);
+ block = ram_block_from_stream(mis, f, flags);
if (!block) {
ret = -EINVAL;
break;
@@ -3689,7 +3690,7 @@ static int ram_load_postcopy(QEMUFile *f)
ret = -EINVAL;
break;
}
- target_pages++;
+ tmp_page->target_pages++;
matches_target_page_size = block->page_size == TARGET_PAGE_SIZE;
/*
* Postcopy requires that we place whole host pages atomically;
@@ -3701,16 +3702,21 @@ static int ram_load_postcopy(QEMUFile *f)
* however the source ensures it always sends all the components
* of a host page in one chunk.
*/
- page_buffer = postcopy_host_page +
+ page_buffer = tmp_page->tmp_huge_page +
host_page_offset_from_ram_block_offset(block, addr);
/* If all TP are zero then we can optimise the place */
- if (target_pages == 1) {
- host_page = host_page_from_ram_block_offset(block, addr);
- } else if (host_page != host_page_from_ram_block_offset(block,
- addr)) {
+ if (tmp_page->target_pages == 1) {
+ tmp_page->host_addr =
+ host_page_from_ram_block_offset(block, addr);
+ } else if (tmp_page->host_addr !=
+ host_page_from_ram_block_offset(block, addr)) {
/* not the 1st TP within the HP */
- error_report("Non-same host page %p/%p", host_page,
- host_page_from_ram_block_offset(block, addr));
+ error_report("Non-same host page detected. "
+ "Target host page %p, received host page %p "
+ "(rb %s offset 0x"RAM_ADDR_FMT" target_pages %d)",
+ tmp_page->host_addr,
+ host_page_from_ram_block_offset(block, addr),
+ block->idstr, addr, tmp_page->target_pages);
ret = -EINVAL;
break;
}
@@ -3719,10 +3725,11 @@ static int ram_load_postcopy(QEMUFile *f)
* If it's the last part of a host page then we place the host
* page
*/
- if (target_pages == (block->page_size / TARGET_PAGE_SIZE)) {
+ if (tmp_page->target_pages ==
+ (block->page_size / TARGET_PAGE_SIZE)) {
place_needed = true;
}
- place_source = postcopy_host_page;
+ place_source = tmp_page->tmp_huge_page;
}
switch (flags & ~RAM_SAVE_FLAG_CONTINUE) {
@@ -3736,12 +3743,12 @@ static int ram_load_postcopy(QEMUFile *f)
memset(page_buffer, ch, TARGET_PAGE_SIZE);
}
if (ch) {
- all_zero = false;
+ tmp_page->all_zero = false;
}
break;
case RAM_SAVE_FLAG_PAGE:
- all_zero = false;
+ tmp_page->all_zero = false;
if (!matches_target_page_size) {
/* For huge pages, we always use temporary buffer */
qemu_get_buffer(f, page_buffer, TARGET_PAGE_SIZE);
@@ -3759,7 +3766,7 @@ static int ram_load_postcopy(QEMUFile *f)
}
break;
case RAM_SAVE_FLAG_COMPRESS_PAGE:
- all_zero = false;
+ tmp_page->all_zero = false;
len = qemu_get_be32(f);
if (len < 0 || len > compressBound(TARGET_PAGE_SIZE)) {
error_report("Invalid compressed data length: %d", len);
@@ -3791,16 +3798,14 @@ static int ram_load_postcopy(QEMUFile *f)
}
if (!ret && place_needed) {
- if (all_zero) {
- ret = postcopy_place_page_zero(mis, host_page, block);
+ if (tmp_page->all_zero) {
+ ret = postcopy_place_page_zero(mis, tmp_page->host_addr, block);
} else {
- ret = postcopy_place_page(mis, host_page, place_source,
- block);
+ ret = postcopy_place_page(mis, tmp_page->host_addr,
+ place_source, block);
}
place_needed = false;
- target_pages = 0;
- /* Assume we have a zero page until we detect something different */
- all_zero = true;
+ postcopy_temp_page_reset(tmp_page);
}
}
@@ -3880,6 +3885,7 @@ void colo_flush_ram_cache(void)
*/
static int ram_load_precopy(QEMUFile *f)
{
+ MigrationIncomingState *mis = migration_incoming_get_current();
int flags = 0, ret = 0, invalid_flags = 0, len = 0, i = 0;
/* ADVISE is earlier, it shows the source has the postcopy capability on */
bool postcopy_advised = postcopy_is_advised();
@@ -3918,7 +3924,7 @@ static int ram_load_precopy(QEMUFile *f)
if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE |
RAM_SAVE_FLAG_COMPRESS_PAGE | RAM_SAVE_FLAG_XBZRLE)) {
- RAMBlock *block = ram_block_from_stream(f, flags);
+ RAMBlock *block = ram_block_from_stream(mis, f, flags);
host = host_from_ram_block_offset(block, addr);
/*