From eeccb99c9d28484303f721e94c5084e9c29a3d03 Mon Sep 17 00:00:00 2001 From: Andrey Gruzdev Date: Thu, 1 Apr 2021 12:22:25 +0300 Subject: migration: Pre-fault memory before starting background snasphot This commit solves the issue with userfault_fd WP feature that background snapshot is based on. For any never poluated or discarded memory page, the UFFDIO_WRITEPROTECT ioctl() would skip updating PTE for that page, thereby loosing WP setting for it. So we need to pre-fault pages for each RAM block to be protected before making a userfault_fd wr-protect ioctl(). Fixes: 278e2f551a095b234de74dca9c214d5502a1f72c (migration: support UFFD write fault processing in ram_save_iterate()) Signed-off-by: Andrey Gruzdev Reported-by: David Hildenbrand Reviewed-by: David Hildenbrand Message-Id: <20210401092226.102804-4-andrey.gruzdev@virtuozzo.com> Signed-off-by: Dr. David Alan Gilbert dgilbert: Bodged ifdef __linux__ on ram_write_tracking_prepare, should really go in a stub --- migration/ram.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'migration/ram.c') diff --git a/migration/ram.c b/migration/ram.c index 40e78952ad..7e2bc0fdd3 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1560,6 +1560,55 @@ out: return ret; } +/* + * 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. + * + * @bs: RAM block to populate + */ +static void ram_block_populate_pages(RAMBlock *bs) +{ + char *ptr = (char *) bs->host; + + for (ram_addr_t offset = 0; offset < bs->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 *bs; + + RCU_READ_LOCK_GUARD(); + + RAMBLOCK_FOREACH_NOT_IGNORED(bs) { + /* Nothing to do with read-only and MMIO-writable regions */ + if (bs->mr->readonly || bs->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(bs); + } +} + /* * ram_write_tracking_start: start UFFD-WP memory tracking * -- cgit v1.2.3