From ec13463af48d5b0e2014f67d68376c5e4f109607 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Fri, 28 Oct 2022 13:39:03 +0300 Subject: [PATCH] migration: Initial support of fixed-ram feature for analyze-migration.py In order to allow analyze-migration.py script to work with migration streams that have the 'fixed-ram' capability, it's required to have access to the stream's configuration object. This commit enables this by making migration json writer part of MigrationState struct, allowing the configuration object be serialized to json. Signed-off-by: Nikolay Borisov Signed-off-by: Fabiano Rosas --- migration/migration.c | 1 + migration/savevm.c | 18 ++++++++++--- scripts/analyze-migration.py | 51 +++++++++++++++++++++++++++++++++--- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 124d9f9e64..d2dfc5d5c3 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1397,6 +1397,7 @@ void migrate_init(MigrationState *s) error_free(s->error); s->error = NULL; s->hostname = NULL; + s->vmdesc = NULL; migrate_set_state(&s->state, MIGRATION_STATUS_NONE, MIGRATION_STATUS_SETUP); diff --git a/migration/savevm.c b/migration/savevm.c index 032044b1d5..bc6f047025 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1209,13 +1209,25 @@ void qemu_savevm_non_migratable_list(strList **reasons) void qemu_savevm_state_header(QEMUFile *f) { + MigrationState *s = migrate_get_current(); + + s->vmdesc = json_writer_new(false); + trace_savevm_state_header(); qemu_put_be32(f, QEMU_VM_FILE_MAGIC); qemu_put_be32(f, QEMU_VM_FILE_VERSION); - if (migrate_get_current()->send_configuration) { + if (s->send_configuration) { qemu_put_byte(f, QEMU_VM_CONFIGURATION); - vmstate_save_state(f, &vmstate_configuration, &savevm_state, 0); + /* + * This starts the main json object and is paired with the + * json_writer_end_object in + * qemu_savevm_state_complete_precopy_non_iterable + */ + json_writer_start_object(s->vmdesc, NULL); + json_writer_start_object(s->vmdesc, "configuration"); + vmstate_save_state(f, &vmstate_configuration, &savevm_state, s->vmdesc); + json_writer_end_object(s->vmdesc); } } @@ -1240,8 +1252,6 @@ void qemu_savevm_state_setup(QEMUFile *f) Error *local_err = NULL; int ret; - ms->vmdesc = json_writer_new(false); - json_writer_start_object(ms->vmdesc, NULL); json_writer_int64(ms->vmdesc, "page_size", qemu_target_page_size()); json_writer_start_array(ms->vmdesc, "devices"); diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index b82a1b0c58..05af9efd2f 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -23,7 +23,7 @@ import argparse import collections import struct import sys - +import math def mkdir_p(path): try: @@ -119,11 +119,16 @@ class RamSection(object): self.file = file self.section_key = section_key self.TARGET_PAGE_SIZE = ramargs['page_size'] + self.TARGET_PAGE_BITS = math.log2(self.TARGET_PAGE_SIZE) self.dump_memory = ramargs['dump_memory'] self.write_memory = ramargs['write_memory'] + self.fixed_ram = ramargs['fixed-ram'] self.sizeinfo = collections.OrderedDict() + self.bitmap_offset = collections.OrderedDict() + self.pages_offset = collections.OrderedDict() self.data = collections.OrderedDict() self.data['section sizes'] = self.sizeinfo + self.ram_read = False self.name = '' if self.write_memory: self.files = { } @@ -140,7 +145,13 @@ class RamSection(object): def getDict(self): return self.data + def write_or_dump_fixed_ram(self): + pass + def read(self): + if self.fixed_ram and self.ram_read: + return + # Read all RAM sections while True: addr = self.file.read64() @@ -167,7 +178,26 @@ class RamSection(object): f.truncate(0) f.truncate(len) self.files[self.name] = f + + if self.fixed_ram: + bitmap_len = self.file.read32() + # skip the pages_offset which we don't need + offset = self.file.tell() + 8 + self.bitmap_offset[self.name] = offset + offset = ((offset + bitmap_len + self.TARGET_PAGE_SIZE - 1) // + self.TARGET_PAGE_SIZE) * self.TARGET_PAGE_SIZE + self.pages_offset[self.name] = offset + self.file.file.seek(offset + len) + flags &= ~self.RAM_SAVE_FLAG_MEM_SIZE + if self.fixed_ram: + self.ram_read = True + # now we should rewind to the ram page offset of the first + # ram section + if self.fixed_ram: + if self.write_memory or self.dump_memory: + self.write_or_dump_fixed_ram() + return if flags & self.RAM_SAVE_FLAG_COMPRESS: if flags & self.RAM_SAVE_FLAG_CONTINUE: @@ -208,7 +238,7 @@ class RamSection(object): # End of RAM section if flags & self.RAM_SAVE_FLAG_EOS: - break + return if flags != 0: raise Exception("Unknown RAM flags: %x" % flags) @@ -521,6 +551,7 @@ class MigrationDump(object): ramargs['page_size'] = self.vmsd_desc['page_size'] ramargs['dump_memory'] = dump_memory ramargs['write_memory'] = write_memory + ramargs['fixed-ram'] = False self.section_classes[('ram',0)][1] = ramargs while True: @@ -528,8 +559,20 @@ class MigrationDump(object): if section_type == self.QEMU_VM_EOF: break elif section_type == self.QEMU_VM_CONFIGURATION: - section = ConfigurationSection(file) - section.read() + config_desc = self.vmsd_desc.get('configuration') + if config_desc is not None: + config = VMSDSection(file, 1, config_desc, 'configuration') + config.read() + caps = config.data.get("configuration/capabilities") + if caps is not None: + caps = caps.data["capabilities"] + if type(caps) != list: + caps = [caps] + for i in caps: + # chomp out string length + cap = i.data[1:].decode("utf8") + if cap == "fixed-ram": + ramargs['fixed-ram'] = True elif section_type == self.QEMU_VM_SECTION_START or section_type == self.QEMU_VM_SECTION_FULL: section_id = file.read32() name = file.readstr()