[GSoC][PATCH v2] qemu_domainjob: removal of its dependency on other qemu-files

Prathamesh Chavan posted 1 patch 3 years, 8 months ago
Test syntax-check failed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20200708183327.8560-1-pc44800@gmail.com
src/qemu/qemu_backup.c           |  13 +-
src/qemu/qemu_domain.c           | 251 +-------------------
src/qemu/qemu_domainjob.c        | 386 ++++++++++++++++++++++++++++---
src/qemu/qemu_domainjob.h        |  69 ++++--
src/qemu/qemu_driver.c           |  21 +-
src/qemu/qemu_migration.c        |  45 ++--
src/qemu/qemu_migration_cookie.c |   7 +-
src/qemu/qemu_migration_params.c |   9 +-
src/qemu/qemu_migration_params.h |  28 +++
src/qemu/qemu_process.c          |  24 +-
10 files changed, 515 insertions(+), 338 deletions(-)
[GSoC][PATCH v2] qemu_domainjob: removal of its dependency on other qemu-files
Posted by Prathamesh Chavan 3 years, 8 months ago
It was seen that `qemu_domain.h` file depended upon
`qemu_migration_params.h` and `qmeu_monitor.h` as they
were required by some qemu_domainjob stuctures.
This dependency was removed by the introduction of
a `void *privateData` pointer. This privateData pointer
was handled using a structure of callback functions.

Additionally, the patch also moves funcitons
`qemuDomainObjPrivateXMLFormatJob` and
`qemuDomainObjPrivateXMLParseJob` from `qemu_domain`
and handles them using the callback structure of
domain jobs.

Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>
---
Previous version of this patch can be found here[1].

This patch adds a funciton to the domainJobInfo callback
structure to specifically to copy the jobInfo privateData
structure.

Also, it was noticed that qemuDomainNamespace was reciding
in `qmeu_domainjob.c`, and should rather be in its original file
`qmeu_domain.c`. hence was moved.

 src/qemu/qemu_backup.c           |  13 +-
 src/qemu/qemu_domain.c           | 251 +-------------------
 src/qemu/qemu_domainjob.c        | 386 ++++++++++++++++++++++++++++---
 src/qemu/qemu_domainjob.h        |  69 ++++--
 src/qemu/qemu_driver.c           |  21 +-
 src/qemu/qemu_migration.c        |  45 ++--
 src/qemu/qemu_migration_cookie.c |   7 +-
 src/qemu/qemu_migration_params.c |   9 +-
 src/qemu/qemu_migration_params.h |  28 +++
 src/qemu/qemu_process.c          |  24 +-
 10 files changed, 515 insertions(+), 338 deletions(-)

