diff mbox series

[3/4] migration: introduce ignore-external capability

Message ID 20190110120120.9943-4-yury-kotov@yandex-team.ru (mailing list archive)
State New, archived
Headers show
Series Add ignore-external migration capability | expand

Commit Message

Yury Kotov Jan. 10, 2019, 12:01 p.m. UTC
We want to use local migration to update QEMU for running guests.
In this case we don't need to migrate external RAM.
So, add a capability to ignore such blocks during live migration.

Signed-off-by: Yury Kotov <yury-kotov@yandex-team.ru>
---
 exec.c                    |  5 +++++
 include/exec/cpu-common.h |  1 +
 migration/migration.c     |  9 +++++++++
 migration/migration.h     |  1 +
 migration/ram.c           | 37 ++++++++++++++++++++++++++++++++++---
 qapi/migration.json       |  6 +++++-
 6 files changed, 55 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/exec.c b/exec.c
index ef2f29d7cb..3c3e42993f 100644
--- a/exec.c
+++ b/exec.c
@@ -2000,6 +2000,11 @@  void qemu_ram_unset_migratable(RAMBlock *rb)
     rb->flags &= ~RAM_MIGRATABLE;
 }
 
+bool qemu_ram_is_external(RAMBlock *rb)
+{
+    return rb->flags & RAM_EXTERNAL;
+}
+
 /* Called with iothread lock held.  */
 void qemu_ram_set_idstr(RAMBlock *new_block, const char *name, DeviceState *dev)
 {
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 2ad2d6d86b..57e84e5aa4 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -78,6 +78,7 @@  void qemu_ram_set_uf_zeroable(RAMBlock *rb);
 bool qemu_ram_is_migratable(RAMBlock *rb);
 void qemu_ram_set_migratable(RAMBlock *rb);
 void qemu_ram_unset_migratable(RAMBlock *rb);
+bool qemu_ram_is_external(RAMBlock *rb);
 
 size_t qemu_ram_pagesize(RAMBlock *block);
 size_t qemu_ram_pagesize_largest(void);
diff --git a/migration/migration.c b/migration/migration.c
index ffc4d9e556..9b789d3535 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1979,6 +1979,15 @@  bool migrate_dirty_bitmaps(void)
     return s->enabled_capabilities[MIGRATION_CAPABILITY_DIRTY_BITMAPS];
 }
 
