aboutsummaryrefslogtreecommitdiff
path: root/migration
diff options
context:
space:
mode:
authorDavid Hildenbrand <david@redhat.com>2023-01-05 13:45:28 +0100
committerJuan Quintela <quintela@redhat.com>2023-02-06 19:22:56 +0100
commite41c57702e940fcb9a8046edc3b43edda5134305 (patch)
treefbe08e303d24e4a6ea9e5da0c1e4a769d0a60001 /migration
parent59bcc049c17a50d8ac0353f164f597e7d904589d (diff)
downloadqemu-e41c57702e940fcb9a8046edc3b43edda5134305.zip
qemu-e41c57702e940fcb9a8046edc3b43edda5134305.tar.gz
qemu-e41c57702e940fcb9a8046edc3b43edda5134305.tar.bz2
migration/ram: Optimize ram_write_tracking_start() for RamDiscardManager
ram_block_populate_read() already optimizes for RamDiscardManager. However, ram_write_tracking_start() will still try protecting discarded memory ranges. Let's optimize, because discarded ranges don't map any pages and (1) For anonymous memory, trying to protect using uffd-wp without a mapped page is ignored by the kernel and consequently a NOP. (2) For shared/file-backed memory, we will fill present page tables in the range with PTE markers. However, we will even allocate page tables just to fill them with unnecessary PTE markers and effectively waste memory. So let's exclude these ranges, just like ram_block_populate_read() already does. Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Signed-off-by: David Hildenbrand <david@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com>
Diffstat (limited to 'migration')
-rw-r--r--migration/ram.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/migration/ram.c b/migration/ram.c
index a6956c9..7f6d5ef 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1865,6 +1865,39 @@ void ram_write_tracking_prepare(void)
}
}
+static inline int uffd_protect_section(MemoryRegionSection *section,
+ void *opaque)
+{
+ const hwaddr size = int128_get64(section->size);
+ const hwaddr offset = section->offset_within_region;
+ RAMBlock *rb = section->mr->ram_block;
+ int uffd_fd = (uintptr_t)opaque;
+
+ return uffd_change_protection(uffd_fd, rb->host + offset, size, true,
+ false);
+}
+
+static int ram_block_uffd_protect(RAMBlock *rb, int uffd_fd)
+{
+ assert(rb->flags & RAM_UF_WRITEPROTECT);
+
+ /* See ram_block_populate_read() */
+ if (rb->mr && memory_region_has_ram_discard_manager(rb->mr)) {
+ RamDiscardManager *rdm = memory_region_get_ram_discard_manager(rb->mr);
+ MemoryRegionSection section = {
+ .mr = rb->mr,
+ .offset_within_region = 0,
+ .size = rb->mr->size,
+ };
+
+ return ram_discard_manager_replay_populated(rdm, &section,
+ uffd_protect_section,
+ (void *)(uintptr_t)uffd_fd);
+ }
+ return uffd_change_protection(uffd_fd, rb->host,
+ rb->used_length, true, false);
+}
+
/*
* ram_write_tracking_start: start UFFD-WP memory tracking
*
@@ -1900,8 +1933,7 @@ int ram_write_tracking_start(void)
memory_region_ref(block->mr);
/* Apply UFFD write protection to the block memory range */
- if (uffd_change_protection(rs->uffdio_fd, block->host,
- block->used_length, true, false)) {
+ if (ram_block_uffd_protect(block, uffd_fd)) {
goto fail;
}