]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: migration_cookie: Add XML handling for setting up bitmap migration
authorPeter Krempa <pkrempa@redhat.com>
Mon, 8 Feb 2021 10:12:35 +0000 (11:12 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Sat, 20 Feb 2021 12:21:21 +0000 (13:21 +0100)
In cases where we are copying the storage we need to ensure that also
bitmaps are copied properly. This patch adds migration cookie XML
infrastructure which will allow the migration sides reach consensus on
which bitmaps to migrate.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
src/qemu/qemu_migration_cookie.c
src/qemu/qemu_migration_cookie.h

index 6f2b1b2f57c13f324fb36675d8d0457ae72d6e33..0f8555cbb013fa606dc234df26f62a2f8ff5d74c 100644 (file)
@@ -51,6 +51,7 @@ VIR_ENUM_IMPL(qemuMigrationCookieFlag,
               "cpu",
               "allowReboot",
               "capabilities",
+              "block-dirty-bitmaps",
 );
 
 
@@ -116,6 +117,39 @@ qemuMigrationCookieCapsFree(qemuMigrationCookieCapsPtr caps)
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMigrationCookieCaps,
                               qemuMigrationCookieCapsFree);
 
+static void
+qemuMigrationBlockDirtyBitmapsDiskBitmapFree(qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bmp)
+{
+    if (!bmp)
+        return;
+
+    g_free(bmp->bitmapname);
+    g_free(bmp->alias);
+    g_free(bmp->sourcebitmap);
+    g_free(bmp);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMigrationBlockDirtyBitmapsDiskBitmap,
+                              qemuMigrationBlockDirtyBitmapsDiskBitmapFree);
+
+
+static void
+qemuMigrationBlockDirtyBitmapsDiskFree(qemuMigrationBlockDirtyBitmapsDiskPtr dsk)
+{
+    if (!dsk)
+        return;
+
+    g_free(dsk->target);
+    if (dsk->bitmaps)
+        g_slist_free_full(dsk->bitmaps,
+                          (GDestroyNotify) qemuMigrationBlockDirtyBitmapsDiskBitmapFree);
+    g_free(dsk);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMigrationBlockDirtyBitmapsDisk,
+                              qemuMigrationBlockDirtyBitmapsDiskFree);
+
+
 void
 qemuMigrationCookieFree(qemuMigrationCookiePtr mig)
 {
@@ -135,6 +169,9 @@ qemuMigrationCookieFree(qemuMigrationCookiePtr mig)
     g_clear_pointer(&mig->jobInfo, qemuDomainJobInfoFree);
     virCPUDefFree(mig->cpu);
     qemuMigrationCookieCapsFree(mig->caps);
+    if (mig->blockDirtyBitmaps)
+        g_slist_free_full(mig->blockDirtyBitmaps,
+                          (GDestroyNotify) qemuMigrationBlockDirtyBitmapsDiskFree);
     g_free(mig);
 }
 
@@ -758,6 +795,48 @@ qemuMigrationCookieNBDXMLFormat(qemuMigrationCookieNBDPtr nbd,
 }
 
 
