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 set 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 <nborisov@suse.com>
This commit is contained in:
Nikolay Borisov
2022-10-28 13:39:03 +03:00
committed by Fabiano Rosas
parent 3ce4e2e8d5
commit ea1efd3d17
3 changed files with 62 additions and 8 deletions

View File

@@ -2260,6 +2260,7 @@ void migrate_init(MigrationState *s)
error_free(s->error); error_free(s->error);
s->error = NULL; s->error = NULL;
s->hostname = NULL; s->hostname = NULL;
s->vmdesc = NULL;
migrate_set_state(&s->state, MIGRATION_STATUS_NONE, MIGRATION_STATUS_SETUP); migrate_set_state(&s->state, MIGRATION_STATUS_NONE, MIGRATION_STATUS_SETUP);

View File

@@ -1206,13 +1206,25 @@ void qemu_savevm_non_migratable_list(strList **reasons)
void qemu_savevm_state_header(QEMUFile *f) void qemu_savevm_state_header(QEMUFile *f)
{ {
MigrationState *s = migrate_get_current();
s->vmdesc = json_writer_new(false);
trace_savevm_state_header(); trace_savevm_state_header();
qemu_put_be32(f, QEMU_VM_FILE_MAGIC); qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
qemu_put_be32(f, QEMU_VM_FILE_VERSION); 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); 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);
} }
} }
@@ -1237,8 +1249,6 @@ void qemu_savevm_state_setup(QEMUFile *f)
Error *local_err = NULL; Error *local_err = NULL;
int ret; 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_int64(ms->vmdesc, "page_size", qemu_target_page_size());
json_writer_start_array(ms->vmdesc, "devices"); json_writer_start_array(ms->vmdesc, "devices");

View File

@@ -23,7 +23,7 @@ import argparse
import collections import collections
import struct import struct
import sys import sys
import math
def mkdir_p(path): def mkdir_p(path):
try: try:
@@ -119,11 +119,16 @@ class RamSection(object):
self.file = file self.file = file
self.section_key = section_key self.section_key = section_key
self.TARGET_PAGE_SIZE = ramargs['page_size'] self.TARGET_PAGE_SIZE = ramargs['page_size']
self.TARGET_PAGE_BITS = math.log2(self.TARGET_PAGE_SIZE)
self.dump_memory = ramargs['dump_memory'] self.dump_memory = ramargs['dump_memory']
self.write_memory = ramargs['write_memory'] self.write_memory = ramargs['write_memory']
self.fixed_ram = ramargs['fixed-ram']
self.sizeinfo = collections.OrderedDict() self.sizeinfo = collections.OrderedDict()
self.bitmap_offset = collections.OrderedDict()
self.pages_offset = collections.OrderedDict()
self.data = collections.OrderedDict() self.data = collections.OrderedDict()
self.data['section sizes'] = self.sizeinfo self.data['section sizes'] = self.sizeinfo
self.ram_read = False
self.name = '' self.name = ''
if self.write_memory: if self.write_memory:
self.files = { } self.files = { }
@@ -140,7 +145,13 @@ class RamSection(object):
def getDict(self): def getDict(self):
return self.data return self.data
def write_or_dump_fixed_ram(self):
pass
def read(self): def read(self):
if self.fixed_ram and self.ram_read:
return
# Read all RAM sections # Read all RAM sections
while True: while True:
addr = self.file.read64() addr = self.file.read64()
@@ -167,7 +178,26 @@ class RamSection(object):
f.truncate(0) f.truncate(0)
f.truncate(len) f.truncate(len)
self.files[self.name] = f 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 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_COMPRESS:
if flags & self.RAM_SAVE_FLAG_CONTINUE: if flags & self.RAM_SAVE_FLAG_CONTINUE:
@@ -208,7 +238,7 @@ class RamSection(object):
# End of RAM section # End of RAM section
if flags & self.RAM_SAVE_FLAG_EOS: if flags & self.RAM_SAVE_FLAG_EOS:
break return
if flags != 0: if flags != 0:
raise Exception("Unknown RAM flags: %x" % flags) raise Exception("Unknown RAM flags: %x" % flags)
@@ -521,6 +551,7 @@ class MigrationDump(object):
ramargs['page_size'] = self.vmsd_desc['page_size'] ramargs['page_size'] = self.vmsd_desc['page_size']
ramargs['dump_memory'] = dump_memory ramargs['dump_memory'] = dump_memory
ramargs['write_memory'] = write_memory ramargs['write_memory'] = write_memory
ramargs['fixed-ram'] = False
self.section_classes[('ram',0)][1] = ramargs self.section_classes[('ram',0)][1] = ramargs
while True: while True:
@@ -528,8 +559,20 @@ class MigrationDump(object):
if section_type == self.QEMU_VM_EOF: if section_type == self.QEMU_VM_EOF:
break break
elif section_type == self.QEMU_VM_CONFIGURATION: elif section_type == self.QEMU_VM_CONFIGURATION:
section = ConfigurationSection(file) config_desc = self.vmsd_desc.get('configuration')
section.read() 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: elif section_type == self.QEMU_VM_SECTION_START or section_type == self.QEMU_VM_SECTION_FULL:
section_id = file.read32() section_id = file.read32()
name = file.readstr() name = file.readstr()