Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/dgilbert/tags/pull-migration-20…
Browse files Browse the repository at this point in the history
…210511a' into staging

Migration pull 2021-05-11

The largest change in this set is David's changes for ram block size
changing; then there's a pile of other cleanups and fixes.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

# gpg: Signature made Tue 11 May 2021 16:06:42 BST
# gpg:                using RSA key 45F5C71B4A0CB7FB977A9FA90516331EBC5BFDE7
# gpg: Good signature from "Dr. David Alan Gilbert (RH2) <dgilbert@redhat.com>" [full]
# Primary key fingerprint: 45F5 C71B 4A0C B7FB 977A  9FA9 0516 331E BC5B FDE7

* remotes/dgilbert/tags/pull-migration-20210511a:
  tests/migration: introduce multifd into guestperf
  tests/qtest/migration-test: Use g_autofree to avoid leaks on error paths
  tests/migration-test: Fix "true" vs true
  migration/ram: Use offset_in_ramblock() in range checks
  migration/multifd: Print used_length of memory block
  migration/ram: Handle RAM block resizes during postcopy
  migration/ram: Simplify host page handling in ram_load_postcopy()
  migration/ram: Discard RAM when growing RAM blocks after ram_postcopy_incoming_init()
  exec: Relax range check in ram_block_discard_range()
  migration/ram: Handle RAM block resizes during precopy
  numa: Make all callbacks of ram block notifiers optional
  numa: Teach ram block notifiers about resizeable ram blocks
  util: vfio-helpers: Factor out and fix processing of existing ram blocks
  migration: Drop redundant query-migrate result @Blocked
  migration/ram: Optimize ram_save_host_page()
  migration/ram: Reduce unnecessary rate limiting
  migrate/ram: remove "ram_bulk_stage" and "fpo_enabled"

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed May 12, 2021
2 parents 3e9f48b + 872df23 commit 07b0a39
Show file tree
Hide file tree
Showing 25 changed files with 367 additions and 250 deletions.
41 changes: 37 additions & 4 deletions hw/core/numa.c
Expand Up @@ -802,30 +802,63 @@ void query_numa_node_mem(NumaNodeMem node_mem[], MachineState *ms)
}
}

static int ram_block_notify_add_single(RAMBlock *rb, void *opaque)
{
const ram_addr_t max_size = qemu_ram_get_max_length(rb);
const ram_addr_t size = qemu_ram_get_used_length(rb);
void *host = qemu_ram_get_host_addr(rb);
RAMBlockNotifier *notifier = opaque;

if (host) {
notifier->ram_block_added(notifier, host, size, max_size);
}
return 0;
}

void ram_block_notifier_add(RAMBlockNotifier *n)
{
QLIST_INSERT_HEAD(&ram_list.ramblock_notifiers, n, next);

/* Notify about all existing ram blocks. */
if (n->ram_block_added) {
qemu_ram_foreach_block(ram_block_notify_add_single, n);
}
}

void ram_block_notifier_remove(RAMBlockNotifier *n)
{
QLIST_REMOVE(n, next);
}

void ram_block_notify_add(void *host, size_t size)
void ram_block_notify_add(void *host, size_t size, size_t max_size)
{
RAMBlockNotifier *notifier;

QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
if (notifier->ram_block_added) {
notifier->ram_block_added(notifier, host, size, max_size);
}
}
}

void ram_block_notify_remove(void *host, size_t size, size_t max_size)
{
RAMBlockNotifier *notifier;

QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
notifier->ram_block_added(notifier, host, size);
if (notifier->ram_block_removed) {
notifier->ram_block_removed(notifier, host, size, max_size);
}
}
}

void ram_block_notify_remove(void *host, size_t size)
void ram_block_notify_resize(void *host, size_t old_size, size_t new_size)
{
RAMBlockNotifier *notifier;

QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
notifier->ram_block_removed(notifier, host, size);
if (notifier->ram_block_resized) {
notifier->ram_block_resized(notifier, host, old_size, new_size);
}
}
}
7 changes: 4 additions & 3 deletions hw/i386/xen/xen-mapcache.c
Expand Up @@ -169,7 +169,8 @@ static void xen_remap_bucket(MapCacheEntry *entry,

if (entry->vaddr_base != NULL) {
if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) {
ram_block_notify_remove(entry->vaddr_base, entry->size);
ram_block_notify_remove(entry->vaddr_base, entry->size,
entry->size);
}

/*
Expand Down Expand Up @@ -224,7 +225,7 @@ static void xen_remap_bucket(MapCacheEntry *entry,
}

if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) {
ram_block_notify_add(vaddr_base, size);
ram_block_notify_add(vaddr_base, size, size);
}

entry->vaddr_base = vaddr_base;
Expand Down Expand Up @@ -465,7 +466,7 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
}

pentry->next = entry->next;
ram_block_notify_remove(entry->vaddr_base, entry->size);
ram_block_notify_remove(entry->vaddr_base, entry->size, entry->size);
if (munmap(entry->vaddr_base, entry->size) != 0) {
perror("unmap fails");
exit(-1);
Expand Down
4 changes: 1 addition & 3 deletions hw/virtio/virtio-balloon.c
Expand Up @@ -663,9 +663,6 @@ virtio_balloon_free_page_hint_notify(NotifierWithReturn *n, void *data)
}

switch (pnd->reason) {
case PRECOPY_NOTIFY_SETUP:
precopy_enable_free_page_optimization();
break;
case PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC:
virtio_balloon_free_page_stop(dev);
break;
Expand All @@ -685,6 +682,7 @@ virtio_balloon_free_page_hint_notify(NotifierWithReturn *n, void *data)
*/
virtio_balloon_free_page_done(dev);
break;
case PRECOPY_NOTIFY_SETUP:
case PRECOPY_NOTIFY_COMPLETE:
break;
default:
Expand Down
3 changes: 0 additions & 3 deletions hw/virtio/virtio-mem.c
Expand Up @@ -902,9 +902,6 @@ static int virtio_mem_precopy_notify(NotifierWithReturn *n, void *data)
PrecopyNotifyData *pnd = data;

switch (pnd->reason) {
case PRECOPY_NOTIFY_SETUP:
precopy_enable_free_page_optimization();
break;
case PRECOPY_NOTIFY_AFTER_BITMAP_SYNC:
virtio_mem_precopy_exclude_unplugged(vmem);
break;
Expand Down
1 change: 1 addition & 0 deletions include/exec/cpu-common.h
Expand Up @@ -57,6 +57,7 @@ const char *qemu_ram_get_idstr(RAMBlock *rb);
void *qemu_ram_get_host_addr(RAMBlock *rb);
ram_addr_t qemu_ram_get_offset(RAMBlock *rb);
ram_addr_t qemu_ram_get_used_length(RAMBlock *rb);
ram_addr_t qemu_ram_get_max_length(RAMBlock *rb);
bool qemu_ram_is_shared(RAMBlock *rb);
bool qemu_ram_is_uf_zeroable(RAMBlock *rb);
void qemu_ram_set_uf_zeroable(RAMBlock *rb);
Expand Down
10 changes: 6 additions & 4 deletions include/exec/memory.h
Expand Up @@ -131,7 +131,7 @@ typedef struct IOMMUTLBEvent {
#define RAM_SHARED (1 << 1)

/* Only a portion of RAM (used_length) is actually used, and migrated.
* This used_length size can change across reboots.
* Resizing RAM while migrating can result in the migration being canceled.
*/
#define RAM_RESIZEABLE (1 << 2)

Expand Down Expand Up @@ -955,7 +955,9 @@ void memory_region_init_ram_shared_nomigrate(MemoryRegion *mr,
* RAM. Accesses into the region will
* modify memory directly. Only an initial
* portion of this RAM is actually used.
* The used size can change across reboots.
* Changing the size while migrating
* can result in the migration being
* canceled.
*
* @mr: the #MemoryRegion to be initialized.
* @owner: the object that tracks the region's reference count
Expand Down Expand Up @@ -1586,8 +1588,8 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr);

/* memory_region_ram_resize: Resize a RAM region.
*
* Only legal before guest might have detected the memory size: e.g. on
* incoming migration, or right after reset.
* Resizing RAM while migrating can result in the migration being canceled.
* Care has to be taken if the guest might have already detected the memory.
*
* @mr: a memory region created with @memory_region_init_resizeable_ram.
* @newsize: the new size the region
Expand Down
10 changes: 10 additions & 0 deletions include/exec/ramblock.h
Expand Up @@ -59,6 +59,16 @@ struct RAMBlock {
*/
unsigned long *clear_bmap;
uint8_t clear_bmap_shift;

/*
* RAM block length that corresponds to the used_length on the migration
* source (after RAM block sizes were synchronized). Especially, after
* starting to run the guest, used_length and postcopy_length can differ.
* Used to register/unregister uffd handlers and as the size of the received
* bitmap. Receiving any page beyond this length will bail out, as it
* could not have been valid on the source.
*/
ram_addr_t postcopy_length;
};
#endif
#endif
13 changes: 9 additions & 4 deletions include/exec/ramlist.h
Expand Up @@ -65,15 +65,20 @@ void qemu_mutex_lock_ramlist(void);
void qemu_mutex_unlock_ramlist(void);

struct RAMBlockNotifier {
void (*ram_block_added)(RAMBlockNotifier *n, void *host, size_t size);
void (*ram_block_removed)(RAMBlockNotifier *n, void *host, size_t size);
void (*ram_block_added)(RAMBlockNotifier *n, void *host, size_t size,
size_t max_size);
void (*ram_block_removed)(RAMBlockNotifier *n, void *host, size_t size,
size_t max_size);
void (*ram_block_resized)(RAMBlockNotifier *n, void *host, size_t old_size,
size_t new_size);
QLIST_ENTRY(RAMBlockNotifier) next;
};

void ram_block_notifier_add(RAMBlockNotifier *n);
void ram_block_notifier_remove(RAMBlockNotifier *n);
void ram_block_notify_add(void *host, size_t size);
void ram_block_notify_remove(void *host, size_t size);
void ram_block_notify_add(void *host, size_t size, size_t max_size);
void ram_block_notify_remove(void *host, size_t size, size_t max_size);
void ram_block_notify_resize(void *host, size_t old_size, size_t new_size);

void ram_block_dump(Monitor *mon);

Expand Down
1 change: 0 additions & 1 deletion include/migration/misc.h
Expand Up @@ -37,7 +37,6 @@ void precopy_infrastructure_init(void);
void precopy_add_notifier(NotifierWithReturn *n);
void precopy_remove_notifier(NotifierWithReturn *n);
int precopy_notify(PrecopyNotifyReason reason, Error **errp);
void precopy_enable_free_page_optimization(void);

void ram_mig_init(void);
void qemu_guest_free_page_hint(void *addr, size_t len);
Expand Down
38 changes: 20 additions & 18 deletions migration/migration.c
Expand Up @@ -223,13 +223,18 @@ void migration_object_init(void)
dirty_bitmap_mig_init();
}

void migration_cancel(void)
{
migrate_fd_cancel(current_migration);
}

void migration_shutdown(void)
{
/*
* Cancel the current migration - that will (eventually)
* stop the migration using this structure
*/
migrate_fd_cancel(current_migration);
migration_cancel();
object_unref(OBJECT(current_migration));

/*
Expand Down Expand Up @@ -1073,27 +1078,24 @@ static void populate_vfio_info(MigrationInfo *info)
static void fill_source_migration_info(MigrationInfo *info)
{
MigrationState *s = migrate_get_current();
GSList *cur_blocker = migration_blockers;

info->blocked = migration_is_blocked(NULL);
info->has_blocked_reasons = info->blocked;
info->blocked_reasons = NULL;
if (info->blocked) {
GSList *cur_blocker = migration_blockers;

/*
* There are two types of reasons a migration might be blocked;
* a) devices marked in VMState as non-migratable, and
* b) Explicit migration blockers
* We need to add both of them here.
*/
qemu_savevm_non_migratable_list(&info->blocked_reasons);
/*
* There are two types of reasons a migration might be blocked;
* a) devices marked in VMState as non-migratable, and
* b) Explicit migration blockers
* We need to add both of them here.
*/
qemu_savevm_non_migratable_list(&info->blocked_reasons);

while (cur_blocker) {
QAPI_LIST_PREPEND(info->blocked_reasons,
g_strdup(error_get_pretty(cur_blocker->data)));
cur_blocker = g_slist_next(cur_blocker);
}
while (cur_blocker) {
QAPI_LIST_PREPEND(info->blocked_reasons,
g_strdup(error_get_pretty(cur_blocker->data)));
cur_blocker = g_slist_next(cur_blocker);
}
info->has_blocked_reasons = info->blocked_reasons != NULL;

switch (s->state) {
case MIGRATION_STATUS_NONE:
Expand Down Expand Up @@ -2310,7 +2312,7 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,

void qmp_migrate_cancel(Error **errp)
{
migrate_fd_cancel(migrate_get_current());
migration_cancel();
}

void qmp_migrate_continue(MigrationStatus state, Error **errp)
Expand Down
1 change: 1 addition & 0 deletions migration/migration.h
Expand Up @@ -375,5 +375,6 @@ int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque);
void migration_make_urgent_request(void);
void migration_consume_urgent_request(void);
bool migration_rate_limit(void);
void migration_cancel(void);

#endif
2 changes: 1 addition & 1 deletion migration/multifd.c
Expand Up @@ -361,7 +361,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
if (offset > (block->used_length - qemu_target_page_size())) {
error_setg(errp, "multifd: offset too long %" PRIu64
" (max " RAM_ADDR_FMT ")",
offset, block->max_length);
offset, block->used_length);
return -1;
}
p->pages->iov[i].iov_base = block->host + offset;
Expand Down
15 changes: 12 additions & 3 deletions migration/postcopy-ram.c
Expand Up @@ -17,6 +17,7 @@
*/

#include "qemu/osdep.h"
#include "qemu/rcu.h"
#include "exec/target_page.h"
#include "migration.h"
#include "qemu-file.h"
Expand All @@ -30,6 +31,7 @@
#include "qemu/error-report.h"
#include "trace.h"
#include "hw/boards.h"
#include "exec/ramblock.h"

/* Arbitrary limit on size of each discard command,
* keeps them around ~200 bytes
Expand Down Expand Up @@ -452,6 +454,13 @@ static int init_range(RAMBlock *rb, void *opaque)
ram_addr_t length = qemu_ram_get_used_length(rb);
trace_postcopy_init_range(block_name, host_addr, offset, length);

/*
* Save the used_length before running the guest. In case we have to
* resize RAM blocks when syncing RAM block sizes from the source during
* precopy, we'll update it manually via the ram block notifier.
*/
rb->postcopy_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
Expand All @@ -474,7 +483,7 @@ static int cleanup_range(RAMBlock *rb, void *opaque)
const char *block_name = qemu_ram_get_idstr(rb);
void *host_addr = qemu_ram_get_host_addr(rb);
ram_addr_t offset = qemu_ram_get_offset(rb);
ram_addr_t length = qemu_ram_get_used_length(rb);
ram_addr_t length = rb->postcopy_length;
MigrationIncomingState *mis = opaque;
struct uffdio_range range_struct;
trace_postcopy_cleanup_range(block_name, host_addr, offset, length);
Expand Down Expand Up @@ -580,7 +589,7 @@ static int nhp_range(RAMBlock *rb, void *opaque)
const char *block_name = qemu_ram_get_idstr(rb);
void *host_addr = qemu_ram_get_host_addr(rb);
ram_addr_t offset = qemu_ram_get_offset(rb);
ram_addr_t length = qemu_ram_get_used_length(rb);
ram_addr_t length = rb->postcopy_length;
trace_postcopy_nhp_range(block_name, host_addr, offset, length);

/*
Expand Down Expand Up @@ -624,7 +633,7 @@ static int ram_block_enable_notify(RAMBlock *rb, void *opaque)
struct uffdio_register reg_struct;

reg_struct.range.start = (uintptr_t)qemu_ram_get_host_addr(rb);
reg_struct.range.len = qemu_ram_get_used_length(rb);
reg_struct.range.len = rb->postcopy_length;
reg_struct.mode = UFFDIO_REGISTER_MODE_MISSING;

/* Now tell our userfault_fd that it's responsible for this area */
Expand Down

0 comments on commit 07b0a39

Please sign in to comment.