qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH qemu] migration/ram: support resize of option rom


From: ~tianren
Subject: [PATCH qemu] migration/ram: support resize of option rom
Date: Mon, 05 Dec 2022 22:49:22 -0500

From: Tianren Zhang <tianren@smartx.com>

The pci option rom is a RAMBlock mapped from a rom file,
but in some cases of migration, the src and dest machine
may have rom files with different size, which causes the
migration to fail due to mismatch of RAMBlock size.

In those cases, we could make the migration more compatible
by initializing the RAMBlock of the option rom as resizeable.
When a guest with a smaller option rom size(e.g. 72k) is
migrated to the dest started with larger rom size(e.g. 256k),
the resize is totally feasible on the dest qemu because 72K
of incoming RAMBlock < local 256K RAMBlock for the option rom.

Signed-off-by: Tianren Zhang <tianren@smartx.com>
---
 hw/pci/pci.c          | 26 ++++++++++++++++++++++++-
 include/exec/memory.h | 25 ++++++++++++++++++++++++
 softmmu/memory.c      | 45 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+), 1 deletion(-)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 2f450f6a72..4a662e1d9a 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2407,6 +2407,30 @@ static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, 
uint32_t size)
     }
 }
 
+/*
+ * This is a hook function which is called when the RAMBlock of a option rom
+ * is resized by QEMU in a live migration. For option rom, since the PCI bar
+ * is registered based on the size of ROM MemoryRegion, after a resize is done
+ * on this ROM MemoryRegion, we should re-register its PCI bar based on the new
+ * size.
+ */
+static void pci_option_rom_resized(const char* id, uint64_t length, void 
*host) {
+    MemoryRegion *mr = memory_region_from_ramblock_id(id);
+    if (mr == NULL) {
+        // The failure to react the resize may cause the later check for
+        // PCI config to fail in the migration, so the migration may fail,
+        // but will not affect the src VM.
+        error_report("failed to find the block %s\n", id);
+        return;
+    }
+
+    PCIDevice *pdev = (PCIDevice *)DEVICE(mr->owner);
+    fprintf(stdout, "block id: %s resized to 0x" RAM_ADDR_FMT \
+            ", re-register pci bar for device: %s\n", id, length, pdev->name);
+
+    pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom);
+}
+
 /* Add an option rom for the device */
 static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom,
                                Error **errp)
@@ -2486,7 +2510,7 @@ static void pci_add_option_rom(PCIDevice *pdev, bool 
is_default_rom,
         snprintf(name, sizeof(name), "%s.rom", 
object_get_typename(OBJECT(pdev)));
     }
     pdev->has_rom = true;
-    memory_region_init_rom(&pdev->rom, OBJECT(pdev), name, pdev->romsize, 
&error_fatal);
+    memory_region_init_resizeable_rom(&pdev->rom, OBJECT(pdev), name, 
pdev->romsize, pdev->romsize, pci_option_rom_resized, &error_fatal);
     ptr = memory_region_get_ram_ptr(&pdev->rom);
     if (load_image_size(path, ptr, size) < 0) {
         error_setg(errp, "failed to load romfile \"%s\"", pdev->romfile);
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 91f8a2395a..531d3bb6ef 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -1276,6 +1276,29 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr,
                                                        uint64_t length,
                                                        void *host),
                                        Error **errp);
+
+/*
+ * memory_region_init_resizeable_rom:  Initialize memory region with resizeable
+ *                                     ROM.
+ * @mr: the #MemoryRegion to be initialized.
+ * @owner: the object that tracks the region's reference count
+ * @name: Region name, becomes part of RAMBlock name used in migration stream
+ *        must be unique within any device
+ * @size: used size of the region.
+ * @max_size: max size of the region.
+ * @resized: callback to notify owner about used size change.
+ * @errp: pointer to Error*, to store an error if it happens.
+ */
+void memory_region_init_resizeable_rom(MemoryRegion *mr,
+                                       struct Object *owner,
+                                       const char *name,
+                                       uint64_t size,
+                                       uint64_t max_size,
+                                       void (*resized)(const char*,
+                                                       uint64_t length,
+                                                       void *host),
+                                       Error **errp);
+
 #ifdef CONFIG_POSIX
 
 /**
@@ -2820,6 +2843,8 @@ MemTxResult 
address_space_write_cached_slow(MemoryRegionCache *cache,
 int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr);
 bool prepare_mmio_access(MemoryRegion *mr);
 
+MemoryRegion *memory_region_from_ramblock_id(const char *id);
+
 static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
 {
     if (is_write) {
diff --git a/softmmu/memory.c b/softmmu/memory.c
index bc0be3f62c..0f69ed320b 100644
--- a/softmmu/memory.c
+++ b/softmmu/memory.c
@@ -2399,6 +2399,18 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr)
     return ptr;
 }
 
+MemoryRegion *memory_region_from_ramblock_id(const char *id)
+{
+    RAMBlock *block = qemu_ram_block_by_name(id);
+
+    if (!block) {
+        return NULL;
+    }
+
+    return block->mr;
+}
+
+
 MemoryRegion *memory_region_from_host(void *ptr, ram_addr_t *offset)
 {
     RAMBlock *block;
@@ -3550,6 +3562,39 @@ void memory_region_init_ram(MemoryRegion *mr,
     vmstate_register_ram(mr, owner_dev);
 }
 
+void memory_region_init_resizeable_rom(MemoryRegion *mr,
+                                       struct Object *owner,
+                                       const char *name,
+                                       uint64_t size,
+                                       uint64_t max_size,
+                                       void (*resized)(const char*,
+                                                       uint64_t length,
+                                                       void *host),
+                                       Error **errp)
+{
+    DeviceState *owner_dev;
+    Error *err = NULL;
+
+    memory_region_init(mr, owner, name, size);
+    mr->ram = true;
+    mr->terminates = true;
+    mr->destructor = memory_region_destructor_ram;
+    mr->ram_block = qemu_ram_alloc_resizeable(size, max_size, resized,
+                                              mr, &err);
+    mr->readonly = true;
+
+    if (err) {
+        mr->size = int128_zero();
+        object_unparent(OBJECT(mr));
+        error_propagate(errp, err);
+        return;
+    }
+
+    owner_dev = DEVICE(owner);
+    vmstate_register_ram(mr, owner_dev);
+}
+
+
 void memory_region_init_rom(MemoryRegion *mr,
                             Object *owner,
                             const char *name,
-- 
2.34.5



reply via email to

[Prev in Thread] Current Thread [Next in Thread]