From 8c4665833750c66b435634678d0df2b71273e177 Mon Sep 17 00:00:00 2001
From: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com>
Date: Fri, 1 Sep 2017 09:49:30 +0300
Subject: [PATCH] qemu: migrate: add mirror stats to migration stats

When getting job info in case mirror does not reach ready phase
fetch mirror stats from qemu. Otherwise mirror stats are already
saved in current job.

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
 src/qemu/qemu_domain.c    | 31 +++++++++++++++-------
 src/qemu/qemu_domain.h    |  9 +++++++
 src/qemu/qemu_driver.c    |  5 ++++
 src/qemu/qemu_migration.c | 54 +++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_migration.h |  6 +++++
 5 files changed, 96 insertions(+), 9 deletions(-)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index dfcdb433c4..b605bbc5b1 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -448,9 +448,13 @@ qemuDomainJobInfoToInfo(qemuDomainJobInfoPtr jobInfo,
     info->memRemaining = jobInfo->stats.ram_remaining;
     info->memProcessed = jobInfo->stats.ram_transferred;
 
-    info->fileTotal = jobInfo->stats.disk_total;
-    info->fileRemaining = jobInfo->stats.disk_remaining;
-    info->fileProcessed = jobInfo->stats.disk_transferred;
+    info->fileTotal = jobInfo->stats.disk_total +
+                      jobInfo->mirrorStats.total;
+    info->fileRemaining = jobInfo->stats.disk_remaining +
+                          (jobInfo->mirrorStats.total -
+                           jobInfo->mirrorStats.transferred);
+    info->fileProcessed = jobInfo->stats.disk_transferred +
+                          jobInfo->mirrorStats.transferred;
 
     info->dataTotal = info->memTotal + info->fileTotal;
     info->dataRemaining = info->memRemaining + info->fileRemaining;
@@ -466,9 +470,12 @@ qemuDomainJobInfoToParams(qemuDomainJobInfoPtr jobInfo,
                           int *nparams)
 {
     qemuMonitorMigrationStats *stats = &jobInfo->stats;
+    qemuDomainMirrorStatsPtr mirrorStats = &jobInfo->mirrorStats;
     virTypedParameterPtr par = NULL;
     int maxpar = 0;
     int npar = 0;
+    unsigned long long mirrorRemaining = mirrorStats->total -
+                                         mirrorStats->transferred;
 
     if (virTypedParamsAddInt(&par, &npar, &maxpar,
                              VIR_DOMAIN_JOB_OPERATION,
@@ -510,15 +517,18 @@ qemuDomainJobInfoToParams(qemuDomainJobInfoPtr jobInfo,
     if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                 VIR_DOMAIN_JOB_DATA_TOTAL,
                                 stats->ram_total +
-                                stats->disk_total) < 0 ||
+                                stats->disk_total +
+                                mirrorStats->total) < 0 ||
         virTypedParamsAddULLong(&par, &npar, &maxpar,
                                 VIR_DOMAIN_JOB_DATA_PROCESSED,
                                 stats->ram_transferred +
-                                stats->disk_transferred) < 0 ||
+                                stats->disk_transferred +
+                                mirrorStats->transferred) < 0 ||
         virTypedParamsAddULLong(&par, &npar, &maxpar,
                                 VIR_DOMAIN_JOB_DATA_REMAINING,
                                 stats->ram_remaining +
-                                stats->disk_remaining) < 0)
+                                stats->disk_remaining +
+                                mirrorRemaining) < 0)
         goto error;
 
     if (virTypedParamsAddULLong(&par, &npar, &maxpar,
@@ -561,13 +571,16 @@ qemuDomainJobInfoToParams(qemuDomainJobInfoPtr jobInfo,
 
     if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                 VIR_DOMAIN_JOB_DISK_TOTAL,
-                                stats->disk_total) < 0 ||
+                                stats->disk_total +
+                                mirrorStats->total) < 0 ||
         virTypedParamsAddULLong(&par, &npar, &maxpar,
                                 VIR_DOMAIN_JOB_DISK_PROCESSED,
-                                stats->disk_transferred) < 0 ||
+                                stats->disk_transferred +
+                                mirrorStats->transferred) < 0 ||
         virTypedParamsAddULLong(&par, &npar, &maxpar,
                                 VIR_DOMAIN_JOB_DISK_REMAINING,
-                                stats->disk_remaining) < 0)
+                                stats->disk_remaining +
+                                mirrorRemaining) < 0)
         goto error;
 
     if (stats->disk_bps &&
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index f6d99b782e..834fa8ec23 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -109,6 +109,14 @@ typedef enum {
     QEMU_DOMAIN_JOB_STATUS_CANCELED,
 } qemuDomainJobStatus;
 
+
+typedef struct _qemuDomainMirrorStats qemuDomainMirrorStats;
+typedef qemuDomainMirrorStats *qemuDomainMirrorStatsPtr;
+struct _qemuDomainMirrorStats {
+    unsigned long long transferred;
+    unsigned long long total;
+};
+
 typedef struct _qemuDomainJobInfo qemuDomainJobInfo;
 typedef qemuDomainJobInfo *qemuDomainJobInfoPtr;
 struct _qemuDomainJobInfo {
@@ -130,6 +138,7 @@ struct _qemuDomainJobInfo {
     bool timeDeltaSet;
     /* Raw values from QEMU */
     qemuMonitorMigrationStats stats;
+    qemuDomainMirrorStats mirrorStats;
 };
 
 struct qemuDomainJobObj {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 24dc87a314..730add84fd 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -13016,6 +13016,11 @@ qemuDomainGetJobStatsInternal(virQEMUDriverPtr driver,
             qemuMigrationFetchStats(driver, vm, QEMU_ASYNC_JOB_NONE, jobInfo) < 0)
             goto cleanup;
 
+        if (jobInfo->status == QEMU_DOMAIN_JOB_STATUS_ACTIVE &&
+            qemuMigrationFetchMirrorStats(driver, vm, QEMU_ASYNC_JOB_NONE,
+                                          jobInfo) < 0)
+            goto cleanup;
+
         if (qemuDomainJobInfoUpdateTime(jobInfo) < 0)
             goto cleanup;
     }
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index f8fe69315b..637b44b83a 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -983,6 +983,9 @@ qemuMigrationDriveMirror(virQEMUDriverPtr driver,
             goto cleanup;
     }
 
+    qemuMigrationFetchMirrorStats(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT,
+                                  priv->job.current);
+
     /* Okay, all disks are ready. Modify migrate_flags */
     *migrate_flags &= ~(QEMU_MONITOR_MIGRATE_NON_SHARED_DISK |
                         QEMU_MONITOR_MIGRATE_NON_SHARED_INC);
@@ -5918,3 +5921,54 @@ qemuMigrationReset(virQEMUDriverPtr driver,
         virFreeError(err);
     }
 }
+
+
+int
+qemuMigrationFetchMirrorStats(virQEMUDriverPtr driver,
+                              virDomainObjPtr vm,
+                              qemuDomainAsyncJob asyncJob,
+                              qemuDomainJobInfoPtr jobInfo)
+{
+    size_t i;
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    bool nbd = false;
+    virHashTablePtr blockinfo = NULL;
+    qemuDomainMirrorStatsPtr stats = &jobInfo->mirrorStats;
+
+    for (i = 0; i < vm->def->ndisks; i++) {
+        virDomainDiskDefPtr disk = vm->def->disks[i];
+        if (QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating) {
+            nbd = true;
+            break;
+        }
+    }
+
+    if (!nbd)
+        return 0;
+
+    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
+        return -1;
+
+    blockinfo = qemuMonitorGetAllBlockJobInfo(priv->mon);
+
+    if (qemuDomainObjExitMonitor(driver, vm) < 0 || !blockinfo)
+        return -1;
+
+    memset(stats, 0, sizeof(*stats));
+
+    for (i = 0; i < vm->def->ndisks; i++) {
+        virDomainDiskDefPtr disk = vm->def->disks[i];
+        qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+        qemuMonitorBlockJobInfoPtr data;
+
+        if (!diskPriv->migrating ||
+            !(data = virHashLookup(blockinfo, disk->info.alias)))
+            continue;
+
+        stats->transferred += data->cur;
+        stats->total += data->end;
+    }
+
+    virHashFree(blockinfo);
+    return 0;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index ecb693c9f0..57c747934d 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -319,4 +319,10 @@ qemuMigrationReset(virQEMUDriverPtr driver,
                    virDomainObjPtr vm,
                    qemuDomainAsyncJob job);
 
+int
+qemuMigrationFetchMirrorStats(virQEMUDriverPtr driver,
+                              virDomainObjPtr vm,
+                              qemuDomainAsyncJob asyncJob,
+                              qemuDomainJobInfoPtr jobInfo);
+
 #endif /* __QEMU_MIGRATION_H__ */