[PATCH 1/3] migration/postcopy: Extract page fault handler callback

Takeru Hayasaka posted 3 patches 2 days, 6 hours ago
Maintainers: Peter Xu <peterx@redhat.com>, Fabiano Rosas <farosas@suse.de>
[PATCH 1/3] migration/postcopy: Extract page fault handler callback
Posted by Takeru Hayasaka 2 days, 6 hours ago
Introduce a PostcopyPageHandler callback type and use it to decouple
the userfaultfd fault thread from the postcopy-specific page request
logic. This prepares for fast snapshot load, which will supply pages
from a local file instead of requesting them over the network.

The fault thread now calls mis->page_fault_handler() instead of
postcopy_request_page() directly. For postcopy, the handler is set to
postcopy_page_fault_handler() which delegates to the existing
postcopy_request_page().

No functional change for postcopy migration.

Signed-off-by: Takeru Hayasaka <hayatake396@gmail.com>
---
 migration/migration.h    | 16 ++++++++++++++++
 migration/postcopy-ram.c | 22 +++++++++++++++++++---
 2 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/migration/migration.h b/migration/migration.h
index b6888daceddf..33525402922d 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -89,6 +89,17 @@ typedef enum {
     PREEMPT_THREAD_QUIT,
 } PreemptThreadStatus;
 
+/*
+ * Callback to handle a page fault from the userfaultfd fault thread.
+ * Implementations resolve the fault by supplying the requested page,
+ * e.g., by requesting it from the migration source (postcopy) or by
+ * reading it from a snapshot file (fast snapshot load).
+ */
+typedef int (*PostcopyPageHandler)(MigrationIncomingState *mis,
+                                   RAMBlock *rb,
+                                   ram_addr_t offset,
+                                   void *fault_address);
+
 /* State for the incoming migration */
 struct MigrationIncomingState {
     QEMUFile *from_src_file;
@@ -116,6 +127,11 @@ struct MigrationIncomingState {
     QemuThread     fault_thread;
     /* Set this when we want the fault thread to quit */
     bool           fault_thread_quit;
+    /* Callback to resolve page faults; set before fault thread starts */
+    PostcopyPageHandler page_fault_handler;
+    void *page_fault_opaque;
+    /* ptid from current uffd fault msg, for postcopy blocktime tracking */
+    uint32_t fault_thread_ptid;
 
     bool           have_listen_thread;
     QemuThread     listen_thread;
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index f5ef93f1933c..8dcd8ff35e85 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -976,6 +976,20 @@ static int postcopy_request_page(MigrationIncomingState *mis, RAMBlock *rb,
     return migrate_send_rp_req_pages(mis, rb, start, haddr, tid);
 }
 
+/*
+ * Default page fault handler for postcopy live migration.
+ * Requests the faulted page from the source via the return path.
+ */
+static int postcopy_page_fault_handler(MigrationIncomingState *mis,
+                                       RAMBlock *rb,
+                                       ram_addr_t offset,
+                                       void *fault_address)
+{
+    return postcopy_request_page(mis, rb, offset,
+                                 (uint64_t)(uintptr_t)fault_address,
+                                 mis->fault_thread_ptid);
+}
+
 /*
  * Callback from shared fault handlers to ask for a page,
  * the page must be specified by a RAMBlock and an offset in that rb
@@ -1392,9 +1406,9 @@ retry:
              * Send the request to the source - we want to request one
              * of our host page sizes (which is >= TPS)
              */
-            ret = postcopy_request_page(mis, rb, rb_offset,
-                                        msg.arg.pagefault.address,
-                                        msg.arg.pagefault.feat.ptid);
+            mis->fault_thread_ptid = msg.arg.pagefault.feat.ptid;
+            ret = mis->page_fault_handler(mis, rb, rb_offset,
+                    (void *)(uintptr_t)msg.arg.pagefault.address);
             if (ret) {
                 /* May be network failure, try to wait for recovery */
                 postcopy_pause_fault_thread(mis);
@@ -1552,6 +1566,8 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
         return -1;
     }
 
+    mis->page_fault_handler = postcopy_page_fault_handler;
+
     postcopy_thread_create(mis, &mis->fault_thread,
                            MIGRATION_THREAD_DST_FAULT,
                            postcopy_ram_fault_thread, QEMU_THREAD_JOINABLE);

-- 
2.43.0