+static void
+qemuMigrationCookieBlockDirtyBitmapsFormat(virBufferPtr buf,
+                                           GSList *bitmaps)
+{
+    g_auto(virBuffer) disksBuf = VIR_BUFFER_INIT_CHILD(buf);
+    GSList *nextdisk;
+
+    for (nextdisk = bitmaps; nextdisk; nextdisk = nextdisk->next) {
+        qemuMigrationBlockDirtyBitmapsDiskPtr disk = nextdisk->data;
+        g_auto(virBuffer) diskAttrBuf = VIR_BUFFER_INITIALIZER;
+        g_auto(virBuffer) diskChildBuf = VIR_BUFFER_INIT_CHILD(&disksBuf);
+        bool hasBitmaps = false;
+        GSList *nextbitmap;
+
+        if (disk->skip || !disk->bitmaps)
+            continue;
+
+        for (nextbitmap = disk->bitmaps; nextbitmap; nextbitmap = nextbitmap->next) {
+            qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap = nextbitmap->data;
+
+            if (bitmap->skip)
+                continue;
+
+            virBufferAsprintf(&diskChildBuf,
+                              "<bitmap name='%s' alias='%s'/>\n",
+                              bitmap->bitmapname, bitmap->alias);
+
+            hasBitmaps = true;
+        }
+
+        if (!hasBitmaps)
+            continue;
+
+        virBufferAsprintf(&diskAttrBuf, " target='%s'", disk->target);
+        virXMLFormatElement(&disksBuf, "disk", &diskAttrBuf, &diskChildBuf);
+    }
+
+
+    virXMLFormatElement(buf, "blockDirtyBitmaps", NULL, &disksBuf);
+}
+
+
 int
 qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver,
                              virQEMUCapsPtr qemuCaps,
@@ -829,6 +908,9 @@ qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver,
     if (mig->flags & QEMU_MIGRATION_COOKIE_CAPS)
         qemuMigrationCookieCapsXMLFormat(buf, mig->caps);
 
+    if (mig->flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS)
+        qemuMigrationCookieBlockDirtyBitmapsFormat(buf, mig->blockDirtyBitmaps);
+
     virBufferAdjustIndent(buf, -2);
     virBufferAddLit(buf, "</qemu-migration>\n");
     return 0;
@@ -1132,6 +1214,65 @@ qemuMigrationCookieXMLParseMandatoryFeatures(xmlXPathContextPtr ctxt,
 }
 
 
+static int
+qemuMigrationCookieBlockDirtyBitmapsParse(xmlXPathContextPtr ctxt,
+                                          qemuMigrationCookiePtr mig)
+{
+    g_autoslist(qemuMigrationBlockDirtyBitmapsDisk) disks = NULL;
+    g_autofree xmlNodePtr *disknodes = NULL;
+    int ndisknodes;
+    size_t i;
+    VIR_XPATH_NODE_AUTORESTORE(ctxt)
+
+    if ((ndisknodes = virXPathNodeSet("./blockDirtyBitmaps/disk", ctxt, &disknodes)) < 0)
+        return -1;
+
+    for (i = 0; i < ndisknodes; i++) {
+        g_autoslist(qemuMigrationBlockDirtyBitmapsDiskBitmap) bitmaps = NULL;
+        qemuMigrationBlockDirtyBitmapsDiskPtr disk;
+        g_autofree xmlNodePtr *bitmapnodes = NULL;
+        int nbitmapnodes;
+        size_t j;
+
+        ctxt->node = disknodes[i];
+
+        if ((nbitmapnodes = virXPathNodeSet("./bitmap", ctxt, &bitmapnodes)) < 0)
+            return -1;
+
+        for (j = 0; j < nbitmapnodes; j++) {
+            qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap;
+
+            bitmap = g_new0(qemuMigrationBlockDirtyBitmapsDiskBitmap, 1);
+            bitmap->bitmapname = virXMLPropString(bitmapnodes[j], "name");
+            bitmap->alias = virXMLPropString(bitmapnodes[j], "alias");
+            bitmaps = g_slist_prepend(bitmaps, bitmap);
+
+            if (!bitmap->bitmapname || !bitmap->alias) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("malformed <blockDirtyBitmaps> in migration cookie"));
+                return -1;
+            }
+        }
+
+        disk = g_new0(qemuMigrationBlockDirtyBitmapsDisk, 1);
+        disk->target = virXMLPropString(disknodes[i], "target");
+        disk->bitmaps = g_slist_reverse(g_steal_pointer(&bitmaps));
+
+        disks = g_slist_prepend(disks, disk);
+
+        if (!disk->target) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("malformed <blockDirtyBitmaps> in migration cookie"));
+            return -1;
+        }
+    }
+
+    mig->blockDirtyBitmaps = g_slist_reverse(g_steal_pointer(&disks));
+
+    return 0;
+}
+
+
 static int
 qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig,
                             virQEMUDriverPtr driver,
