From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53008) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xa6yt-0001Cn-B9 for qemu-devel@nongnu.org; Fri, 03 Oct 2014 13:49:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Xa6yn-0001ao-55 for qemu-devel@nongnu.org; Fri, 03 Oct 2014 13:49:27 -0400 Received: from mx1.redhat.com ([209.132.183.28]:44979) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xa6ym-0001aj-Uk for qemu-devel@nongnu.org; Fri, 03 Oct 2014 13:49:21 -0400 From: "Dr. David Alan Gilbert (git)" Date: Fri, 3 Oct 2014 18:47:37 +0100 Message-Id: <1412358473-31398-32-git-send-email-dgilbert@redhat.com> In-Reply-To: <1412358473-31398-1-git-send-email-dgilbert@redhat.com> References: <1412358473-31398-1-git-send-email-dgilbert@redhat.com> Subject: [Qemu-devel] [PATCH v4 31/47] postcopy: Incoming initialisation 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, lilei@linux.vnet.ibm.com, quintela@redhat.com, cristian.klein@cs.umu.se, amit.shah@redhat.com, yanghy@cn.fujitsu.com From: "Dr. David Alan Gilbert" Signed-off-by: Dr. David Alan Gilbert --- arch_init.c | 11 ++++ include/migration/migration.h | 1 + include/migration/postcopy-ram.h | 12 +++++ migration.c | 1 + postcopy-ram.c | 110 ++++++++++++++++++++++++++++++++++++++- savevm.c | 4 ++ 6 files changed, 138 insertions(+), 1 deletion(-) diff --git a/arch_init.c b/arch_init.c index 030d189..4a03171 100644 --- a/arch_init.c +++ b/arch_init.c @@ -1345,6 +1345,17 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size) } } +/* + * Allocate data structures etc needed by incoming migration with postcopy-ram + * postcopy-ram's similarly names postcopy_ram_incoming_init does the work + */ +int ram_postcopy_incoming_init(MigrationIncomingState *mis) +{ + size_t ram_pages = last_ram_offset() >> TARGET_PAGE_BITS; + + return postcopy_ram_incoming_init(mis, ram_pages); +} + static int ram_load(QEMUFile *f, void *opaque, int version_id) { ram_addr_t addr; diff --git a/include/migration/migration.h b/include/migration/migration.h index 73d338e..be63c89 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -203,6 +203,7 @@ int ram_postcopy_send_discard_bitmap(MigrationState *ms); /* For incoming postcopy discard */ int ram_discard_range(MigrationIncomingState *mis, const char *block_name, uint64_t start, uint64_t end); +int ram_postcopy_incoming_init(MigrationIncomingState *mis); /** * @migrate_add_blocker - prevent migration from proceeding diff --git a/include/migration/postcopy-ram.h b/include/migration/postcopy-ram.h index 2a39a03..8f237a2 100644 --- a/include/migration/postcopy-ram.h +++ b/include/migration/postcopy-ram.h @@ -19,6 +19,18 @@ int postcopy_ram_hosttest(void); /* + * Initialise postcopy-ram, setting the RAM to a state where we can go into + * postcopy later; must be called prior to any precopy. + * called from arch_init's similarly named ram_postcopy_incoming_init + */ +int postcopy_ram_incoming_init(MigrationIncomingState *mis, size_t ram_pages); + +/* + * At the end of a migration where postcopy_ram_incoming_init was called. + */ +int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis); + +/* * In 'advise' mode record that a page has been received. */ void postcopy_hook_early_receive(MigrationIncomingState *mis, diff --git a/migration.c b/migration.c index db860c9..63d70b6 100644 --- a/migration.c +++ b/migration.c @@ -99,6 +99,7 @@ MigrationIncomingState *migration_incoming_state_init(QEMUFile* f) void migration_incoming_state_destroy(void) { + postcopy_pmi_destroy(mis_current); g_free(mis_current); mis_current = NULL; } diff --git a/postcopy-ram.c b/postcopy-ram.c index 76f992f..8eccf26 100644 --- a/postcopy-ram.c +++ b/postcopy-ram.c @@ -104,7 +104,6 @@ struct PostcopyDiscardState { /* It's a pair of bitmaps (of the same structure as the migration bitmaps)*/ /* holding one bit per target-page, although all operations work on host */ /* pages. */ -__attribute__ (( unused )) /* Until later in patch series */ static void postcopy_pmi_init(MigrationIncomingState *mis, size_t ram_pages) { unsigned int tpb = qemu_target_page_bits(); @@ -388,6 +387,104 @@ int postcopy_ram_discard_range(MigrationIncomingState *mis, uint8_t *start, return 0; } +/* + * Setup an area of RAM so that it *can* be used for postcopy later; this + * must be done right at the start prior to pre-copy. + * opaque should be the MIS. + */ +static int init_area(const char *block_name, void *host_addr, + ram_addr_t offset, ram_addr_t length, void *opaque) +{ + MigrationIncomingState *mis = opaque; + + DPRINTF("init_area: %s: %p offset=%zx length=%zd(%zx)", + block_name, host_addr, offset, length, length); + /* + * We need the whole of RAM to be truly empty for postcopy, so things + * like ROMs and any data tables built during init must be zero'd + * - we're going to get the copy from the source anyway. + */ + if (postcopy_ram_discard_range(mis, host_addr, (host_addr + length - 1))) { + return -1; + } + + /* + * We also need the area to be normal 4k pages, not huge pages + * (otherwise we can't be sure we can use remap_anon_pages to put + * a 4k page in later). THP might come along and map a 2MB page + * and when it's partially accessed in precopy it might not break + * it down, but leave a 2MB zero'd page. + */ + if (madvise(host_addr, length, MADV_NOHUGEPAGE)) { + perror("init_area: NOHUGEPAGE"); + return -1; + } + + return 0; +} + +/* + * At the end of migration, undo the effects of init_area + * opaque should be the MIS. + */ +static int cleanup_area(const char *block_name, void *host_addr, + ram_addr_t offset, ram_addr_t length, void *opaque) +{ + /* Turn off userfault here as well? */ + + DPRINTF("cleanup_area: %s: %p offset=%zx length=%zd(%zx)", + block_name, host_addr, offset, length, length); + /* + * We turned off hugepage for the precopy stage with postcopy enabled + * we can turn it back on now. + */ + if (madvise(host_addr, length, MADV_HUGEPAGE)) { + perror("init_area: HUGEPAGE"); + return -1; + } + + /* + * We can also turn off userfault now since we should have all the + * pages. It can be useful to leave it on to debug postcopy + * if you're not sure it's always getting every page. + */ + if (madvise(host_addr, length, MADV_NOUSERFAULT)) { + perror("init_area: NOUSERFAULT"); + return -1; + } + + return 0; +} + +/* + * Initialise postcopy-ram, setting the RAM to a state where we can go into + * postcopy later; must be called prior to any precopy. + * called from arch_init's similarly named ram_postcopy_incoming_init + */ +int postcopy_ram_incoming_init(MigrationIncomingState *mis, size_t ram_pages) +{ + postcopy_pmi_init(mis, ram_pages); + + if (qemu_ram_foreach_block(init_area, mis)) { + return -1; + } + + return 0; +} + +/* + * At the end of a migration where postcopy_ram_incoming_init was called. + */ +int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis) +{ + /* TODO: Join the fault thread once we're sure it will exit */ + if (qemu_ram_foreach_block(cleanup_area, mis)) { + return -1; + } + + return 0; +} + #else /* No target OS support, stubs just fail */ @@ -404,6 +501,17 @@ void postcopy_hook_early_receive(MigrationIncomingState *mis, /* We don't support postcopy so don't care */ } +int postcopy_ram_incoming_init(MigrationIncomingState *mis, size_t ram_pages) +{ + error_report("postcopy_ram_incoming_init: No OS support"); + return -1; +} + +int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis) +{ + assert(0); +} + void postcopy_pmi_destroy(MigrationIncomingState *mis) { /* Called in normal cleanup path - so it's OK */ diff --git a/savevm.c b/savevm.c index 7f9e0b2..54bdb26 100644 --- a/savevm.c +++ b/savevm.c @@ -1166,6 +1166,10 @@ static int loadvm_postcopy_ram_handle_advise(MigrationIncomingState *mis, return -1; } + if (ram_postcopy_incoming_init(mis)) { + return -1; + } + mis->postcopy_ram_state = POSTCOPY_RAM_INCOMING_ADVISE; /* -- 1.9.3