During stopping mirror block jobs vm lock is droped on awating block
job events, thus next scenario is possible:
1. stop mirror block job is sent
2. migration routine awaits for block job event
3. mirror job stopped and event send
4. getting migration job info routine asks for block job info and as
qemu block job stopped and disapperaed we get no block job info.
As a result block job info for the disk will be missed in the result.
To handle this case let's ask qemu for block job info and store it
just before stopping mirror jobs. Next in getting migration job info
routine we detect this race condition and take stored block job info
instead. I guess info will be just slightly outdated and at least
will not go backwards.
---
src/qemu/qemu_migration.c | 33 ++++++++++++++++++++++++++++-----
1 file changed, 28 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 43d87a0..76c8554 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1557,6 +1557,7 @@ qemuMigrationWaitForCompletion(virQEMUDriverPtr driver,
ignore_value(qemuMigrationFetchMigrationStats(driver, vm, asyncJob,
&jobInfo->stats, true));
+ qemuMigrationFetchMirrorStats(driver, vm, asyncJob, NULL);
qemuDomainJobInfoUpdateTime(jobInfo);
qemuDomainJobInfoUpdateDowntime(jobInfo);
VIR_FREE(priv->job.completed);
@@ -5884,6 +5885,9 @@ qemuMigrationReset(virQEMUDriverPtr driver,
}
+/* Query qemu for block job stats. If @stats is not NULL then sum them up
+ * in @stats, otherwise store them in disks private area for each disk.
+ */
int
qemuMigrationFetchMirrorStats(virQEMUDriverPtr driver,
virDomainObjPtr vm,
@@ -5918,14 +5922,33 @@ qemuMigrationFetchMirrorStats(virQEMUDriverPtr driver,
virDomainDiskDefPtr disk = vm->def->disks[i];
qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
qemuMonitorBlockJobInfoPtr data;
+ unsigned long long transferred;
+ unsigned long long total;
- if (!diskPriv->migrating ||
- !(data = virHashLookup(blockinfo, disk->info.alias)))
+ if (!diskPriv->migrating)
continue;
- stats->disk_transferred += data->cur;
- stats->disk_total += data->end;
- stats->disk_remaining += data->end - data->cur;
+ data = virHashLookup(blockinfo, disk->info.alias);
+
+ if (stats) {
+ if (data) {
+ transferred = data->cur;
+ total = data->end;
+ } else {
+ /* Race condition. There is no blockjob for disk already
+ * but is has been migrating via nbd. Thanx we store job
+ * len value just before stopping mirror jobs which can be
+ * good approximation at this point.
+ */
+ total = transferred = diskPriv->blockJobLength;
+ }
+
+ stats->disk_transferred += transferred;
+ stats->disk_total += total;
+ stats->disk_remaining += total - transferred;
+ } else if (data) {
+ diskPriv->blockJobLength = data->end;
+ }
}
virHashFree(blockinfo);
--
1.8.3.1