@@ -1275,6 +1416,11 @@ qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig,
         !(mig->caps = qemuMigrationCookieCapsXMLParse(ctxt)))
         return -1;
 
+    if (flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS &&
+        virXPathBoolean("boolean(./blockDirtyBitmaps)", ctxt) &&
+        qemuMigrationCookieBlockDirtyBitmapsParse(ctxt, mig) < 0)
+        return -1;
+
     return 0;
 }
 
index ecd1a01375a40c0d858cb741860119de4f6b5cda..8636f955dadb318a562ee5ed1d2d30f03aa1a859 100644 (file)
@@ -35,6 +35,7 @@ typedef enum {
     QEMU_MIGRATION_COOKIE_FLAG_CPU,
     QEMU_MIGRATION_COOKIE_FLAG_ALLOW_REBOOT,
     QEMU_MIGRATION_COOKIE_FLAG_CAPS,
+    QEMU_MIGRATION_COOKIE_FLAG_BLOCK_DIRTY_BITMAPS,
 
     QEMU_MIGRATION_COOKIE_FLAG_LAST
 } qemuMigrationCookieFlags;
@@ -53,6 +54,7 @@ typedef enum {
     QEMU_MIGRATION_COOKIE_CPU = (1 << QEMU_MIGRATION_COOKIE_FLAG_CPU),
     QEMU_MIGRATION_COOKIE_ALLOW_REBOOT = (1 << QEMU_MIGRATION_COOKIE_FLAG_ALLOW_REBOOT),
     QEMU_MIGRATION_COOKIE_CAPS = (1 << QEMU_MIGRATION_COOKIE_FLAG_CAPS),
+    QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS = (1 << QEMU_MIGRATION_COOKIE_FLAG_BLOCK_DIRTY_BITMAPS),
 } qemuMigrationCookieFeatures;
 
 typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics;
@@ -107,6 +109,35 @@ struct _qemuMigrationCookieCaps {
     virBitmapPtr automatic;
 };
 
+typedef struct _qemuMigrationBlockDirtyBitmapsDiskBitmap qemuMigrationBlockDirtyBitmapsDiskBitmap;
+typedef qemuMigrationBlockDirtyBitmapsDiskBitmap *qemuMigrationBlockDirtyBitmapsDiskBitmapPtr;
+struct _qemuMigrationBlockDirtyBitmapsDiskBitmap {
+    /* config */
+    char *bitmapname;
+    char *alias;
+
+    /* runtime */
+    virTristateBool persistent; /* force persisting of the bitmap */
+    char *sourcebitmap; /* optional, actual bitmap to migrate in case we needed
+                           to create a temporary one by merging */
+    bool skip; /* omit this bitmap */
+};
+
+
+typedef struct _qemuMigrationBlockDirtyBitmapsDisk qemuMigrationBlockDirtyBitmapsDisk;
+typedef qemuMigrationBlockDirtyBitmapsDisk *qemuMigrationBlockDirtyBitmapsDiskPtr;
+struct _qemuMigrationBlockDirtyBitmapsDisk {
+    char *target;
+
+    GSList *bitmaps;
+
+    /* runtime data */
+    virDomainDiskDefPtr disk; /* disk object corresponding to 'target' */
+    const char *nodename; /* nodename of the top level source of 'disk' */
+    bool skip; /* omit this disk */
+};
+
+
 typedef struct _qemuMigrationCookie qemuMigrationCookie;
 typedef qemuMigrationCookie *qemuMigrationCookiePtr;
 struct _qemuMigrationCookie {
@@ -150,6 +181,9 @@ struct _qemuMigrationCookie {
 
     /* If flags & QEMU_MIGRATION_COOKIE_CAPS */
     qemuMigrationCookieCapsPtr caps;
+
+    /* If flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS */
+    GSList *blockDirtyBitmaps;
 };