@@ -373,7 +373,7 @@ int postcopy_ram_prepare_discard(MigrationIncomingState *mis)
return 0;
}
-int ram_set_pages_wp(uint64_t page_addr,
+int ram_set_pages_wp(ram_addr_t page_addr,
uint64_t size,
bool remove,
int uffd)
@@ -556,10 +556,10 @@ static void *postcopy_ram_fault_thread(void *opaque)
* will be an deadlock error.
*/
if (migration_in_setup(ms)) {
- uint64_t host = msg.arg.pagefault.address;
+ ram_addr_t host = msg.arg.pagefault.address;
host &= ~(hostpagesize - 1);
- ret = ram_set_pages_wp(host, getpagesize(), true,
+ ret = ram_set_pages_wp(host, hostpagesize, true,
us->userfault_fd);
if (ret < 0) {
error_report("Remove page's write-protect failed");
@@ -1383,14 +1383,24 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage,
/* For snapshot, we will remove the page write-protect here */
if (migration_in_snapshot(ms)) {
int ret;
- uint64_t host_addr = (uint64_t)(pss.block->host + pss.offset);
-
+ /*
+ * Some architectures in QEMU use a smaller memory page size
+ * with respect to the host page size. ARM as an example
+ * uses 1K memory pages, while Linux supports pages of minimum
+ * size of 4K.
+ * Userfault write protection works at the level of a host page
+ * and thus one full host page has to be protected/unprotected
+ * every time.
+ */
+ ram_addr_t host_addr = (ram_addr_t)(pss.block->host +
+ pss.offset) & (~(qemu_host_page_size - 1));
ret = ram_set_pages_wp(host_addr, getpagesize(), true,
ms->userfault_state.userfault_fd);
if (ret < 0) {
error_report("Failed to remove the write-protect for page:"
- "%"PRIx64 " length: %d, block: %s", host_addr,
- getpagesize(), pss.block->idstr);
+ "%"PRIx64 " length: %d, offset: %"PRIx64
+ ", block: %s", host_addr, getpagesize(),
+ pss.offset, pss.block->idstr);
}
}
}