aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-04-08 14:00:57 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-04-08 14:00:57 +0100
commitd8724020dd13c88a72fc391a6a2cf63abbd3dcca (patch)
tree5ff191d498a3f787c5353cf08e9e0f69832c3272
parent9692c7b0373677badcf8bb299ab8e2597244d436 (diff)
parente999fa47b220274082cb238d5ccb2c9bacd42bf1 (diff)
downloadqemu-d8724020dd13c88a72fc391a6a2cf63abbd3dcca.zip
qemu-d8724020dd13c88a72fc391a6a2cf63abbd3dcca.tar.gz
qemu-d8724020dd13c88a72fc391a6a2cf63abbd3dcca.tar.bz2
Merge remote-tracking branch 'remotes/dgilbert/tags/pull-migration-20210407b' into staging
V2 migration+virtiofs fixes pull 2021-04-07 A seg fix in virtiofsd, a bunch of fixes for background snapshots, and a migration test fix. Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> v2 Fix for !linux build # gpg: Signature made Wed 07 Apr 2021 18:53:13 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-20210407b: tests/migration: fix parameter of auto-converge migration migration: Rename 'bs' to 'block' in background snapshot code migration: Pre-fault memory before starting background snasphot migration: Inhibit virtio-balloon for the duration of background snapshot migration: Fix missing qemu_fflush() on buffer file in bg_migration_thread virtiofsd: Fix security.capability comparison Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/virtio/virtio-balloon.c8
-rw-r--r--include/migration/misc.h2
-rw-r--r--migration/migration.c24
-rw-r--r--migration/ram.c119
-rw-r--r--migration/ram.h1
-rw-r--r--tests/migration/guestperf/engine.py4
-rw-r--r--tools/virtiofsd/passthrough_ll.c3
7 files changed, 121 insertions, 40 deletions
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index e770955..d120bf8 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -66,8 +66,12 @@ static bool virtio_balloon_pbp_matches(PartiallyBalloonedPage *pbp,
static bool virtio_balloon_inhibited(void)
{
- /* Postcopy cannot deal with concurrent discards, so it's special. */
- return ram_block_discard_is_disabled() || migration_in_incoming_postcopy();
+ /*
+ * Postcopy cannot deal with concurrent discards,
+ * so it's special, as well as background snapshots.
+ */
+ return ram_block_discard_is_disabled() || migration_in_incoming_postcopy() ||
+ migration_in_bg_snapshot();
}
static void balloon_inflate_page(VirtIOBalloon *balloon,
diff --git a/include/migration/misc.h b/include/migration/misc.h
index bccc1b6..738675e 100644
--- a/include/migration/misc.h
+++ b/include/migration/misc.h
@@ -70,6 +70,8 @@ bool migration_in_postcopy_after_devices(MigrationState *);
void migration_global_dump(Monitor *mon);
/* True if incomming migration entered POSTCOPY_INCOMING_DISCARD */
bool migration_in_incoming_postcopy(void);
+/* True if background snapshot is active */
+bool migration_in_bg_snapshot(void);
/* migration/block-dirty-bitmap.c */
void dirty_bitmap_mig_init(void);
diff --git a/migration/migration.c b/migration/migration.c
index ca8b97b..8ca0341 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1976,6 +1976,14 @@ bool migration_in_incoming_postcopy(void)
return ps >= POSTCOPY_INCOMING_DISCARD && ps < POSTCOPY_INCOMING_END;
}
+bool migration_in_bg_snapshot(void)
+{
+ MigrationState *s = migrate_get_current();
+
+ return migrate_background_snapshot() &&
+ migration_is_setup_or_active(s->state);
+}
+
bool migration_is_idle(void)
{
MigrationState *s = current_migration;
@@ -3812,13 +3820,21 @@ static void *bg_migration_thread(void *opaque)
* with vCPUs running and, finally, write stashed non-RAM part of
* the vmstate from the buffer to the migration stream.
*/
- s->bioc = qio_channel_buffer_new(128 * 1024);
+ s->bioc = qio_channel_buffer_new(512 * 1024);
qio_channel_set_name(QIO_CHANNEL(s->bioc), "vmstate-buffer");
fb = qemu_fopen_channel_output(QIO_CHANNEL(s->bioc));
object_unref(OBJECT(s->bioc));
update_iteration_initial_status(s);
+ /*
+ * Prepare for tracking memory writes with UFFD-WP - populate
+ * RAM pages before protecting.
+ */
+#ifdef __linux__
+ ram_write_tracking_prepare();
+#endif
+
qemu_savevm_state_header(s->to_dst_file);
qemu_savevm_state_setup(s->to_dst_file);
@@ -3866,6 +3882,12 @@ static void *bg_migration_thread(void *opaque)
if (qemu_savevm_state_complete_precopy_non_iterable(fb, false, false)) {
goto fail;
}
+ /*
+ * Since we are going to get non-iterable state data directly
+ * from s->bioc->data, explicit flush is needed here.
+ */
+ qemu_fflush(fb);
+
/* Now initialize UFFD context and start tracking RAM writes */
if (ram_write_tracking_start()) {
goto fail;
diff --git a/migration/ram.c b/migration/ram.c
index 40e7895..4682f36 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1455,7 +1455,7 @@ static RAMBlock *poll_fault_page(RAMState *rs, ram_addr_t *offset)
{
struct uffd_msg uffd_msg;
void *page_address;
- RAMBlock *bs;
+ RAMBlock *block;
int res;
if (!migrate_background_snapshot()) {
@@ -1468,9 +1468,9 @@ static RAMBlock *poll_fault_page(RAMState *rs, ram_addr_t *offset)
}
page_address = (void *)(uintptr_t) uffd_msg.arg.pagefault.address;
- bs = qemu_ram_block_from_host(page_address, false, offset);
- assert(bs && (bs->flags & RAM_UF_WRITEPROTECT) != 0);
- return bs;
+ block = qemu_ram_block_from_host(page_address, false, offset);
+ assert(block && (block->flags & RAM_UF_WRITEPROTECT) != 0);
+ return block;
}
/**
@@ -1526,7 +1526,7 @@ bool ram_write_tracking_compatible(void)
{
const uint64_t uffd_ioctls_mask = BIT(_UFFDIO_WRITEPROTECT);
int uffd_fd;
- RAMBlock *bs;
+ RAMBlock *block;
bool ret = false;
/* Open UFFD file descriptor */
@@ -1537,15 +1537,15 @@ bool ram_write_tracking_compatible(void)
RCU_READ_LOCK_GUARD();
- RAMBLOCK_FOREACH_NOT_IGNORED(bs) {
+ RAMBLOCK_FOREACH_NOT_IGNORED(block) {
uint64_t uffd_ioctls;
/* Nothing to do with read-only and MMIO-writable regions */
- if (bs->mr->readonly || bs->mr->rom_device) {
+ if (block->mr->readonly || block->mr->rom_device) {
continue;
}
/* Try to register block memory via UFFD-IO to track writes */
- if (uffd_register_memory(uffd_fd, bs->host, bs->max_length,
+ if (uffd_register_memory(uffd_fd, block->host, block->max_length,
UFFDIO_REGISTER_MODE_WP, &uffd_ioctls)) {
goto out;
}
@@ -1561,6 +1561,55 @@ out:
}
/*
+ * ram_block_populate_pages: populate memory in the RAM block by reading
+ * an integer from the beginning of each page.
+ *
+ * Since it's solely used for userfault_fd WP feature, here we just
+ * hardcode page size to qemu_real_host_page_size.
+ *
+ * @block: RAM block to populate
+ */
+static void ram_block_populate_pages(RAMBlock *block)
+{
+ char *ptr = (char *) block->host;
+
+ for (ram_addr_t offset = 0; offset < block->used_length;
+ offset += qemu_real_host_page_size) {
+ char tmp = *(ptr + offset);
+
+ /* Don't optimize the read out */
+ asm volatile("" : "+r" (tmp));
+ }
+}
+
+/*
+ * ram_write_tracking_prepare: prepare for UFFD-WP memory tracking
+ */
+void ram_write_tracking_prepare(void)
+{
+ RAMBlock *block;
+
+ RCU_READ_LOCK_GUARD();
+
+ RAMBLOCK_FOREACH_NOT_IGNORED(block) {
+ /* Nothing to do with read-only and MMIO-writable regions */
+ if (block->mr->readonly || block->mr->rom_device) {
+ continue;
+ }
+
+ /*
+ * Populate pages of the RAM block before enabling userfault_fd
+ * write protection.
+ *
+ * This stage is required since ioctl(UFFDIO_WRITEPROTECT) with
+ * UFFDIO_WRITEPROTECT_MODE_WP mode setting would silently skip
+ * pages with pte_none() entries in page table.
+ */
+ ram_block_populate_pages(block);
+ }
+}
+
+/*
* ram_write_tracking_start: start UFFD-WP memory tracking
*
* Returns 0 for success or negative value in case of error
@@ -1569,7 +1618,7 @@ int ram_write_tracking_start(void)
{
int uffd_fd;
RAMState *rs = ram_state;
- RAMBlock *bs;
+ RAMBlock *block;
/* Open UFFD file descriptor */
uffd_fd = uffd_create_fd(UFFD_FEATURE_PAGEFAULT_FLAG_WP, true);
@@ -1580,27 +1629,27 @@ int ram_write_tracking_start(void)
RCU_READ_LOCK_GUARD();
- RAMBLOCK_FOREACH_NOT_IGNORED(bs) {
+ RAMBLOCK_FOREACH_NOT_IGNORED(block) {
/* Nothing to do with read-only and MMIO-writable regions */
- if (bs->mr->readonly || bs->mr->rom_device) {
+ if (block->mr->readonly || block->mr->rom_device) {
continue;
}
/* Register block memory with UFFD to track writes */
- if (uffd_register_memory(rs->uffdio_fd, bs->host,
- bs->max_length, UFFDIO_REGISTER_MODE_WP, NULL)) {
+ if (uffd_register_memory(rs->uffdio_fd, block->host,
+ block->max_length, UFFDIO_REGISTER_MODE_WP, NULL)) {
goto fail;
}
/* Apply UFFD write protection to the block memory range */
- if (uffd_change_protection(rs->uffdio_fd, bs->host,
- bs->max_length, true, false)) {
+ if (uffd_change_protection(rs->uffdio_fd, block->host,
+ block->max_length, true, false)) {
goto fail;
}
- bs->flags |= RAM_UF_WRITEPROTECT;
- memory_region_ref(bs->mr);
+ block->flags |= RAM_UF_WRITEPROTECT;
+ memory_region_ref(block->mr);
- trace_ram_write_tracking_ramblock_start(bs->idstr, bs->page_size,
- bs->host, bs->max_length);
+ trace_ram_write_tracking_ramblock_start(block->idstr, block->page_size,
+ block->host, block->max_length);
}
return 0;
@@ -1608,19 +1657,20 @@ int ram_write_tracking_start(void)
fail:
error_report("ram_write_tracking_start() failed: restoring initial memory state");
- RAMBLOCK_FOREACH_NOT_IGNORED(bs) {
- if ((bs->flags & RAM_UF_WRITEPROTECT) == 0) {
+ RAMBLOCK_FOREACH_NOT_IGNORED(block) {
+ if ((block->flags & RAM_UF_WRITEPROTECT) == 0) {
continue;
}
/*
* In case some memory block failed to be write-protected
* remove protection and unregister all succeeded RAM blocks
*/
- uffd_change_protection(rs->uffdio_fd, bs->host, bs->max_length, false, false);
- uffd_unregister_memory(rs->uffdio_fd, bs->host, bs->max_length);
+ uffd_change_protection(rs->uffdio_fd, block->host, block->max_length,
+ false, false);
+ uffd_unregister_memory(rs->uffdio_fd, block->host, block->max_length);
/* Cleanup flags and remove reference */
- bs->flags &= ~RAM_UF_WRITEPROTECT;
- memory_region_unref(bs->mr);
+ block->flags &= ~RAM_UF_WRITEPROTECT;
+ memory_region_unref(block->mr);
}
uffd_close_fd(uffd_fd);
@@ -1634,24 +1684,25 @@ fail:
void ram_write_tracking_stop(void)
{
RAMState *rs = ram_state;
- RAMBlock *bs;
+ RAMBlock *block;
RCU_READ_LOCK_GUARD();
- RAMBLOCK_FOREACH_NOT_IGNORED(bs) {
- if ((bs->flags & RAM_UF_WRITEPROTECT) == 0) {
+ RAMBLOCK_FOREACH_NOT_IGNORED(block) {
+ if ((block->flags & RAM_UF_WRITEPROTECT) == 0) {
continue;
}
/* Remove protection and unregister all affected RAM blocks */
- uffd_change_protection(rs->uffdio_fd, bs->host, bs->max_length, false, false);
- uffd_unregister_memory(rs->uffdio_fd, bs->host, bs->max_length);
+ uffd_change_protection(rs->uffdio_fd, block->host, block->max_length,
+ false, false);
+ uffd_unregister_memory(rs->uffdio_fd, block->host, block->max_length);
- trace_ram_write_tracking_ramblock_stop(bs->idstr, bs->page_size,
- bs->host, bs->max_length);
+ trace_ram_write_tracking_ramblock_stop(block->idstr, block->page_size,
+ block->host, block->max_length);
/* Cleanup flags and remove reference */
- bs->flags &= ~RAM_UF_WRITEPROTECT;
- memory_region_unref(bs->mr);
+ block->flags &= ~RAM_UF_WRITEPROTECT;
+ memory_region_unref(block->mr);
}
/* Finally close UFFD file descriptor */
diff --git a/migration/ram.h b/migration/ram.h
index 6378bb3..4833e9f 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -82,6 +82,7 @@ void colo_incoming_start_dirty_log(void);
/* Background snapshot */
bool ram_write_tracking_available(void);
bool ram_write_tracking_compatible(void);
+void ram_write_tracking_prepare(void);
int ram_write_tracking_start(void);
void ram_write_tracking_stop(void);
diff --git a/tests/migration/guestperf/engine.py b/tests/migration/guestperf/engine.py
index e399447..6b49aed 100644
--- a/tests/migration/guestperf/engine.py
+++ b/tests/migration/guestperf/engine.py
@@ -102,7 +102,7 @@ class Engine(object):
info.get("downtime", 0),
info.get("expected-downtime", 0),
info.get("setup-time", 0),
- info.get("x-cpu-throttle-percentage", 0),
+ info.get("cpu-throttle-percentage", 0),
)
def _migrate(self, hardware, scenario, src, dst, connect_uri):
@@ -135,7 +135,7 @@ class Engine(object):
"state": True }
])
resp = src.command("migrate-set-parameters",
- x_cpu_throttle_increment=scenario._auto_converge_step)
+ cpu_throttle_increment=scenario._auto_converge_step)
if scenario._post_copy:
resp = src.command("migrate-set-capabilities",
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
index b144320..1553d2e 100644
--- a/tools/virtiofsd/passthrough_ll.c
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -2636,7 +2636,8 @@ static void parse_xattrmap(struct lo_data *lo)
strerror(ret));
exit(1);
}
- if (!strcmp(lo->xattr_security_capability, "security.capability")) {
+ if (!lo->xattr_security_capability ||
+ !strcmp(lo->xattr_security_capability, "security.capability")) {
/* 1-1 mapping, don't need to do anything */
free(lo->xattr_security_capability);
lo->xattr_security_capability = NULL;