mirror of
https://github.com/qemu/qemu.git
synced 2026-02-04 02:24:38 +00:00
scripts/analyze-migration: Support mapped-ram snapshot format
The script has not been updated to read mapped-ram snapshots and is currently
crashing when trying to read such a file.
With this commit, it can now read a snapshot created with:
(qemu) migrate_set_capability x-ignore-shared on
(qemu) migrate_set_capability mapped-ram on
(qemu) migrate -d file:vm.state
Signed-off-by: Pawel Zmarzly <pzmarzly0@gmail.com>
Link: https://lore.kernel.org/r/20251126155015.941129-1-pzmarzly0@gmail.com
[peterx: space fixes, introduce parseMappedRamBlob(), add comments, etc.]
Signed-off-by: Peter Xu <peterx@redhat.com>
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import math
|
||||||
import argparse
|
import argparse
|
||||||
import collections
|
import collections
|
||||||
import struct
|
import struct
|
||||||
@@ -127,6 +128,7 @@ class RamSection(object):
|
|||||||
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.ignore_shared = ramargs['ignore_shared']
|
self.ignore_shared = ramargs['ignore_shared']
|
||||||
|
self.mapped_ram = ramargs['mapped_ram']
|
||||||
self.sizeinfo = collections.OrderedDict()
|
self.sizeinfo = collections.OrderedDict()
|
||||||
self.data = collections.OrderedDict()
|
self.data = collections.OrderedDict()
|
||||||
self.data['section sizes'] = self.sizeinfo
|
self.data['section sizes'] = self.sizeinfo
|
||||||
@@ -146,6 +148,57 @@ class RamSection(object):
|
|||||||
def getDict(self):
|
def getDict(self):
|
||||||
return self.data
|
return self.data
|
||||||
|
|
||||||
|
def parseMappedRamBlob(self, len):
|
||||||
|
version = self.file.read32()
|
||||||
|
if version != 1:
|
||||||
|
raise Exception("Unsupported MappedRamHeader version %s" % version)
|
||||||
|
|
||||||
|
page_size = self.file.read64()
|
||||||
|
if page_size != self.TARGET_PAGE_SIZE:
|
||||||
|
raise Exception("Page size mismatch in MappedRamHeader")
|
||||||
|
|
||||||
|
bitmap_offset = self.file.read64()
|
||||||
|
pages_offset = self.file.read64()
|
||||||
|
|
||||||
|
if self.ignore_shared and bitmap_offset == 0 and pages_offset == 0:
|
||||||
|
# This is a shared ramblock, x-ignore-share must have been
|
||||||
|
# enabled, and mapped-ram didn't allocate bitmap or page blob
|
||||||
|
# for it.
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.dump_memory or self.write_memory:
|
||||||
|
num_pages = len // page_size
|
||||||
|
|
||||||
|
self.file.seek(bitmap_offset, os.SEEK_SET)
|
||||||
|
bitmap_len = int(math.ceil(num_pages / 8))
|
||||||
|
bitmap = self.file.readvar(size=bitmap_len)
|
||||||
|
|
||||||
|
self.file.seek(pages_offset, os.SEEK_SET)
|
||||||
|
for page_num in range(num_pages):
|
||||||
|
page_addr = page_num * page_size
|
||||||
|
|
||||||
|
is_filled = (bitmap[page_num // 8] >> page_num % 8) & 1
|
||||||
|
if is_filled:
|
||||||
|
data = self.file.readvar(size=self.TARGET_PAGE_SIZE)
|
||||||
|
if self.write_memory:
|
||||||
|
self.files[self.name].seek(page_addr, os.SEEK_SET)
|
||||||
|
self.files[self.name].write(data)
|
||||||
|
if self.dump_memory:
|
||||||
|
hexdata = " ".join("{0:02x}".format(c) for c in data)
|
||||||
|
self.memory['%s (0x%016x)' %
|
||||||
|
(self.name, page_addr)] = hexdata
|
||||||
|
else:
|
||||||
|
self.file.seek(self.TARGET_PAGE_SIZE, os.SEEK_CUR)
|
||||||
|
if self.write_memory:
|
||||||
|
self.files[self.name].seek(page_addr, os.SEEK_SET)
|
||||||
|
self.files[self.name].write(
|
||||||
|
b'\x00' * self.TARGET_PAGE_SIZE)
|
||||||
|
if self.dump_memory:
|
||||||
|
self.memory['%s (0x%016x)' %
|
||||||
|
(self.name, page_addr)] = 'Filled with 0x00'
|
||||||
|
|
||||||
|
self.file.seek(pages_offset + len, os.SEEK_SET)
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
# Read all RAM sections
|
# Read all RAM sections
|
||||||
while True:
|
while True:
|
||||||
@@ -170,6 +223,8 @@ class RamSection(object):
|
|||||||
self.files[self.name] = f
|
self.files[self.name] = f
|
||||||
if self.ignore_shared:
|
if self.ignore_shared:
|
||||||
mr_addr = self.file.read64()
|
mr_addr = self.file.read64()
|
||||||
|
if self.mapped_ram:
|
||||||
|
self.parseMappedRamBlob(len)
|
||||||
flags &= ~self.RAM_SAVE_FLAG_MEM_SIZE
|
flags &= ~self.RAM_SAVE_FLAG_MEM_SIZE
|
||||||
|
|
||||||
if flags & self.RAM_SAVE_FLAG_ZERO:
|
if flags & self.RAM_SAVE_FLAG_ZERO:
|
||||||
@@ -660,6 +715,7 @@ class MigrationDump(object):
|
|||||||
ramargs['dump_memory'] = dump_memory
|
ramargs['dump_memory'] = dump_memory
|
||||||
ramargs['write_memory'] = write_memory
|
ramargs['write_memory'] = write_memory
|
||||||
ramargs['ignore_shared'] = False
|
ramargs['ignore_shared'] = False
|
||||||
|
ramargs['mapped_ram'] = False
|
||||||
self.section_classes[('ram',0)][1] = ramargs
|
self.section_classes[('ram',0)][1] = ramargs
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@@ -671,6 +727,7 @@ class MigrationDump(object):
|
|||||||
section = ConfigurationSection(file, config_desc)
|
section = ConfigurationSection(file, config_desc)
|
||||||
section.read()
|
section.read()
|
||||||
ramargs['ignore_shared'] = section.has_capability('x-ignore-shared')
|
ramargs['ignore_shared'] = section.has_capability('x-ignore-shared')
|
||||||
|
ramargs['mapped_ram'] = section.has_capability('mapped-ram')
|
||||||
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()
|
||||||
|
|||||||
Reference in New Issue
Block a user