+bool migrate_ignore_external(void)
+{
+    MigrationState *s;
+
+    s = migrate_get_current();
+
+    return s->enabled_capabilities[MIGRATION_CAPABILITY_X_IGNORE_EXTERNAL];
+}
+
 bool migrate_use_events(void)
 {
     MigrationState *s;
diff --git a/migration/migration.h b/migration/migration.h
index e413d4d8b6..06691242f3 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -255,6 +255,7 @@  bool migrate_release_ram(void);
 bool migrate_postcopy_ram(void);
 bool migrate_zero_blocks(void);
 bool migrate_dirty_bitmaps(void);
+bool migrate_ignore_external(void);
 
 bool migrate_auto_converge(void);
 bool migrate_use_multifd(void);
diff --git a/migration/ram.c b/migration/ram.c
index 39629254e1..0091a8ae3a 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -166,6 +166,11 @@  out:
 
 #undef RAMBLOCK_FOREACH
 
+static bool is_ignored_block(RAMBlock *block)
+{
+    return migrate_ignore_external() && qemu_ram_is_external(block);
+}
+
 static void ramblock_recv_map_init(void)
 {
     RAMBlock *rb;
@@ -1537,7 +1542,7 @@  unsigned long migration_bitmap_find_dirty(RAMState *rs, RAMBlock *rb,
     unsigned long *bitmap = rb->bmap;
     unsigned long next;
 
-    if (!qemu_ram_is_migratable(rb)) {
+    if (!qemu_ram_is_migratable(rb) || is_ignored_block(rb)) {
         return size;
     }
 
@@ -1651,6 +1656,9 @@  static void migration_bitmap_sync(RAMState *rs)
     qemu_mutex_lock(&rs->bitmap_mutex);
     rcu_read_lock();
     RAMBLOCK_FOREACH_MIGRATABLE(block) {
+        if (is_ignored_block(block)) {
+            continue;
+        }
         migration_bitmap_sync_range(rs, block, 0, block->used_length);
     }
     ram_counters.remaining = ram_bytes_remaining();
@@ -2472,19 +2480,27 @@  void acct_update_position(QEMUFile *f, size_t size, bool zero)
     }
 }
 
-uint64_t ram_bytes_total(void)
+static uint64_t ram_bytes_total_common(bool skip_ignored)
 {
     RAMBlock *block;
     uint64_t total = 0;
 
     rcu_read_lock();
     RAMBLOCK_FOREACH_MIGRATABLE(block) {
+        if (skip_ignored && is_ignored_block(block)) {
+            continue;
+        }
         total += block->used_length;
     }
     rcu_read_unlock();
     return total;
 }
 
+uint64_t ram_bytes_total(void)
+{
+    return ram_bytes_total_common(true);
+}
+
 static void xbzrle_load_setup(void)
 {
     XBZRLE.decoded_buf = g_malloc(TARGET_PAGE_SIZE);
@@ -3162,7 +3178,7 @@  static int ram_save_setup(QEMUFile *f, void *opaque)
 
     rcu_read_lock();
 
-    qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
+    qemu_put_be64(f, ram_bytes_total_common(false) | RAM_SAVE_FLAG_MEM_SIZE);
 
     RAMBLOCK_FOREACH_MIGRATABLE(block) {
         qemu_put_byte(f, strlen(block->idstr));
@@ -3172,6 +3188,7 @@  static int ram_save_setup(QEMUFile *f, void *opaque)
             qemu_put_be64(f, block->page_size);
         }
         qemu_put_be64(f, block->offset);
+        qemu_put_byte(f, is_ignored_block(block) ? 1 : 0);
     }
 
     rcu_read_unlock();
@@ -4135,13 +4152,27 @@  static int ram_load(QEMUFile *f, void *opaque, int version_id)
                     }
                     if (version_id >= 5) {
                         ram_addr_t offset;
+                        bool ignored;
                         offset = qemu_get_be64(f);
+                        ignored = qemu_get_byte(f);
                         if (block->offset != offset) {
                             error_report("Mismatched RAM block offset %s "
                                          "%" PRId64 "!= %" PRId64,
                                          id, offset, (uint64_t)block->offset);
                             ret = -EINVAL;
                         }
+                        if (ignored) {
+                            if (!migrate_ignore_external()) {
+                                error_report("Unexpected ignored RAM block %s: "
+                                             "ignore-external capability is "
+                                             "disabled", id);
+                                ret = -EINVAL;
+                            } else if (!qemu_ram_is_external(block)) {
+                                error_report("Only external RAM block %s "
+                                             "can be ignored", id);
+                                ret = -EINVAL;
+                            }
+                        }
                     }
                     ram_control_load_hook(f, RAM_CONTROL_BLOCK_REG,
                                           block->idstr);
diff --git a/qapi/migration.json b/qapi/migration.json
index 31b589ec26..10bbac87f8 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -406,13 +406,17 @@ 
 #           devices (and thus take locks) immediately at the end of migration.
 #           (since 3.0)
 #
+# @x-ignore-external: If enabled, QEMU will not migrate shared memory
+#                     (since 4.0)
+#
 # Since: 1.2
 ##
 { 'enum': 'MigrationCapability',
   'data': ['xbzrle', 'rdma-pin-all', 'auto-converge', 'zero-blocks',
            'compress', 'events', 'postcopy-ram', 'x-colo', 'release-ram',
            'block', 'return-path', 'pause-before-switchover', 'x-multifd',
-           'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate' ] }
+           'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate',
+           'x-ignore-external' ] }
 
 ##
 # @MigrationCapabilityStatus: