Message ID | 20200221164204.105570-8-david@redhat.com |
---|---|
State | New |
Headers | show |
Series | migrate/ram: Fix resizing RAM blocks while migrating | expand |
On Fri, Feb 21, 2020 at 05:41:58PM +0100, David Hildenbrand wrote: > In case we grow our RAM after ram_postcopy_incoming_init() (e.g., when > synchronizing the RAM block state with the migration source), the resized > part would not get discarded. Let's perform that when being notified > about a resize while postcopy has been advised, but is not listening > yet. With precopy, the process is as following: > > 1. VM created > - RAM blocks are created > 2. Incomming migration started > - Postcopy is advised > - All pages in RAM blocks are discarded > 3. Precopy starts > - RAM blocks are resized to match the size on the migration source. > - RAM pages from precopy stream are loaded > - Uffd handler is registered, postcopy starts listening > 3. Guest started, postcopy running > - Pagefaults get resolved, pages get placed > > Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com> > Cc: Juan Quintela <quintela@redhat.com> > Cc: Peter Xu <peterx@redhat.com> > Signed-off-by: David Hildenbrand <david@redhat.com> Reviewed-by: Peter Xu <peterx@redhat.com>
diff --git a/migration/ram.c b/migration/ram.c index 39c7d1c4a6..d5a4d69e1c 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3714,6 +3714,7 @@ static SaveVMHandlers savevm_ram_handlers = { static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host, size_t old_size, size_t new_size) { + PostcopyState ps = postcopy_state_get(); ram_addr_t offset; Error *err = NULL; RAMBlock *rb = qemu_ram_block_from_host(host, false, &offset); @@ -3734,6 +3735,35 @@ static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host, error_free(err); migration_cancel(); } + + switch (ps) { + case POSTCOPY_INCOMING_ADVISE: + /* + * Update what ram_postcopy_incoming_init()->init_range() does at the + * time postcopy was advised. Syncing RAM blocks with the source will + * result in RAM resizes. + */ + if (old_size < new_size) { + if (ram_discard_range(rb->idstr, old_size, new_size - old_size)) { + error_report("RAM block '%s' discard of resized RAM failed", + rb->idstr); + } + } + break; + case POSTCOPY_INCOMING_NONE: + case POSTCOPY_INCOMING_RUNNING: + case POSTCOPY_INCOMING_END: + /* + * Once our guest is running, postcopy does no longer care about + * resizes. When growing, the new memory was not available on the + * source, no handler needed. + */ + break; + default: + error_report("RAM block '%s' resized during postcopy state: %d", + rb->idstr, ps); + exit(-1); + } } static RAMBlockNotifier ram_mig_ram_notifier = {
In case we grow our RAM after ram_postcopy_incoming_init() (e.g., when synchronizing the RAM block state with the migration source), the resized part would not get discarded. Let's perform that when being notified about a resize while postcopy has been advised, but is not listening yet. With precopy, the process is as following: 1. VM created - RAM blocks are created 2. Incomming migration started - Postcopy is advised - All pages in RAM blocks are discarded 3. Precopy starts - RAM blocks are resized to match the size on the migration source. - RAM pages from precopy stream are loaded - Uffd handler is registered, postcopy starts listening 3. Guest started, postcopy running - Pagefaults get resolved, pages get placed Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com> Cc: Juan Quintela <quintela@redhat.com> Cc: Peter Xu <peterx@redhat.com> Signed-off-by: David Hildenbrand <david@redhat.com> --- migration/ram.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)