Patchwork [v3,14/35] arch_init: refactor ram_save_block() and export ram_save_block()

login
register
mail settings
Submitter Isaku Yamahata
Date Oct. 30, 2012, 8:32 a.m.
Message ID <9588c5b9666a4eab6a844fa3a1e50d08c1d4ef81.1351582535.git.yamahata@valinux.co.jp>
Download mbox | patch
Permalink /patch/195415/
State New
Headers show

Comments

Isaku Yamahata - Oct. 30, 2012, 8:32 a.m.
arch_init: factor out counting transferred bytes.
This will be used by postcopy.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
Changes v2 -> v3:
- manual rebase
- report ram_save_block

Chnages v1 -> v2:
- don't refer last_block which can be NULL.
  And avoid possible infinite loop.
---
 arch_init.c |  122 +++++++++++++++++++++++++++++++----------------------------
 arch_init.h |    5 +++
 migration.h |    1 +
 3 files changed, 70 insertions(+), 58 deletions(-)

Patch

diff --git a/arch_init.c b/arch_init.c
index 23717d3..ad1b01b 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -399,59 +399,77 @@  static void migration_bitmap_sync(void)
     }
 }
 
+static uint64_t bytes_transferred;
+
+/*
+ * ram_save_page: Writes a page of memory to the stream f
+ *
+ * Returns:  true:  page written
+ *           false: no page written
+ */
+static const RAMBlock *last_sent_block = NULL;
+bool ram_save_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
+                   bool last_stage)
+{
+    MemoryRegion *mr = block->mr;
+    uint8_t *p;
+    int cont;
+    int bytes_sent = -1;
+    ram_addr_t current_addr;
+
+    if (!migration_bitmap_test_and_reset_dirty(mr, offset)) {
+        return false;
+    }
+
+    cont = (block == last_sent_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
+    last_sent_block = block;
+    p = memory_region_get_ram_ptr(mr) + offset;
+    if (is_dup_page(p)) {
+        acct_info.dup_pages++;
+        save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS);
+        qemu_put_byte(f, *p);
+        bytes_sent = 1;
+    } else if (migrate_use_xbzrle()) {
+        current_addr = block->offset + offset;
+        bytes_sent = save_xbzrle_page(f, p, current_addr, block,
+                                      offset, cont, last_stage);
+        if (!last_stage) {
+            p = get_cached_data(XBZRLE.cache, current_addr);
+        }
+    }
+
+    /* either we didn't send yet (we may have had XBZRLE overflow) */
+    if (bytes_sent == -1) {
+        save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
+        qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
+        bytes_sent = TARGET_PAGE_SIZE;
+        acct_info.norm_pages++;
+    }
+
+    bytes_transferred += bytes_sent;
+    return true;
+}
+
 /*
  * ram_save_block: Writes a page of memory to the stream f
  *
- * Returns:  0: if the page hasn't changed
- *          -1: if there are no more dirty pages
- *           n: the amount of bytes written in other case
+ * Returns: true:  there may be more dirty pages
+ *          false: if there are no more dirty pages
  */
 
-static int ram_save_block(QEMUFile *f, bool last_stage)
+bool ram_save_block(QEMUFile *f, bool last_stage)
 {
     RAMBlock *block = last_block;
     ram_addr_t offset = last_offset;
-    int bytes_sent = -1;
-    MemoryRegion *mr;
-    ram_addr_t current_addr;
+    bool wrote = false;
 
     if (!block)
         block = QLIST_FIRST(&ram_list.blocks);
 
     do {
-        mr = block->mr;
-        if (migration_bitmap_test_and_reset_dirty(mr, offset)) {
-            uint8_t *p;
-            int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
-
-            p = memory_region_get_ram_ptr(mr) + offset;
-
-            if (is_dup_page(p)) {
-                acct_info.dup_pages++;
-                save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS);
-                qemu_put_byte(f, *p);
-                bytes_sent = 1;
-            } else if (migrate_use_xbzrle()) {
-                current_addr = block->offset + offset;
-                bytes_sent = save_xbzrle_page(f, p, current_addr, block,
-                                              offset, cont, last_stage);
-                if (!last_stage) {
-                    p = get_cached_data(XBZRLE.cache, current_addr);
-                }
-            }
-
-            /* either we didn't send yet (we may have had XBZRLE overflow) */
-            if (bytes_sent == -1) {
-                save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
-                qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
-                bytes_sent = TARGET_PAGE_SIZE;
-                acct_info.norm_pages++;
-            }
-
-            /* if page is unmodified, continue to the next */
-            if (bytes_sent != 0) {
-                break;
-            }
+        wrote = ram_save_page(f, block, offset, last_stage);
+        if (wrote) {
+            break;
         }
 
         offset += TARGET_PAGE_SIZE;
@@ -466,11 +484,9 @@  static int ram_save_block(QEMUFile *f, bool last_stage)
     last_block = block;
     last_offset = offset;
 
-    return bytes_sent;
+    return wrote;
 }
 
-static uint64_t bytes_transferred;
-
 static ram_addr_t ram_save_remaining(void)
 {
     return migration_dirty_pages;
@@ -547,6 +563,7 @@  static void ram_migration_cancel(void *opaque)
 
 static void reset_ram_globals(void)
 {
+    last_sent_block = NULL;
     last_block = NULL;
     last_offset = 0;
     last_version = ram_list.version;
@@ -618,14 +635,10 @@  static int ram_save_iterate(QEMUFile *f, void *opaque)
 
     i = 0;
     while ((ret = qemu_file_rate_limit(f)) == 0) {
-        int bytes_sent;
-
-        bytes_sent = ram_save_block(f, false);
-        /* no more blocks to sent */
-        if (bytes_sent < 0) {
+        if (!ram_save_block(f, false)) {
+            /* no more blocks to sent */
             break;
         }
-        bytes_transferred += bytes_sent;
         acct_info.iterations++;
         /* we want to check in the 1st loop, just in case it was the 1st time
            and we had to sync the dirty bitmap.
@@ -683,15 +696,8 @@  static int ram_save_complete(QEMUFile *f, void *opaque)
     /* try transferring iterative blocks of memory */
 
     /* flush all remaining blocks regardless of rate limiting */
-    while (true) {
-        int bytes_sent;
-
-        bytes_sent = ram_save_block(f, true);
-        /* no more blocks to sent */
-        if (bytes_sent < 0) {
-            break;
-        }
-        bytes_transferred += bytes_sent;
+    while (!ram_save_block(f, true)) {
+        /* nothing */
     }
     memory_global_dirty_log_stop();
 
diff --git a/arch_init.h b/arch_init.h
index 780eedf..f2a7ae5 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -46,4 +46,9 @@  CpuDefinitionInfoList GCC_WEAK_DECL *arch_query_cpu_definitions(Error **errp);
 
 #define RAM_SAVE_VERSION_ID     4 /* currently version 4 */
 
+#if defined(NEED_CPU_H) && !defined(CONFIG_USER_ONLY)
+bool ram_save_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
+                   bool last_stage);
+#endif
+
 #endif
diff --git a/migration.h b/migration.h
index 1c3e9b7..7d1b62d 100644
--- a/migration.h
+++ b/migration.h
@@ -91,6 +91,7 @@  bool migration_has_finished(MigrationState *);
 bool migration_has_failed(MigrationState *);
 MigrationState *migrate_get_current(void);
 
+bool ram_save_block(QEMUFile *f, bool last_stage);
 uint64_t ram_bytes_remaining(void);
 uint64_t ram_bytes_transferred(void);
 uint64_t ram_bytes_total(void);