diff --git a/src/qemu/qemu_backup.c b/src/qemu/qemu_backup.c
index b711f8f623..82dc7797cb 100644
--- a/src/qemu/qemu_backup.c
+++ b/src/qemu/qemu_backup.c
@@ -529,17 +529,19 @@ qemuBackupJobTerminate(virDomainObjPtr vm,
 
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobInfoPrivatePtr completedJobInfo;
     size_t i;
 
     qemuDomainJobInfoUpdateTime(priv->job.current);
 
     g_clear_pointer(&priv->job.completed, qemuDomainJobInfoFree);
     priv->job.completed = qemuDomainJobInfoCopy(priv->job.current);
+    completedJobInfo = priv->job.completed->privateData;
 
-    priv->job.completed->stats.backup.total = priv->backup->push_total;
-    priv->job.completed->stats.backup.transferred = priv->backup->push_transferred;
-    priv->job.completed->stats.backup.tmp_used = priv->backup->pull_tmp_used;
-    priv->job.completed->stats.backup.tmp_total = priv->backup->pull_tmp_total;
+    completedJobInfo->stats.backup.total = priv->backup->push_total;
+    completedJobInfo->stats.backup.transferred = priv->backup->push_transferred;
+    completedJobInfo->stats.backup.tmp_used = priv->backup->pull_tmp_used;
+    completedJobInfo->stats.backup.tmp_total = priv->backup->pull_tmp_total;
 
     priv->job.completed->status = jobstatus;
     priv->job.completed->errmsg = g_strdup(priv->backup->errmsg);
@@ -1069,7 +1071,8 @@ qemuBackupGetJobInfoStats(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           qemuDomainJobInfoPtr jobInfo)
 {
-    qemuDomainBackupStats *stats = &jobInfo->stats.backup;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
+    qemuDomainBackupStats *stats = &jobInfoPriv->stats.backup;
     qemuDomainObjPrivatePtr priv = vm->privateData;
     qemuMonitorJobInfoPtr *blockjobs = NULL;
     size_t nblockjobs = 0;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 42cc78ac1b..c77e809045 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -83,6 +83,11 @@
 
 VIR_LOG_INIT("qemu.qemu_domain");
 
+VIR_ENUM_IMPL(qemuDomainNamespace,
+              QEMU_DOMAIN_NS_LAST,
+              "mount",
+);
+
 /**
  * qemuDomainObjFromDomain:
  * @domain: Domain pointer that has to be looked up
@@ -2162,103 +2167,6 @@ qemuDomainObjPrivateXMLFormatPR(virBufferPtr buf,
         virBufferAddLit(buf, "<prDaemon/>\n");
 }
 
-
-static int
-qemuDomainObjPrivateXMLFormatNBDMigrationSource(virBufferPtr buf,
-                                                virStorageSourcePtr src,
-                                                virDomainXMLOptionPtr xmlopt)
-{
-    g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
-    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
-
-    virBufferAsprintf(&attrBuf, " type='%s' format='%s'",
-                      virStorageTypeToString(src->type),
-                      virStorageFileFormatTypeToString(src->format));
-
-    if (virDomainDiskSourceFormat(&childBuf, src, "source", 0, false,
-                                  VIR_DOMAIN_DEF_FORMAT_STATUS,
-                                  false, false, xmlopt) < 0)
-        return -1;
-
-    virXMLFormatElement(buf, "migrationSource", &attrBuf, &childBuf);
-
-    return 0;
-}
-
-
-static int
-qemuDomainObjPrivateXMLFormatNBDMigration(virBufferPtr buf,
-                                          virDomainObjPtr vm)
-{
-    qemuDomainObjPrivatePtr priv = vm->privateData;
-    size_t i;
-    virDomainDiskDefPtr disk;
-    qemuDomainDiskPrivatePtr diskPriv;
-
-    for (i = 0; i < vm->def->ndisks; i++) {
-        g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
-        g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
-        disk = vm->def->disks[i];
-        diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
-
-        virBufferAsprintf(&attrBuf, " dev='%s' migrating='%s'",
-                          disk->dst, diskPriv->migrating ? "yes" : "no");
-
-        if (diskPriv->migrSource &&
-            qemuDomainObjPrivateXMLFormatNBDMigrationSource(&childBuf,
-                                                            diskPriv->migrSource,
-                                                            priv->driver->xmlopt) < 0)
-            return -1;
-
-        virXMLFormatElement(buf, "disk", &attrBuf, &childBuf);
-    }
-
-    return 0;
-}
-
-
-static int
-qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf,
-                                 virDomainObjPtr vm,
-                                 qemuDomainObjPrivatePtr priv)
-{
-    g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
-    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
-    qemuDomainJob job = priv->job.active;
-
-    if (!qemuDomainTrackJob(job))
-        job = QEMU_JOB_NONE;
-
-    if (job == QEMU_JOB_NONE &&
-        priv->job.asyncJob == QEMU_ASYNC_JOB_NONE)
-        return 0;
-
-    virBufferAsprintf(&attrBuf, " type='%s' async='%s'",
-                      qemuDomainJobTypeToString(job),
-                      qemuDomainAsyncJobTypeToString(priv->job.asyncJob));
-
-    if (priv->job.phase) {
-        virBufferAsprintf(&attrBuf, " phase='%s'",
-                          qemuDomainAsyncJobPhaseToString(priv->job.asyncJob,
-                                                          priv->job.phase));
-    }
-
-    if (priv->job.asyncJob != QEMU_ASYNC_JOB_NONE)
-        virBufferAsprintf(&attrBuf, " flags='0x%lx'", priv->job.apiFlags);
-
-    if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT &&
-        qemuDomainObjPrivateXMLFormatNBDMigration(&childBuf, vm) < 0)
-        return -1;
-
-    if (priv->job.migParams)
-        qemuMigrationParamsFormat(&childBuf, priv->job.migParams);
-
-    virXMLFormatElement(buf, "job", &attrBuf, &childBuf);
-
-    return 0;
-}
-
-
 static bool
 qemuDomainHasSlirp(virDomainObjPtr vm)
 {
@@ -2394,7 +2302,7 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf,
     if (priv->lockState)
         virBufferAsprintf(buf, "<lockstate>%s</lockstate>\n", priv->lockState);
 
-    if (qemuDomainObjPrivateXMLFormatJob(buf, vm, priv) < 0)
+    if (priv->job.cb.formatJob(buf, vm, &priv->job) < 0)
         return -1;
 
     if (priv->fakeReboot)
@@ -2894,151 +2802,6 @@ qemuDomainObjPrivateXMLParsePR(xmlXPathContextPtr ctxt,
 }
 
 
-static int
-qemuDomainObjPrivateXMLParseJobNBDSource(xmlNodePtr node,
-                                         xmlXPathContextPtr ctxt,
-                                         virDomainDiskDefPtr disk,
-                                         virDomainXMLOptionPtr xmlopt)
-{
-    VIR_XPATH_NODE_AUTORESTORE(ctxt);
-    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
-    g_autofree char *format = NULL;
-    g_autofree char *type = NULL;
-    g_autoptr(virStorageSource) migrSource = NULL;
-    xmlNodePtr sourceNode;
-
-    ctxt->node = node;
-
-    if (!(ctxt->node = virXPathNode("./migrationSource", ctxt)))
-        return 0;
-
-    if (!(type = virXMLPropString(ctxt->node, "type"))) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("missing storage source type"));
-        return -1;
-    }
-
-    if (!(format = virXMLPropString(ctxt->node, "format"))) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("missing storage source format"));
-        return -1;
-    }
-
-    if (!(migrSource = virDomainStorageSourceParseBase(type, format, NULL)))
-        return -1;
-
-    /* newer libvirt uses the <source> subelement instead of formatting the
-     * source directly into <migrationSource> */
-    if ((sourceNode = virXPathNode("./source", ctxt)))
-        ctxt->node = sourceNode;
-
-    if (virDomainStorageSourceParse(ctxt->node, ctxt, migrSource,
-                                    VIR_DOMAIN_DEF_PARSE_STATUS, xmlopt) < 0)
-        return -1;
-
-    diskPriv->migrSource = g_steal_pointer(&migrSource);
-    return 0;
-}
-
-
-static int
-qemuDomainObjPrivateXMLParseJobNBD(virDomainObjPtr vm,
-                                   qemuDomainObjPrivatePtr priv,
-                                   xmlXPathContextPtr ctxt)
-{
-    g_autofree xmlNodePtr *nodes = NULL;
-    size_t i;
-    int n;
-
-    if ((n = virXPathNodeSet("./disk[@migrating='yes']", ctxt, &nodes)) < 0)
-        return -1;
-
-    if (n > 0) {
-        if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
-            VIR_WARN("Found disks marked for migration but we were not "
-                     "migrating");
-            n = 0;
-        }
-        for (i = 0; i < n; i++) {
-            virDomainDiskDefPtr disk;
-            g_autofree char *dst = NULL;
-
-            if ((dst = virXMLPropString(nodes[i], "dev")) &&
-                (disk = virDomainDiskByTarget(vm->def, dst))) {
-                QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating = true;
-
-                if (qemuDomainObjPrivateXMLParseJobNBDSource(nodes[i], ctxt,
-                                                             disk,
-                                                             priv->driver->xmlopt) < 0)
-                    return -1;
-            }
-        }
-    }
-
-    return 0;
-}
-
-
-static int
-qemuDomainObjPrivateXMLParseJob(virDomainObjPtr vm,
-                                qemuDomainObjPrivatePtr priv,
-                                xmlXPathContextPtr ctxt)
-{
-    VIR_XPATH_NODE_AUTORESTORE(ctxt);
-    g_autofree char *tmp = NULL;
-
-    if (!(ctxt->node = virXPathNode("./job[1]", ctxt)))
-        return 0;
-
-    if ((tmp = virXPathString("string(@type)", ctxt))) {
-        int type;
-
-        if ((type = qemuDomainJobTypeFromString(tmp)) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Unknown job type %s"), tmp);
-            return -1;
-        }
-        VIR_FREE(tmp);
-        priv->job.active = type;
-    }
-
-    if ((tmp = virXPathString("string(@async)", ctxt))) {
-        int async;
-
-        if ((async = qemuDomainAsyncJobTypeFromString(tmp)) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Unknown async job type %s"), tmp);
-            return -1;
-        }
-        VIR_FREE(tmp);
-        priv->job.asyncJob = async;
-
-        if ((tmp = virXPathString("string(@phase)", ctxt))) {
-            priv->job.phase = qemuDomainAsyncJobPhaseFromString(async, tmp);
-            if (priv->job.phase < 0) {
-                virReportError(VIR_ERR_INTERNAL_ERROR,
-                               _("Unknown job phase %s"), tmp);
-                return -1;
-            }
-            VIR_FREE(tmp);
-        }
-    }
-
-    if (virXPathULongHex("string(@flags)", ctxt, &priv->job.apiFlags) == -2) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid job flags"));
-        return -1;
-    }
-
-    if (qemuDomainObjPrivateXMLParseJobNBD(vm, priv, ctxt) < 0)
-        return -1;
-
-    if (qemuMigrationParamsParse(ctxt, &priv->job.migParams) < 0)
-        return -1;
-
-    return 0;
-}
-
-
 static int
 qemuDomainObjPrivateXMLParseSlirpFeatures(xmlNodePtr featuresNode,
                                           xmlXPathContextPtr ctxt,
@@ -3198,7 +2961,7 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,
 
     priv->lockState = virXPathString("string(./lockstate)", ctxt);
 
-    if (qemuDomainObjPrivateXMLParseJob(vm, priv, ctxt) < 0)
+    if (priv->job.cb.parseJob(vm, &priv->job, ctxt, priv->driver->xmlopt) < 0)
         goto error;
 
     priv->fakeReboot = virXPathBoolean("boolean(./fakereboot)", ctxt) == 1;
diff --git a/src/qemu/qemu_domainjob.c b/src/qemu/qemu_domainjob.c
index 7111acadda..389777153b 100644
--- a/src/qemu/qemu_domainjob.c
+++ b/src/qemu/qemu_domainjob.c
@@ -63,11 +63,6 @@ VIR_ENUM_IMPL(qemuDomainAsyncJob,
               "backup",
 );
 
-VIR_ENUM_IMPL(qemuDomainNamespace,
-              QEMU_DOMAIN_NS_LAST,
-              "mount",
-);
-
 
 const char *
 qemuDomainAsyncJobPhaseToString(qemuDomainAsyncJob job,
@@ -121,22 +116,68 @@ qemuDomainAsyncJobPhaseFromString(qemuDomainAsyncJob job,
         return -1;
 }
 
+static void
+qemuJobInfoFreePrivateData(qemuDomainJobInfoPrivatePtr priv)
+{
+    g_free(&priv->stats);
+}
+
+static void
+qemuJobInfoFreePrivate(void *opaque)
+{
+    qemuDomainJobInfoPtr jobInfo = (qemuDomainJobInfoPtr) opaque;
+    qemuJobInfoFreePrivateData(jobInfo->privateData);
+}
 
 void
 qemuDomainJobInfoFree(qemuDomainJobInfoPtr info)
 {
+    info->cb.freeJobInfoPrivate(info);
     g_free(info->errmsg);
     g_free(info);
 }
 
+static void *
+qemuDomainJobInfoPrivateAlloc(void)
+{
+    qemuDomainJobInfoPrivatePtr retPriv = g_new0(qemuDomainJobInfoPrivate, 1);
+    return (void *)retPriv;
+}
+
+static void
+qemuDomainJobInfoPrivateCopy(qemuDomainJobInfoPtr src,
+                             qemuDomainJobInfoPtr dest)
+{
+    memcpy(dest->privateData, src->privateData,
+           sizeof(qemuDomainJobInfoPrivate));
+}
+
+static qemuDomainJobInfoPtr
+qemuDomainJobInfoAlloc(void)
+{
+    qemuDomainJobInfoPtr ret = g_new0(qemuDomainJobInfo, 1);
+    ret->cb.allocJobInfoPrivate = &qemuDomainJobInfoPrivateAlloc;
+    ret->cb.freeJobInfoPrivate = &qemuJobInfoFreePrivate;
+    ret->cb.copyJobInfoPrivate = &qemuDomainJobInfoPrivateCopy;
+    ret->privateData = ret->cb.allocJobInfoPrivate();
+    return ret;
+}
+
+static void
+qemuDomainCurrentJobInfoInit(qemuDomainJobObjPtr job)
+{
+    job->current = qemuDomainJobInfoAlloc();
+    job->current->status = QEMU_DOMAIN_JOB_STATUS_ACTIVE;
+}
+
 
 qemuDomainJobInfoPtr
 qemuDomainJobInfoCopy(qemuDomainJobInfoPtr info)
 {
-    qemuDomainJobInfoPtr ret = g_new0(qemuDomainJobInfo, 1);
+    qemuDomainJobInfoPtr ret = qemuDomainJobInfoAlloc();
 
     memcpy(ret, info, sizeof(*info));
-
+    ret->cb.copyJobInfoPrivate(info, ret);
     ret->errmsg = g_strdup(info->errmsg);
 
     return ret;
@@ -166,10 +207,43 @@ qemuDomainEventEmitJobCompleted(virQEMUDriverPtr driver,
 }
 
 
+static void *
+qemuJobAllocPrivate(void)
+{
+    qemuDomainJobPrivatePtr priv;
+    if (VIR_ALLOC(priv) < 0)
+        return NULL;
+    return (void *)priv;
+}
+
+
+static void
+qemuJobFreePrivateData(qemuDomainJobPrivatePtr priv)
+{
+    priv->spiceMigration = false;
+    priv->spiceMigrated = false;
+    priv->dumpCompleted = false;
+    qemuMigrationParamsFree(priv->migParams);
+    priv->migParams = NULL;
+}
+
+static void
+qemuJobFreePrivate(void *opaque)
+{
+    qemuDomainJobObjPtr job = (qemuDomainJobObjPtr) opaque;
+    qemuJobFreePrivateData(job->privateData);
+}
+
+
 int
 qemuDomainObjInitJob(qemuDomainJobObjPtr job)
 {
     memset(job, 0, sizeof(*job));
+    job->cb.allocJobPrivate = &qemuJobAllocPrivate;
+    job->cb.freeJobPrivate = &qemuJobFreePrivate;
+    job->cb.formatJob = &qemuDomainObjPrivateXMLFormatJob;
+    job->cb.parseJob = &qemuDomainObjPrivateXMLParseJob;
+    job->privateData = job->cb.allocJobPrivate();
 
     if (virCondInit(&job->cond) < 0)
         return -1;
@@ -213,13 +287,9 @@ qemuDomainObjResetAsyncJob(qemuDomainJobObjPtr job)
     job->phase = 0;
     job->mask = QEMU_JOB_DEFAULT_MASK;
     job->abortJob = false;
-    job->spiceMigration = false;
-    job->spiceMigrated = false;
-    job->dumpCompleted = false;
     VIR_FREE(job->error);
     g_clear_pointer(&job->current, qemuDomainJobInfoFree);
-    qemuMigrationParamsFree(job->migParams);
-    job->migParams = NULL;
+    job->cb.freeJobPrivate(job);
     job->apiFlags = 0;
 }
 
@@ -235,7 +305,7 @@ qemuDomainObjRestoreJob(virDomainObjPtr obj,
     job->asyncJob = priv->job.asyncJob;
     job->asyncOwner = priv->job.asyncOwner;
     job->phase = priv->job.phase;
-    job->migParams = g_steal_pointer(&priv->job.migParams);
+    job->privateData = g_steal_pointer(&priv->job.privateData);
     job->apiFlags = priv->job.apiFlags;
 
     qemuDomainObjResetJob(&priv->job);
@@ -285,6 +355,7 @@ int
 qemuDomainJobInfoUpdateDowntime(qemuDomainJobInfoPtr jobInfo)
 {
     unsigned long long now;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
 
     if (!jobInfo->stopped)
         return 0;
@@ -298,8 +369,8 @@ qemuDomainJobInfoUpdateDowntime(qemuDomainJobInfoPtr jobInfo)
         return 0;
     }
 
-    jobInfo->stats.mig.downtime = now - jobInfo->stopped;
-    jobInfo->stats.mig.downtime_set = true;
+    jobInfoPriv->stats.mig.downtime = now - jobInfo->stopped;
+    jobInfoPriv->stats.mig.downtime_set = true;
     return 0;
 }
 
@@ -334,38 +405,39 @@ int
 qemuDomainJobInfoToInfo(qemuDomainJobInfoPtr jobInfo,
                         virDomainJobInfoPtr info)
 {
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
     info->type = qemuDomainJobStatusToType(jobInfo->status);
     info->timeElapsed = jobInfo->timeElapsed;
 
     switch (jobInfo->statsType) {
     case QEMU_DOMAIN_JOB_STATS_TYPE_MIGRATION:
-        info->memTotal = jobInfo->stats.mig.ram_total;
-        info->memRemaining = jobInfo->stats.mig.ram_remaining;
-        info->memProcessed = jobInfo->stats.mig.ram_transferred;
-        info->fileTotal = jobInfo->stats.mig.disk_total +
+        info->memTotal = jobInfoPriv->stats.mig.ram_total;
+        info->memRemaining = jobInfoPriv->stats.mig.ram_remaining;
+        info->memProcessed = jobInfoPriv->stats.mig.ram_transferred;
+        info->fileTotal = jobInfoPriv->stats.mig.disk_total +
                           jobInfo->mirrorStats.total;
-        info->fileRemaining = jobInfo->stats.mig.disk_remaining +
+        info->fileRemaining = jobInfoPriv->stats.mig.disk_remaining +
                               (jobInfo->mirrorStats.total -
                                jobInfo->mirrorStats.transferred);
-        info->fileProcessed = jobInfo->stats.mig.disk_transferred +
+        info->fileProcessed = jobInfoPriv->stats.mig.disk_transferred +
                               jobInfo->mirrorStats.transferred;
         break;
 
     case QEMU_DOMAIN_JOB_STATS_TYPE_SAVEDUMP:
-        info->memTotal = jobInfo->stats.mig.ram_total;
-        info->memRemaining = jobInfo->stats.mig.ram_remaining;
-        info->memProcessed = jobInfo->stats.mig.ram_transferred;
+        info->memTotal = jobInfoPriv->stats.mig.ram_total;
+        info->memRemaining = jobInfoPriv->stats.mig.ram_remaining;
+        info->memProcessed = jobInfoPriv->stats.mig.ram_transferred;
         break;
 
     case QEMU_DOMAIN_JOB_STATS_TYPE_MEMDUMP:
-        info->memTotal = jobInfo->stats.dump.total;
-        info->memProcessed = jobInfo->stats.dump.completed;
+        info->memTotal = jobInfoPriv->stats.dump.total;
+        info->memProcessed = jobInfoPriv->stats.dump.completed;
         info->memRemaining = info->memTotal - info->memProcessed;
         break;
 
     case QEMU_DOMAIN_JOB_STATS_TYPE_BACKUP:
-        info->fileTotal = jobInfo->stats.backup.total;
-        info->fileProcessed = jobInfo->stats.backup.transferred;
+        info->fileTotal = jobInfoPriv->stats.backup.total;
+        info->fileProcessed = jobInfoPriv->stats.backup.transferred;
         info->fileRemaining = info->fileTotal - info->fileProcessed;
         break;
 
@@ -387,7 +459,8 @@ qemuDomainMigrationJobInfoToParams(qemuDomainJobInfoPtr jobInfo,
                                    virTypedParameterPtr *params,
                                    int *nparams)
 {
-    qemuMonitorMigrationStats *stats = &jobInfo->stats.mig;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
+    qemuMonitorMigrationStats *stats = &jobInfoPriv->stats.mig;
     qemuDomainMirrorStatsPtr mirrorStats = &jobInfo->mirrorStats;
     virTypedParameterPtr par = NULL;
     int maxpar = 0;
@@ -564,7 +637,8 @@ qemuDomainDumpJobInfoToParams(qemuDomainJobInfoPtr jobInfo,
                               virTypedParameterPtr *params,
                               int *nparams)
 {
-    qemuMonitorDumpStats *stats = &jobInfo->stats.dump;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
+    qemuMonitorDumpStats *stats = &jobInfoPriv->stats.dump;
     virTypedParameterPtr par = NULL;
     int maxpar = 0;
     int npar = 0;
@@ -607,7 +681,8 @@ qemuDomainBackupJobInfoToParams(qemuDomainJobInfoPtr jobInfo,
                                 virTypedParameterPtr *params,
                                 int *nparams)
 {
-    qemuDomainBackupStats *stats = &jobInfo->stats.backup;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
+    qemuDomainBackupStats *stats = &jobInfoPriv->stats.backup;
     g_autoptr(virTypedParamList) par = g_new0(virTypedParamList, 1);
 
     if (virTypedParamListAddInt(par, jobInfo->operation,
@@ -782,6 +857,7 @@ qemuDomainObjCanSetJob(qemuDomainJobObjPtr job,
 /* Give up waiting for mutex after 30 seconds */
 #define QEMU_JOB_WAIT_TIME (1000ull * 30)
 
+
 /**
  * qemuDomainObjBeginJobInternal:
  * @driver: qemu driver
@@ -890,8 +966,7 @@ qemuDomainObjBeginJobInternal(virQEMUDriverPtr driver,
                       qemuDomainAsyncJobTypeToString(asyncJob),
                       obj, obj->def->name);
             qemuDomainObjResetAsyncJob(&priv->job);
-            priv->job.current = g_new0(qemuDomainJobInfo, 1);
-            priv->job.current->status = QEMU_DOMAIN_JOB_STATUS_ACTIVE;
+            qemuDomainCurrentJobInfoInit(&priv->job);
             priv->job.asyncJob = asyncJob;
             priv->job.asyncOwner = virThreadSelfID();
             priv->job.asyncOwnerAPI = virThreadJobGet();
@@ -1190,3 +1265,248 @@ qemuDomainObjAbortAsyncJob(virDomainObjPtr obj)
     priv->job.abortJob = true;
     virDomainObjBroadcast(obj);
 }
+
+
+static int
+qemuDomainObjPrivateXMLFormatNBDMigrationSource(virBufferPtr buf,
+                                                virStorageSourcePtr src,
+                                                virDomainXMLOptionPtr xmlopt)
+{
+    g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
+    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
+
+    virBufferAsprintf(&attrBuf, " type='%s' format='%s'",
+                      virStorageTypeToString(src->type),
+                      virStorageFileFormatTypeToString(src->format));
+
+    if (virDomainDiskSourceFormat(&childBuf, src, "source", 0, false,
+                                  VIR_DOMAIN_DEF_FORMAT_STATUS,
+                                  false, false, xmlopt) < 0)
+        return -1;
+
+    virXMLFormatElement(buf, "migrationSource", &attrBuf, &childBuf);
+
+    return 0;
+}
+
+
+static int
+qemuDomainObjPrivateXMLFormatNBDMigration(virBufferPtr buf,
+                                          virDomainObjPtr vm)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    size_t i;
+    virDomainDiskDefPtr disk;
+    qemuDomainDiskPrivatePtr diskPriv;
+
+    for (i = 0; i < vm->def->ndisks; i++) {
+        g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
+        g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
+        disk = vm->def->disks[i];
+        diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+
+        virBufferAsprintf(&attrBuf, " dev='%s' migrating='%s'",
+                          disk->dst, diskPriv->migrating ? "yes" : "no");
+
+        if (diskPriv->migrSource &&
+            qemuDomainObjPrivateXMLFormatNBDMigrationSource(&childBuf,
+                                                            diskPriv->migrSource,
+                                                            priv->driver->xmlopt) < 0)
+            return -1;
+
+        virXMLFormatElement(buf, "disk", &attrBuf, &childBuf);
+    }
+
+    return 0;
+}
+
+
+int
+qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf,
+                                 virDomainObjPtr vm,
+                                 qemuDomainJobObjPtr jobObj)
+{
+    g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
+    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
+    qemuDomainJob job = jobObj->active;
+    qemuDomainJobPrivatePtr jobPriv = jobObj->privateData;
+
+    if (!qemuDomainTrackJob(job))
+        job = QEMU_JOB_NONE;
+
+    if (job == QEMU_JOB_NONE &&
+        jobObj->asyncJob == QEMU_ASYNC_JOB_NONE)
+        return 0;
+
+    virBufferAsprintf(&attrBuf, " type='%s' async='%s'",
+                      qemuDomainJobTypeToString(job),
+                      qemuDomainAsyncJobTypeToString(jobObj->asyncJob));
+
+    if (jobObj->phase) {
+        virBufferAsprintf(&attrBuf, " phase='%s'",
+                          qemuDomainAsyncJobPhaseToString(jobObj->asyncJob,
+                                                          jobObj->phase));
+    }
+
+    if (jobObj->asyncJob != QEMU_ASYNC_JOB_NONE)
+        virBufferAsprintf(&attrBuf, " flags='0x%lx'", jobObj->apiFlags);
+
+    if (jobObj->asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT &&
+        qemuDomainObjPrivateXMLFormatNBDMigration(&childBuf, vm) < 0)
+        return -1;
+
+    if (jobPriv->migParams)
+        qemuMigrationParamsFormat(&childBuf, jobPriv->migParams);
+
+    virXMLFormatElement(buf, "job", &attrBuf, &childBuf);
+
+    return 0;
+}
+
+
+static int
+qemuDomainObjPrivateXMLParseJobNBDSource(xmlNodePtr node,
+                                         xmlXPathContextPtr ctxt,
+                                         virDomainDiskDefPtr disk,
+                                         virDomainXMLOptionPtr xmlopt)
+{
+    VIR_XPATH_NODE_AUTORESTORE(ctxt);
+    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+    g_autofree char *format = NULL;
+    g_autofree char *type = NULL;
+    g_autoptr(virStorageSource) migrSource = NULL;
+    xmlNodePtr sourceNode;
+
+    ctxt->node = node;
+
+    if (!(ctxt->node = virXPathNode("./migrationSource", ctxt)))
+        return 0;
+
+    if (!(type = virXMLPropString(ctxt->node, "type"))) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("missing storage source type"));
+        return -1;
+    }
+
+    if (!(format = virXMLPropString(ctxt->node, "format"))) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("missing storage source format"));
+        return -1;
+    }
+
+    if (!(migrSource = virDomainStorageSourceParseBase(type, format, NULL)))
+        return -1;
+
+    /* newer libvirt uses the <source> subelement instead of formatting the
+     * source directly into <migrationSource> */
+    if ((sourceNode = virXPathNode("./source", ctxt)))
+        ctxt->node = sourceNode;
+
+    if (virDomainStorageSourceParse(ctxt->node, ctxt, migrSource,
+                                    VIR_DOMAIN_DEF_PARSE_STATUS, xmlopt) < 0)
+        return -1;
+
+    diskPriv->migrSource = g_steal_pointer(&migrSource);
+    return 0;
+}
+
+
+static int
+qemuDomainObjPrivateXMLParseJobNBD(virDomainObjPtr vm,
+                                   qemuDomainJobObjPtr job,
+                                   xmlXPathContextPtr ctxt,
+                                   virDomainXMLOptionPtr xmlopt)
+{
+    g_autofree xmlNodePtr *nodes = NULL;
+    size_t i;
+    int n;
+
+    if ((n = virXPathNodeSet("./disk[@migrating='yes']", ctxt, &nodes)) < 0)
+        return -1;
+
+    if (n > 0) {
+        if (job->asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
+            VIR_WARN("Found disks marked for migration but we were not "
+                     "migrating");
+            n = 0;
+        }
+        for (i = 0; i < n; i++) {
+            virDomainDiskDefPtr disk;
+            g_autofree char *dst = NULL;
+
+            if ((dst = virXMLPropString(nodes[i], "dev")) &&
+                (disk = virDomainDiskByTarget(vm->def, dst))) {
+                QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating = true;
+
+                if (qemuDomainObjPrivateXMLParseJobNBDSource(nodes[i], ctxt,
+                                                             disk,
+                                                             xmlopt) < 0)
+                    return -1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+int
+qemuDomainObjPrivateXMLParseJob(virDomainObjPtr vm,
+                                qemuDomainJobObjPtr job,
+                                xmlXPathContextPtr ctxt,
+                                virDomainXMLOptionPtr xmlopt)
+{
+    qemuDomainJobPrivatePtr jobPriv = job->privateData;
+    VIR_XPATH_NODE_AUTORESTORE(ctxt);
+    g_autofree char *tmp = NULL;
+
+    if (!(ctxt->node = virXPathNode("./job[1]", ctxt)))
+        return 0;
+
+    if ((tmp = virXPathString("string(@type)", ctxt))) {
+        int type;
+
+        if ((type = qemuDomainJobTypeFromString(tmp)) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Unknown job type %s"), tmp);
+            return -1;
+        }
+        VIR_FREE(tmp);
+        job->active = type;
+    }
+
+    if ((tmp = virXPathString("string(@async)", ctxt))) {
+        int async;
+
+        if ((async = qemuDomainAsyncJobTypeFromString(tmp)) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Unknown async job type %s"), tmp);
+            return -1;
+        }
+        VIR_FREE(tmp);
+        job->asyncJob = async;
+
+        if ((tmp = virXPathString("string(@phase)", ctxt))) {
+            job->phase = qemuDomainAsyncJobPhaseFromString(async, tmp);
+            if (job->phase < 0) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("Unknown job phase %s"), tmp);
+                return -1;
+            }
+            VIR_FREE(tmp);
+        }
+    }
+
+    if (virXPathULongHex("string(@flags)", ctxt, &job->apiFlags) == -2) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid job flags"));
+        return -1;
+    }
+
+    if (qemuDomainObjPrivateXMLParseJobNBD(vm, job, ctxt, xmlopt) < 0)
+        return -1;
+
+    if (qemuMigrationParamsParse(ctxt, &jobPriv->migParams) < 0)
+        return -1;
+
+    return 0;
+}
diff --git a/src/qemu/qemu_domainjob.h b/src/qemu/qemu_domainjob.h
index 124664354d..ca546c8844 100644
--- a/src/qemu/qemu_domainjob.h
+++ b/src/qemu/qemu_domainjob.h
@@ -19,7 +19,6 @@
 #pragma once
 
 #include <glib-object.h>
-#include "qemu_migration_params.h"
 
 #define JOB_MASK(job)                  (job == 0 ? 0 : 1 << (job - 1))
 #define QEMU_JOB_DEFAULT_MASK \
@@ -99,7 +98,6 @@ typedef enum {
     QEMU_DOMAIN_JOB_STATS_TYPE_BACKUP,
 } qemuDomainJobStatsType;
 
-
 typedef struct _qemuDomainMirrorStats qemuDomainMirrorStats;
 typedef qemuDomainMirrorStats *qemuDomainMirrorStatsPtr;
 struct _qemuDomainMirrorStats {
@@ -107,16 +105,22 @@ struct _qemuDomainMirrorStats {
     unsigned long long total;
 };
 
-typedef struct _qemuDomainBackupStats qemuDomainBackupStats;
-struct _qemuDomainBackupStats {
-    unsigned long long transferred;
-    unsigned long long total;
-    unsigned long long tmp_used;
-    unsigned long long tmp_total;
-};
 
 typedef struct _qemuDomainJobInfo qemuDomainJobInfo;
 typedef qemuDomainJobInfo *qemuDomainJobInfoPtr;
+
+typedef void *(*qemuDomainObjJobInfoPrivateAlloc)(void);
+typedef void (*qemuDomainObjJobInfoPrivateFree)(void *);
+typedef void (*qemuDomainObjJobInfoPrivateCopy)(qemuDomainJobInfoPtr,
+                                                qemuDomainJobInfoPtr);
+
+typedef struct _qemuDomainObjPrivateJobInfoCallbacks qemuDomainObjPrivateJobInfoCallbacks;
+struct _qemuDomainObjPrivateJobInfoCallbacks {
+   qemuDomainObjJobInfoPrivateAlloc allocJobInfoPrivate;
+   qemuDomainObjJobInfoPrivateFree freeJobInfoPrivate;
+   qemuDomainObjJobInfoPrivateCopy copyJobInfoPrivate;
+};
+
 struct _qemuDomainJobInfo {
     qemuDomainJobStatus status;
     virDomainJobOperation operation;
@@ -136,16 +140,15 @@ struct _qemuDomainJobInfo {
     bool timeDeltaSet;
     /* Raw values from QEMU */
     qemuDomainJobStatsType statsType;
-    union {
-        qemuMonitorMigrationStats mig;
-        qemuMonitorDumpStats dump;
-        qemuDomainBackupStats backup;
-    } stats;
     qemuDomainMirrorStats mirrorStats;
 
     char *errmsg; /* optional error message for failed completed jobs */
+
+    void *privateData;  /* job specific collection of info */
+    qemuDomainObjPrivateJobInfoCallbacks cb;
 };
 
+
 void
 qemuDomainJobInfoFree(qemuDomainJobInfoPtr info);
 
@@ -156,6 +159,25 @@ qemuDomainJobInfoCopy(qemuDomainJobInfoPtr info);
 
 typedef struct _qemuDomainJobObj qemuDomainJobObj;
 typedef qemuDomainJobObj *qemuDomainJobObjPtr;
+
+typedef void *(*qemuDomainObjPrivateJobAlloc)(void);
+typedef void (*qemuDomainObjPrivateJobFree)(void *);
+typedef int (*qemuDomainObjPrivateJobFormat)(virBufferPtr,
+                                             virDomainObjPtr,
+                                             qemuDomainJobObjPtr);
+typedef int (*qemuDomainObjPrivateJobParse)(virDomainObjPtr,
+                                            qemuDomainJobObjPtr,
+                                            xmlXPathContextPtr,
+                                            virDomainXMLOptionPtr);
+
+typedef struct _qemuDomainObjPrivateJobCallbacks qemuDomainObjPrivateJobCallbacks;
+struct _qemuDomainObjPrivateJobCallbacks {
+   qemuDomainObjPrivateJobAlloc allocJobPrivate;
+   qemuDomainObjPrivateJobFree freeJobPrivate;
+   qemuDomainObjPrivateJobFormat formatJob;
+   qemuDomainObjPrivateJobParse parseJob;
+};
+
 struct _qemuDomainJobObj {
     virCond cond;                       /* Use to coordinate jobs */
 
@@ -182,14 +204,10 @@ struct _qemuDomainJobObj {
     qemuDomainJobInfoPtr current;       /* async job progress data */
     qemuDomainJobInfoPtr completed;     /* statistics data of a recently completed job */
     bool abortJob;                      /* abort of the job requested */
-    bool spiceMigration;                /* we asked for spice migration and we
-                                         * should wait for it to finish */
-    bool spiceMigrated;                 /* spice migration completed */
     char *error;                        /* job event completion error */
-    bool dumpCompleted;                 /* dump completed */
-
-    qemuMigrationParamsPtr migParams;
     unsigned long apiFlags; /* flags passed to the API which started the async job */
+    void *privateData;                  /* job specific collection of data */
+    qemuDomainObjPrivateJobCallbacks cb;
 };
 
 const char *qemuDomainAsyncJobPhaseToString(qemuDomainAsyncJob job,
@@ -267,3 +285,14 @@ void qemuDomainObjFreeJob(qemuDomainJobObjPtr job);
 int qemuDomainObjInitJob(qemuDomainJobObjPtr job);
 
 bool qemuDomainJobAllowed(qemuDomainJobObjPtr jobs, qemuDomainJob newJob);
+
+int
+qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf,
+                                 virDomainObjPtr vm,
+                                 qemuDomainJobObjPtr jobObj);
+
+int
+qemuDomainObjPrivateXMLParseJob(virDomainObjPtr vm,
+                                qemuDomainJobObjPtr job,
+                                xmlXPathContextPtr ctxt,
+                                virDomainXMLOptionPtr xmlopt);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index cd8d7ffb56..3ff5c5db53 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3701,14 +3701,16 @@ static int
 qemuDumpWaitForCompletion(virDomainObjPtr vm)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobPrivatePtr jobPriv = priv->job.privateData;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = priv->job.current->privateData;
 
     VIR_DEBUG("Waiting for dump completion");
-    while (!priv->job.dumpCompleted && !priv->job.abortJob) {
+    while (!jobPriv->dumpCompleted && !priv->job.abortJob) {
         if (virDomainObjWait(vm) < 0)
             return -1;
     }
 
-    if (priv->job.current->stats.dump.status == QEMU_MONITOR_DUMP_STATUS_FAILED) {
+    if (jobInfoPriv->stats.dump.status == QEMU_MONITOR_DUMP_STATUS_FAILED) {
         if (priv->job.error)
             virReportError(VIR_ERR_OPERATION_FAILED,
                            _("memory-only dump failed: %s"),
@@ -13554,6 +13556,7 @@ qemuDomainGetJobInfoDumpStats(virQEMUDriverPtr driver,
                               qemuDomainJobInfoPtr jobInfo)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
     qemuMonitorDumpStats stats = { 0 };
     int rc;
 
@@ -13565,33 +13568,33 @@ qemuDomainGetJobInfoDumpStats(virQEMUDriverPtr driver,
     if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
         return -1;
 
-    jobInfo->stats.dump = stats;
+    jobInfoPriv->stats.dump = stats;
 
     if (qemuDomainJobInfoUpdateTime(jobInfo) < 0)
         return -1;
 
-    switch (jobInfo->stats.dump.status) {
+    switch (jobInfoPriv->stats.dump.status) {
     case QEMU_MONITOR_DUMP_STATUS_NONE:
     case QEMU_MONITOR_DUMP_STATUS_FAILED:
     case QEMU_MONITOR_DUMP_STATUS_LAST:
         virReportError(VIR_ERR_OPERATION_FAILED,
                        _("dump query failed, status=%d"),
-                       jobInfo->stats.dump.status);
+                       jobInfoPriv->stats.dump.status);
         return -1;
         break;
 
     case QEMU_MONITOR_DUMP_STATUS_ACTIVE:
         jobInfo->status = QEMU_DOMAIN_JOB_STATUS_ACTIVE;
         VIR_DEBUG("dump active, bytes written='%llu' remaining='%llu'",
-                  jobInfo->stats.dump.completed,
-                  jobInfo->stats.dump.total -
-                  jobInfo->stats.dump.completed);
+                  jobInfoPriv->stats.dump.completed,
+                  jobInfoPriv->stats.dump.total -
+                  jobInfoPriv->stats.dump.completed);
         break;
 
     case QEMU_MONITOR_DUMP_STATUS_COMPLETED:
         jobInfo->status = QEMU_DOMAIN_JOB_STATUS_COMPLETED;
         VIR_DEBUG("dump completed, bytes written='%llu'",
-                  jobInfo->stats.dump.completed);
+                  jobInfoPriv->stats.dump.completed);
         break;
     }
 
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 13427c1203..a45d13aaac 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1422,12 +1422,13 @@ static int
 qemuMigrationSrcWaitForSpice(virDomainObjPtr vm)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobPrivatePtr jobPriv = priv->job.privateData;
 
-    if (!priv->job.spiceMigration)
+    if (!jobPriv->spiceMigration)
         return 0;
 
     VIR_DEBUG("Waiting for SPICE to finish migration");
-    while (!priv->job.spiceMigrated && !priv->job.abortJob) {
+    while (!jobPriv->spiceMigrated && !priv->job.abortJob) {
         if (virDomainObjWait(vm) < 0)
             return -1;
     }
@@ -1438,7 +1439,8 @@ qemuMigrationSrcWaitForSpice(virDomainObjPtr vm)
 static void
 qemuMigrationUpdateJobType(qemuDomainJobInfoPtr jobInfo)
 {
-    switch ((qemuMonitorMigrationStatus) jobInfo->stats.mig.status) {
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
+    switch ((qemuMonitorMigrationStatus) jobInfoPriv->stats.mig.status) {
     case QEMU_MONITOR_MIGRATION_STATUS_POSTCOPY:
         jobInfo->status = QEMU_DOMAIN_JOB_STATUS_POSTCOPY;
         break;
@@ -1485,6 +1487,7 @@ qemuMigrationAnyFetchStats(virQEMUDriverPtr driver,
                            char **error)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
     qemuMonitorMigrationStats stats;
     int rv;
 
@@ -1496,7 +1499,7 @@ qemuMigrationAnyFetchStats(virQEMUDriverPtr driver,
     if (qemuDomainObjExitMonitor(driver, vm) < 0 || rv < 0)
         return -1;
 
-    jobInfo->stats.mig = stats;
+    jobInfoPriv->stats.mig = stats;
 
     return 0;
 }
@@ -1538,12 +1541,14 @@ qemuMigrationJobCheckStatus(virQEMUDriverPtr driver,
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
     qemuDomainJobInfoPtr jobInfo = priv->job.current;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
+
     char *error = NULL;
     bool events = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_EVENT);
     int ret = -1;
 
     if (!events ||
-        jobInfo->stats.mig.status == QEMU_MONITOR_MIGRATION_STATUS_ERROR) {
+        jobInfoPriv->stats.mig.status == QEMU_MONITOR_MIGRATION_STATUS_ERROR) {
         if (qemuMigrationAnyFetchStats(driver, vm, asyncJob, jobInfo, &error) < 0)
             return -1;
     }
@@ -1777,6 +1782,7 @@ qemuMigrationSrcGraphicsRelocate(virQEMUDriverPtr driver,
                                  const char *graphicsuri)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobPrivatePtr jobPriv = priv->job.privateData;
     int ret = -1;
     const char *listenAddress = NULL;
     virSocketAddr addr;
@@ -1858,7 +1864,7 @@ qemuMigrationSrcGraphicsRelocate(virQEMUDriverPtr driver,
                                        QEMU_ASYNC_JOB_MIGRATION_OUT) == 0) {
         ret = qemuMonitorGraphicsRelocate(priv->mon, type, listenAddress,
                                           port, tlsPort, tlsSubject);
-        priv->job.spiceMigration = !ret;
+        jobPriv->spiceMigration = !ret;
         if (qemuDomainObjExitMonitor(driver, vm) < 0)
             ret = -1;
     }
@@ -1993,6 +1999,7 @@ qemuMigrationSrcCleanup(virDomainObjPtr vm,
 {
     virQEMUDriverPtr driver = opaque;
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobPrivatePtr jobPriv = priv->job.privateData;
 
     VIR_DEBUG("vm=%s, conn=%p, asyncJob=%s, phase=%s",
               vm->def->name, conn,
@@ -2018,7 +2025,7 @@ qemuMigrationSrcCleanup(virDomainObjPtr vm,
                  " domain was successfully started on destination or not",
                  vm->def->name);
         qemuMigrationParamsReset(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT,
-                                 priv->job.migParams, priv->job.apiFlags);
+                                 jobPriv->migParams, priv->job.apiFlags);
         /* clear the job and let higher levels decide what to do */
         qemuDomainObjDiscardAsyncJob(driver, vm);
         break;
@@ -2403,6 +2410,7 @@ qemuMigrationDstPrepareAny(virQEMUDriverPtr driver,
     bool relabel = false;
     int rv;
     char *tlsAlias = NULL;
+    qemuDomainJobPrivatePtr jobPriv = NULL;
 
     virNWFilterReadLockFilterUpdates();
 
@@ -2410,7 +2418,7 @@ qemuMigrationDstPrepareAny(virQEMUDriverPtr driver,
         if (flags & (VIR_MIGRATE_NON_SHARED_DISK |
                      VIR_MIGRATE_NON_SHARED_INC)) {
             virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                           _("offline migration cannot handle "
+                           _("offlineqemuDomainJobPrivatePtr jobPriv = priv->job.privateData;priv migration cannot handle "
                              "non-shared storage"));
             goto cleanup;
         }
@@ -2519,6 +2527,7 @@ qemuMigrationDstPrepareAny(virQEMUDriverPtr driver,
     *def = NULL;
 
     priv = vm->privateData;
+    jobPriv = priv->job.privateData;
     priv->origname = g_strdup(origname);
 
     if (taint_hook) {
@@ -2726,7 +2735,7 @@ qemuMigrationDstPrepareAny(virQEMUDriverPtr driver,
 
  stopjob:
     qemuMigrationParamsReset(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN,
-                             priv->job.migParams, priv->job.apiFlags);
+                             jobPriv->migParams, priv->job.apiFlags);
 
     if (stopProcess) {
         unsigned int stopFlags = VIR_QEMU_PROCESS_STOP_MIGRATED;
@@ -3000,6 +3009,7 @@ qemuMigrationSrcConfirmPhase(virQEMUDriverPtr driver,
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
     qemuDomainObjPrivatePtr priv = vm->privateData;
     qemuDomainJobInfoPtr jobInfo = NULL;
+    qemuDomainJobPrivatePtr jobPriv = priv->job.privateData;
 
     VIR_DEBUG("driver=%p, vm=%p, cookiein=%s, cookieinlen=%d, "
               "flags=0x%x, retcode=%d",
@@ -3025,6 +3035,8 @@ qemuMigrationSrcConfirmPhase(virQEMUDriverPtr driver,
 
     /* Update times with the values sent by the destination daemon */
     if (mig->jobInfo && jobInfo) {
+        qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
+        qemuDomainJobInfoPrivatePtr migJobInfoPriv = mig->jobInfo->privateData;
         int reason;
 
         /* We need to refresh migration statistics after a completed post-copy
@@ -3040,8 +3052,8 @@ qemuMigrationSrcConfirmPhase(virQEMUDriverPtr driver,
         qemuDomainJobInfoUpdateTime(jobInfo);
         jobInfo->timeDeltaSet = mig->jobInfo->timeDeltaSet;
         jobInfo->timeDelta = mig->jobInfo->timeDelta;
-        jobInfo->stats.mig.downtime_set = mig->jobInfo->stats.mig.downtime_set;
-        jobInfo->stats.mig.downtime = mig->jobInfo->stats.mig.downtime;
+        jobInfoPriv->stats.mig.downtime_set = migJobInfoPriv->stats.mig.downtime_set;
+        jobInfoPriv->stats.mig.downtime = migJobInfoPriv->stats.mig.downtime;
     }
 
     if (flags & VIR_MIGRATE_OFFLINE)
@@ -3084,7 +3096,7 @@ qemuMigrationSrcConfirmPhase(virQEMUDriverPtr driver,
             qemuMigrationSrcRestoreDomainState(driver, vm);
 
         qemuMigrationParamsReset(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT,
-                                 priv->job.migParams, priv->job.apiFlags);
+                                 jobPriv->migParams, priv->job.apiFlags);
 
         if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
             VIR_WARN("Failed to save status on vm %s", vm->def->name);
@@ -4681,6 +4693,7 @@ qemuMigrationSrcPerformJob(virQEMUDriverPtr driver,
     virErrorPtr orig_err = NULL;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobPrivatePtr jobPriv = priv->job.privateData;
 
     if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT,
                               flags) < 0)
@@ -4738,7 +4751,7 @@ qemuMigrationSrcPerformJob(virQEMUDriverPtr driver,
      */
     if (!v3proto && ret < 0)
         qemuMigrationParamsReset(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT,
-                                 priv->job.migParams, priv->job.apiFlags);
+                                 jobPriv->migParams, priv->job.apiFlags);
 
     qemuMigrationSrcRestoreDomainState(driver, vm);
 
@@ -4780,6 +4793,7 @@ qemuMigrationSrcPerformPhase(virQEMUDriverPtr driver,
                              unsigned long resource)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobPrivatePtr jobPriv = priv->job.privateData;
     int ret = -1;
 
     /* If we didn't start the job in the begin phase, start it now. */
@@ -4814,7 +4828,7 @@ qemuMigrationSrcPerformPhase(virQEMUDriverPtr driver,
  endjob:
     if (ret < 0) {
         qemuMigrationParamsReset(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT,
-                                 priv->job.migParams, priv->job.apiFlags);
+                                 jobPriv->migParams, priv->job.apiFlags);
         qemuMigrationJobFinish(driver, vm);
     } else {
         qemuMigrationJobContinue(vm);
@@ -5019,6 +5033,7 @@ qemuMigrationDstFinish(virQEMUDriverPtr driver,
     virErrorPtr orig_err = NULL;
     int cookie_flags = 0;
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobPrivatePtr jobPriv = priv->job.privateData;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
     unsigned short port;
     unsigned long long timeReceived = 0;
@@ -5272,7 +5287,7 @@ qemuMigrationDstFinish(virQEMUDriverPtr driver,
     }
 
     qemuMigrationParamsReset(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN,
-                             priv->job.migParams, priv->job.apiFlags);
+                             jobPriv->migParams, priv->job.apiFlags);
 
     qemuMigrationJobFinish(driver, vm);
     if (!virDomainObjIsActive(vm))
diff --git a/src/qemu/qemu_migration_cookie.c b/src/qemu/qemu_migration_cookie.c
index fb8b5bcd92..b5f4647539 100644
--- a/src/qemu/qemu_migration_cookie.c
+++ b/src/qemu/qemu_migration_cookie.c
@@ -641,7 +641,8 @@ static void
 qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf,
                                        qemuDomainJobInfoPtr jobInfo)
 {
-    qemuMonitorMigrationStats *stats = &jobInfo->stats.mig;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = jobInfo->privateData;
+    qemuMonitorMigrationStats *stats = &jobInfoPriv->stats.mig;
 
     virBufferAddLit(buf, "<statistics>\n");
     virBufferAdjustIndent(buf, 2);
@@ -1044,6 +1045,7 @@ static qemuDomainJobInfoPtr
 qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt)
 {
     qemuDomainJobInfoPtr jobInfo = NULL;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv = NULL;
     qemuMonitorMigrationStats *stats;
     VIR_XPATH_NODE_AUTORESTORE(ctxt);
 
@@ -1051,8 +1053,9 @@ qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt)
         return NULL;
 
     jobInfo = g_new0(qemuDomainJobInfo, 1);
+    jobInfoPriv = jobInfo->privateData;
 
-    stats = &jobInfo->stats.mig;
+    stats = &jobInfoPriv->stats.mig;
     jobInfo->status = QEMU_DOMAIN_JOB_STATUS_COMPLETED;
 
     virXPathULongLong("string(./started[1])", ctxt, &jobInfo->started);
diff --git a/src/qemu/qemu_migration_params.c b/src/qemu/qemu_migration_params.c
index 6953badcfe..ba3eb14831 100644
--- a/src/qemu/qemu_migration_params.c
+++ b/src/qemu/qemu_migration_params.c
@@ -953,6 +953,7 @@ qemuMigrationParamsEnableTLS(virQEMUDriverPtr driver,
                              qemuMigrationParamsPtr migParams)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobPrivatePtr jobPriv = priv->job.privateData;
     virJSONValuePtr tlsProps = NULL;
     virJSONValuePtr secProps = NULL;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
@@ -965,7 +966,7 @@ qemuMigrationParamsEnableTLS(virQEMUDriverPtr driver,
         goto error;
     }
 
-    if (!priv->job.migParams->params[QEMU_MIGRATION_PARAM_TLS_CREDS].set) {
+    if (!jobPriv->migParams->params[QEMU_MIGRATION_PARAM_TLS_CREDS].set) {
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                        _("TLS migration is not supported with this "
                          "QEMU binary"));
@@ -1038,8 +1039,9 @@ qemuMigrationParamsDisableTLS(virDomainObjPtr vm,
                               qemuMigrationParamsPtr migParams)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobPrivatePtr jobPriv = priv->job.privateData;
 
-    if (!priv->job.migParams->params[QEMU_MIGRATION_PARAM_TLS_CREDS].set)
+    if (!jobPriv->migParams->params[QEMU_MIGRATION_PARAM_TLS_CREDS].set)
         return 0;
 
     if (qemuMigrationParamsSetString(migParams,
@@ -1168,6 +1170,7 @@ qemuMigrationParamsCheck(virQEMUDriverPtr driver,
                          virBitmapPtr remoteCaps)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainJobPrivatePtr jobPriv = priv->job.privateData;
     qemuMigrationCapability cap;
     qemuMigrationParty party;
     size_t i;
@@ -1221,7 +1224,7 @@ qemuMigrationParamsCheck(virQEMUDriverPtr driver,
      * to ask QEMU for their current settings.
      */
 
-    return qemuMigrationParamsFetch(driver, vm, asyncJob, &priv->job.migParams);
+    return qemuMigrationParamsFetch(driver, vm, asyncJob, &jobPriv->migParams);
 }
 
 
diff --git a/src/qemu/qemu_migration_params.h b/src/qemu/qemu_migration_params.h
index 9aea24725f..381eabbe4a 100644
--- a/src/qemu/qemu_migration_params.h
+++ b/src/qemu/qemu_migration_params.h
@@ -70,6 +70,34 @@ typedef enum {
     QEMU_MIGRATION_DESTINATION = (1 << 1),
 } qemuMigrationParty;
 
+typedef struct _qemuDomainJobPrivate qemuDomainJobPrivate;
+typedef qemuDomainJobPrivate *qemuDomainJobPrivatePtr;
+struct _qemuDomainJobPrivate {
+    bool spiceMigration;                /* we asked for spice migration and we
+                                         * should wait for it to finish */
+    bool spiceMigrated;                 /* spice migration completed */
+    bool dumpCompleted;                 /* dump completed */
+    qemuMigrationParamsPtr migParams;
+};
+
+
+typedef struct _qemuDomainBackupStats qemuDomainBackupStats;
+struct _qemuDomainBackupStats {
+    unsigned long long transferred;
+    unsigned long long total;
+    unsigned long long tmp_used;
+    unsigned long long tmp_total;
+};
+
+typedef struct _qemuDomainJobInfoPrivate qemuDomainJobInfoPrivate;
+typedef qemuDomainJobInfoPrivate *qemuDomainJobInfoPrivatePtr;
+struct _qemuDomainJobInfoPrivate {
+    union {
+            qemuMonitorMigrationStats mig;
+            qemuMonitorDumpStats dump;
+            qemuDomainBackupStats backup;
+        } stats;
+};
 
 virBitmapPtr
 qemuMigrationParamsGetAlwaysOnCaps(qemuMigrationParty party);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index d36088ba98..97c6b2ec27 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1608,6 +1608,7 @@ qemuProcessHandleSpiceMigrated(qemuMonitorPtr mon G_GNUC_UNUSED,
                                void *opaque G_GNUC_UNUSED)
 {
     qemuDomainObjPrivatePtr priv;
+    qemuDomainJobPrivatePtr jobPriv;
 
     virObjectLock(vm);
 
@@ -1615,12 +1616,13 @@ qemuProcessHandleSpiceMigrated(qemuMonitorPtr mon G_GNUC_UNUSED,
               vm, vm->def->name);
 
     priv = vm->privateData;
+    jobPriv = priv->job.privateData;
     if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
         VIR_DEBUG("got SPICE_MIGRATE_COMPLETED event without a migration job");
         goto cleanup;
     }
 
-    priv->job.spiceMigrated = true;
+    jobPriv->spiceMigrated = true;
     virDomainObjBroadcast(vm);
 
  cleanup:
@@ -1636,6 +1638,7 @@ qemuProcessHandleMigrationStatus(qemuMonitorPtr mon G_GNUC_UNUSED,
                                  void *opaque)
 {
     qemuDomainObjPrivatePtr priv;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv;
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
@@ -1648,12 +1651,13 @@ qemuProcessHandleMigrationStatus(qemuMonitorPtr mon G_GNUC_UNUSED,
               qemuMonitorMigrationStatusTypeToString(status));
 
     priv = vm->privateData;
+    jobInfoPriv = priv->job.current->privateData;
     if (priv->job.asyncJob == QEMU_ASYNC_JOB_NONE) {
         VIR_DEBUG("got MIGRATION event without a migration job");
         goto cleanup;
     }
 
-    priv->job.current->stats.mig.status = status;
+    jobInfoPriv->stats.mig.status = status;
     virDomainObjBroadcast(vm);
 
     if (status == QEMU_MONITOR_MIGRATION_STATUS_POSTCOPY &&
@@ -1720,6 +1724,8 @@ qemuProcessHandleDumpCompleted(qemuMonitorPtr mon G_GNUC_UNUSED,
                                void *opaque G_GNUC_UNUSED)
 {
     qemuDomainObjPrivatePtr priv;
+    qemuDomainJobPrivatePtr jobPriv;
+    qemuDomainJobInfoPrivatePtr jobInfoPriv;
 
     virObjectLock(vm);
 
@@ -1727,18 +1733,20 @@ qemuProcessHandleDumpCompleted(qemuMonitorPtr mon G_GNUC_UNUSED,
               vm, vm->def->name, stats, NULLSTR(error));
 
     priv = vm->privateData;
+    jobPriv = priv->job.privateData;
+    jobInfoPriv = priv->job.current->privateData;
     if (priv->job.asyncJob == QEMU_ASYNC_JOB_NONE) {
         VIR_DEBUG("got DUMP_COMPLETED event without a dump_completed job");
         goto cleanup;
     }
-    priv->job.dumpCompleted = true;
-    priv->job.current->stats.dump = *stats;
+    jobPriv->dumpCompleted = true;
+    jobInfoPriv->stats.dump = *stats;
     priv->job.error = g_strdup(error);
 
     /* Force error if extracting the DUMP_COMPLETED status failed */
     if (!error && status < 0) {
         priv->job.error = g_strdup(virGetLastErrorMessage());
-        priv->job.current->stats.dump.status = QEMU_MONITOR_DUMP_STATUS_FAILED;
+        jobInfoPriv->stats.dump.status = QEMU_MONITOR_DUMP_STATUS_FAILED;
     }
 
     virDomainObjBroadcast(vm);
@@ -3411,6 +3419,7 @@ qemuProcessRecoverMigrationIn(virQEMUDriverPtr driver,
                               virDomainState state,
                               int reason)
 {
+    qemuDomainJobPrivatePtr jobPriv = job->privateData;
     bool postcopy = (state == VIR_DOMAIN_PAUSED &&
                      reason == VIR_DOMAIN_PAUSED_POSTCOPY_FAILED) ||
                     (state == VIR_DOMAIN_RUNNING &&
@@ -3459,7 +3468,7 @@ qemuProcessRecoverMigrationIn(virQEMUDriverPtr driver,
     }
 
     qemuMigrationParamsReset(driver, vm, QEMU_ASYNC_JOB_NONE,
-                             job->migParams, job->apiFlags);
+                             jobPriv->migParams, job->apiFlags);
     return 0;
 }
 
@@ -3471,6 +3480,7 @@ qemuProcessRecoverMigrationOut(virQEMUDriverPtr driver,
                                int reason,
                                unsigned int *stopFlags)
 {
+    qemuDomainJobPrivatePtr jobPriv = job->privateData;
     bool postcopy = state == VIR_DOMAIN_PAUSED &&
                     (reason == VIR_DOMAIN_PAUSED_POSTCOPY ||
                      reason == VIR_DOMAIN_PAUSED_POSTCOPY_FAILED);
@@ -3554,7 +3564,7 @@ qemuProcessRecoverMigrationOut(virQEMUDriverPtr driver,
     }
 
     qemuMigrationParamsReset(driver, vm, QEMU_ASYNC_JOB_NONE,
-                             job->migParams, job->apiFlags);
+                             jobPriv->migParams, job->apiFlags);
     return 0;
 }
 
-- 
2.17.1

Re: [GSoC][PATCH v2] qemu_domainjob: removal of its dependency on other qemu-files
Posted by Michal Privoznik 3 years, 8 months ago
On 7/8/20 8:33 PM, Prathamesh Chavan wrote:
> It was seen that `qemu_domain.h` file depended upon
> `qemu_migration_params.h` and `qmeu_monitor.h` as they
> were required by some qemu_domainjob stuctures.
> This dependency was removed by the introduction of
> a `void *privateData` pointer. This privateData pointer
> was handled using a structure of callback functions.
> 
> Additionally, the patch also moves funcitons
> `qemuDomainObjPrivateXMLFormatJob` and
> `qemuDomainObjPrivateXMLParseJob` from `qemu_domain`
> and handles them using the callback structure of
> domain jobs.
> 
> Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>
> ---
> Previous version of this patch can be found here[1].
> 
> This patch adds a funciton to the domainJobInfo callback
> structure to specifically to copy the jobInfo privateData
> structure.
> 
> Also, it was noticed that qemuDomainNamespace was reciding
> in `qmeu_domainjob.c`, and should rather be in its original file
> `qmeu_domain.c`. hence was moved.
> 
>   src/qemu/qemu_backup.c           |  13 +-
>   src/qemu/qemu_domain.c           | 251 +-------------------
>   src/qemu/qemu_domainjob.c        | 386 ++++++++++++++++++++++++++++---
>   src/qemu/qemu_domainjob.h        |  69 ++++--
>   src/qemu/qemu_driver.c           |  21 +-
>   src/qemu/qemu_migration.c        |  45 ++--
>   src/qemu/qemu_migration_cookie.c |   7 +-
>   src/qemu/qemu_migration_params.c |   9 +-
>   src/qemu/qemu_migration_params.h |  28 +++
>   src/qemu/qemu_process.c          |  24 +-
>   10 files changed, 515 insertions(+), 338 deletions(-)

This is very large change. Can it be split into smaller patches so that 
it is easier to review? There are several things happening at the same 
time hence I think it should be possible.

Michal