qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v4 39/47] postcopy_ram.c: place_page and helpers


From: Dr. David Alan Gilbert (git)
Subject: [Qemu-devel] [PATCH v4 39/47] postcopy_ram.c: place_page and helpers
Date: Fri, 3 Oct 2014 18:47:45 +0100

From: "Dr. David Alan Gilbert" <address@hidden>

postcopy_place_page (etc) provide a way for postcopy to place a page
into guests memory atomically (using the new remap_anon_pages syscall).

Signed-off-by: Dr. David Alan Gilbert <address@hidden>
---
 include/migration/migration.h    |   2 +
 include/migration/postcopy-ram.h |  23 +++++++
 postcopy-ram.c                   | 145 ++++++++++++++++++++++++++++++++++++++-
 3 files changed, 168 insertions(+), 2 deletions(-)

diff --git a/include/migration/migration.h b/include/migration/migration.h
index 5bc01d5..58ac7bf 100644
--- a/include/migration/migration.h
+++ b/include/migration/migration.h
@@ -96,6 +96,8 @@ struct MigrationIncomingState {
     QEMUFile *return_path;
     QemuMutex      rp_mutex;    /* We send replies from multiple threads */
     PostcopyPMI    postcopy_pmi;
+    void          *postcopy_tmp_page;
+    long           postcopy_place_skipped; /* Check for incorrect place ops */
 };
 
 MigrationIncomingState *migration_incoming_get_current(void);
diff --git a/include/migration/postcopy-ram.h b/include/migration/postcopy-ram.h
index 413b670..0210491 100644
--- a/include/migration/postcopy-ram.h
+++ b/include/migration/postcopy-ram.h
@@ -80,4 +80,27 @@ void postcopy_discard_send_chunk(MigrationState *ms, 
PostcopyDiscardState *pds,
 void postcopy_discard_send_finish(MigrationState *ms,
                                   PostcopyDiscardState *pds);
 
+/*
+ * Place a zero'd page of memory at *host
+ * returns 0 on success
+ */
+int postcopy_place_zero_page(MigrationIncomingState *mis, void *host,
+                             long bitmap_offset);
+
+/*
+ * Place a page (from) at (host) efficiently
+ *    There are restrictions on how 'from' must be mapped, in general best
+ *    to use other postcopy_ routines to allocate.
+ * returns 0 on success
+ */
+int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from,
+                        long bitmap_offset);
+
+/*
+ * Allocate a page of memory that can be mapped at a later point in time
+ * using postcopy_place_page
+ * Returns: Pointer to allocated page
+ */
+void *postcopy_get_tmp_page(MigrationIncomingState *mis, long bitmap_offset);
+
 #endif
diff --git a/postcopy-ram.c b/postcopy-ram.c
index 8b2a035..19d4b20 100644
--- a/postcopy-ram.c
+++ b/postcopy-ram.c
@@ -229,7 +229,6 @@ static PostcopyPMIState postcopy_pmi_get_state_nolock(
 }
 
 /* Retrieve the state of the given page */
-__attribute__ (( unused )) /* Until later in patch series */
 static PostcopyPMIState postcopy_pmi_get_state(MigrationIncomingState *mis,
                                                size_t bitmap_index)
 {
@@ -245,7 +244,6 @@ static PostcopyPMIState 
postcopy_pmi_get_state(MigrationIncomingState *mis,
  * Set the page state to the given state if the previous state was as expected
  * Return the actual previous state.
  */
-__attribute__ (( unused )) /* Until later in patch series */
 static PostcopyPMIState postcopy_pmi_change_state(MigrationIncomingState *mis,
                                            size_t bitmap_index,
                                            PostcopyPMIState expected_state,
@@ -464,6 +462,7 @@ static int cleanup_area(const char *block_name, void 
*host_addr,
 int postcopy_ram_incoming_init(MigrationIncomingState *mis, size_t ram_pages)
 {
     postcopy_pmi_init(mis, ram_pages);
+    mis->postcopy_place_skipped = -1;
 
     if (qemu_ram_foreach_block(init_area, mis)) {
         return -1;
@@ -482,6 +481,10 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState 
*mis)
         return -1;
     }
 
+    if (mis->postcopy_tmp_page) {
+        munmap(mis->postcopy_tmp_page, getpagesize());
+        mis->postcopy_tmp_page = NULL;
+    }
     return 0;
 }
 
@@ -551,6 +554,126 @@ int postcopy_ram_enable_notify(MigrationIncomingState 
*mis)
     return 0;
 }
 
+/*
+ * Place a zero'd page of memory at *host
+ * returns 0 on success
+ * bitmap_offset: Index into the migration bitmaps
+ */
+int postcopy_place_zero_page(MigrationIncomingState *mis, void *host,
+                             long bitmap_offset)
+{
+    void *tmp = postcopy_get_tmp_page(mis, bitmap_offset);
+    if (!tmp) {
+        return -ENOMEM;
+    }
+    *(char *)tmp = 0;
+    return postcopy_place_page(mis, host, tmp, bitmap_offset);
+}
+
+/*
+ * Place a target page (from) at (host) efficiently
+ *    There are restrictions on how 'from' must be mapped, in general best
+ *    to use other postcopy_ routines to allocate.
+ * returns 0 on success
+ * bitmap_offset: Index into the migration bitmaps
+ *
+ * Where HPS > TPS it holds off doing the place until the last TP in the HP
+ *  and assumes (from, host) point to the last TP in a continuous HP
+ */
+int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from,
+                        long bitmap_offset)
+{
+    PostcopyPMIState old_state, tmp_state;
+    size_t hps = sysconf(_SC_PAGESIZE);
+
+    /* Only place the page when the last target page within the hp arrives */
+    if ((bitmap_offset + 1) & (mis->postcopy_pmi.host_bits - 1)) {
+        DPRINTF("%s: Skipping incomplete hp host=%p from=%p bitmap_offset=%lx",
+                __func__, host, from, bitmap_offset);
+        mis->postcopy_place_skipped = bitmap_offset;
+        return 0;
+    }
+
+    /*
+     * If we skip a page (above) we should end up placing that page before
+     * doing anything with other host pages.
+     */
+    if (mis->postcopy_place_skipped != -1) {
+        assert((bitmap_offset & ~(mis->postcopy_pmi.host_bits - 1)) ==
+               (mis->postcopy_place_skipped &
+                ~(mis->postcopy_pmi.host_bits - 1)));
+    }
+    mis->postcopy_place_skipped = -1;
+
+    /* Adjust pointers to point to start of host page */
+    host = (void *)((uintptr_t)host & ~(hps - 1));
+    from = (void *)((uintptr_t)from & ~(hps - 1));
+    bitmap_offset -= (mis->postcopy_pmi.host_bits - 1);
+
+    if (syscall(__NR_remap_anon_pages, host, from, hps, 0) !=
+            getpagesize()) {
+        perror("remap_anon_pages in postcopy_place_page");
+        fprintf(stderr, "host: %p from: %p pmi=%d\n", host, from,
+                postcopy_pmi_get_state(mis, bitmap_offset));
+
+        return -errno;
+    }
+
+    tmp_state = postcopy_pmi_get_state(mis, bitmap_offset);
+    do {
+        old_state = tmp_state;
+        tmp_state = postcopy_pmi_change_state(mis, bitmap_offset, old_state,
+                                              POSTCOPY_PMI_RECEIVED);
+
+    } while (old_state != tmp_state);
+
+
+    if (old_state == POSTCOPY_PMI_REQUESTED) {
+        /* TODO: Notify kernel */
+    }
+
+    return 0;
+}
+
+/*
+ * Returns a target page of memory that can be mapped at a later point in time
+ * using postcopy_place_page
+ * The same address is used repeatedly, postcopy_place_page just takes the
+ * backing page away.
+ * Returns: Pointer to allocated page
+ *
+ * Note this is a target page and uses the bitmap_offset to get an offset
+ * into a hostpage; since there's only one real temporary host page the caller
+ * is expected to not flip around between pages.
+ */
+void *postcopy_get_tmp_page(MigrationIncomingState *mis, long bitmap_offset)
+{
+    ptrdiff_t offset;
+
+    if (!mis->postcopy_tmp_page) {
+        mis->postcopy_tmp_page = mmap(NULL, getpagesize(),
+                             PROT_READ | PROT_WRITE, MAP_PRIVATE |
+                             MAP_ANONYMOUS, -1, 0);
+        if (!mis->postcopy_tmp_page) {
+            perror("mapping postcopy tmp page");
+            return NULL;
+        }
+        if (madvise(mis->postcopy_tmp_page, getpagesize(), MADV_DONTFORK)) {
+            munmap(mis->postcopy_tmp_page, getpagesize());
+            perror("postcpy tmp page DONTFORK");
+            return NULL;
+        }
+    }
+
+    /*
+     * Get the offset within the host page based on bitmap_offset.
+     */
+    offset = (bitmap_offset & (mis->postcopy_pmi.host_bits - 1)) <<
+                 qemu_target_page_bits();
+
+    return (void *)((uint8_t *)mis->postcopy_tmp_page + offset);
+}
+
 #else
 /* No target OS support, stubs just fail */
 int postcopy_ram_hosttest(void)
@@ -598,6 +721,24 @@ int postcopy_ram_enable_notify(MigrationIncomingState *mis)
 {
     assert(0);
 }
+
+int postcopy_place_zero_page(MigrationIncomingState *mis, void *host,
+                             long bitmap_offset)
+{
+    assert(0);
+}
+
+int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from,
+                        long bitmap_offset)
+{
+    assert(0);
+}
+
+void *postcopy_get_tmp_page(MigrationIncomingState *mis, long bitmap_offset)
+{
+    assert(0);
+}
+
 #endif
 
 /* ------------------------------------------------------------------------- */
-- 
1.9.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]