mirror of https://github.com/xqemu/xqemu.git
postcopy: Transmit ram size summary word
Replace the host page-size in the 'advise' command by a pagesize summary bitmap; if the VM is just using normal RAM then this will be exactly the same as before, however if they're using huge pages they'll be different, and thus: a) Migration from/to old qemu's that don't understand huge pages will fail early. b) Migrations with different size RAMBlocks will also fail early. This catches it very early; earlier than the detailed per-block check in the next patch. Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Reviewed-by: Laurent Vivier <lvivier@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Message-Id: <20170224182844.32452-2-dgilbert@redhat.com> Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
This commit is contained in:
parent
f9c8caa04f
commit
e8ca1db29b
|
@ -378,6 +378,7 @@ void global_state_store_running(void);
|
||||||
void flush_page_queue(MigrationState *ms);
|
void flush_page_queue(MigrationState *ms);
|
||||||
int ram_save_queue_pages(MigrationState *ms, const char *rbname,
|
int ram_save_queue_pages(MigrationState *ms, const char *rbname,
|
||||||
ram_addr_t start, ram_addr_t len);
|
ram_addr_t start, ram_addr_t len);
|
||||||
|
uint64_t ram_pagesize_summary(void);
|
||||||
|
|
||||||
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 */
|
||||||
|
|
|
@ -600,6 +600,23 @@ static void migration_bitmap_sync_init(void)
|
||||||
iterations_prev = 0;
|
iterations_prev = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns a summary bitmap of the page sizes of all RAMBlocks;
|
||||||
|
* for VMs with just normal pages this is equivalent to the
|
||||||
|
* host page size. If it's got some huge pages then it's the OR
|
||||||
|
* of all the different page sizes.
|
||||||
|
*/
|
||||||
|
uint64_t ram_pagesize_summary(void)
|
||||||
|
{
|
||||||
|
RAMBlock *block;
|
||||||
|
uint64_t summary = 0;
|
||||||
|
|
||||||
|
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||||
|
summary |= block->page_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
|
||||||
static void migration_bitmap_sync(void)
|
static void migration_bitmap_sync(void)
|
||||||
{
|
{
|
||||||
RAMBlock *block;
|
RAMBlock *block;
|
||||||
|
|
|
@ -870,7 +870,7 @@ int qemu_savevm_send_packaged(QEMUFile *f, const uint8_t *buf, size_t len)
|
||||||
void qemu_savevm_send_postcopy_advise(QEMUFile *f)
|
void qemu_savevm_send_postcopy_advise(QEMUFile *f)
|
||||||
{
|
{
|
||||||
uint64_t tmp[2];
|
uint64_t tmp[2];
|
||||||
tmp[0] = cpu_to_be64(getpagesize());
|
tmp[0] = cpu_to_be64(ram_pagesize_summary());
|
||||||
tmp[1] = cpu_to_be64(1ul << qemu_target_page_bits());
|
tmp[1] = cpu_to_be64(1ul << qemu_target_page_bits());
|
||||||
|
|
||||||
trace_qemu_savevm_send_postcopy_advise();
|
trace_qemu_savevm_send_postcopy_advise();
|
||||||
|
@ -1352,7 +1352,7 @@ static int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis);
|
||||||
static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis)
|
static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis)
|
||||||
{
|
{
|
||||||
PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE);
|
PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE);
|
||||||
uint64_t remote_hps, remote_tps;
|
uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps;
|
||||||
|
|
||||||
trace_loadvm_postcopy_handle_advise();
|
trace_loadvm_postcopy_handle_advise();
|
||||||
if (ps != POSTCOPY_INCOMING_NONE) {
|
if (ps != POSTCOPY_INCOMING_NONE) {
|
||||||
|
@ -1365,17 +1365,27 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
remote_hps = qemu_get_be64(mis->from_src_file);
|
remote_pagesize_summary = qemu_get_be64(mis->from_src_file);
|
||||||
if (remote_hps != getpagesize()) {
|
local_pagesize_summary = ram_pagesize_summary();
|
||||||
|
|
||||||
|
if (remote_pagesize_summary != local_pagesize_summary) {
|
||||||
/*
|
/*
|
||||||
* Some combinations of mismatch are probably possible but it gets
|
* This detects two potential causes of mismatch:
|
||||||
* a bit more complicated. In particular we need to place whole
|
* a) A mismatch in host page sizes
|
||||||
* host pages on the dest at once, and we need to ensure that we
|
* Some combinations of mismatch are probably possible but it gets
|
||||||
* handle dirtying to make sure we never end up sending part of
|
* a bit more complicated. In particular we need to place whole
|
||||||
* a hostpage on it's own.
|
* host pages on the dest at once, and we need to ensure that we
|
||||||
|
* handle dirtying to make sure we never end up sending part of
|
||||||
|
* a hostpage on it's own.
|
||||||
|
* b) The use of different huge page sizes on source/destination
|
||||||
|
* a more fine grain test is performed during RAM block migration
|
||||||
|
* but this test here causes a nice early clear failure, and
|
||||||
|
* also fails when passed to an older qemu that doesn't
|
||||||
|
* do huge pages.
|
||||||
*/
|
*/
|
||||||
error_report("Postcopy needs matching host page sizes (s=%d d=%d)",
|
error_report("Postcopy needs matching RAM page sizes (s=%" PRIx64
|
||||||
(int)remote_hps, getpagesize());
|
" d=%" PRIx64 ")",
|
||||||
|
remote_pagesize_summary, local_pagesize_summary);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue