As a side effect, this also fixes reporting disk migration process. It was added to memory migration progress, which was wrong. Disk progress has dedicated fields in virDomainJobInfo structure. --- src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 3 +- src/qemu/qemu_migration.c | 44 +++++++------ src/qemu/qemu_monitor.c | 15 +---- src/qemu/qemu_monitor.h | 34 ++++++++-- src/qemu/qemu_monitor_json.c | 150 ++++++++++++++++++++++++++++++------------- src/qemu/qemu_monitor_json.h | 5 +- src/qemu/qemu_monitor_text.c | 47 +++++++------- src/qemu/qemu_monitor_text.h | 5 +- 9 files changed, 192 insertions(+), 112 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 482f64a..eca85fc 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -160,6 +160,7 @@ qemuDomainObjResetAsyncJob(qemuDomainObjPrivatePtr priv) job->start = 0; job->dump_memory_only = false; job->asyncAbort = false; + memset(&job->status, 0, sizeof(job->status)); memset(&job->info, 0, sizeof(job->info)); } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index c9d5f8b..e4fb2f6 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -110,7 +110,8 @@ struct qemuDomainJobObj { unsigned long long mask; /* Jobs allowed during async job */ unsigned long long start; /* When the async job started */ bool dump_memory_only; /* use dump-guest-memory to do dump */ - virDomainJobInfo info; /* Async job progress data */ + qemuMonitorMigrationStatus status; /* Raw async job progress data */ + virDomainJobInfo info; /* Processed async job progress data */ bool asyncAbort; /* abort of async job requested */ }; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index de8dfec..4142872 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1198,12 +1198,11 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver, { qemuDomainObjPrivatePtr priv = vm->privateData; int ret; - int status; bool wait_for_spice = false; bool spice_migrated = false; - unsigned long long memProcessed; - unsigned long long memRemaining; - unsigned long long memTotal; + qemuMonitorMigrationStatus status; + + memset(&status, 0, sizeof(status)); /* If guest uses SPICE and supports seamles_migration we have to hold up * migration finish until SPICE server transfers its data */ @@ -1217,20 +1216,19 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver, /* Guest already exited; nothing further to update. */ return -1; } - ret = qemuMonitorGetMigrationStatus(priv->mon, - &status, - &memProcessed, - &memRemaining, - &memTotal); + ret = qemuMonitorGetMigrationStatus(priv->mon, &status); /* If qemu says migrated, check spice */ - if (wait_for_spice && (ret == 0) && - (status == QEMU_MONITOR_MIGRATION_STATUS_COMPLETED)) + if (wait_for_spice && + ret == 0 && + status.status == QEMU_MONITOR_MIGRATION_STATUS_COMPLETED) ret = qemuMonitorGetSpiceMigrationStatus(priv->mon, &spice_migrated); qemuDomainObjExitMonitor(driver, vm); + priv->job.status = status; + if (ret < 0 || virTimeMillisNow(&priv->job.info.timeElapsed) < 0) { priv->job.info.type = VIR_DOMAIN_JOB_FAILED; return -1; @@ -1238,7 +1236,7 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver, priv->job.info.timeElapsed -= priv->job.start; ret = -1; - switch (status) { + switch (priv->job.status.status) { case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE: priv->job.info.type = VIR_DOMAIN_JOB_NONE; virReportError(VIR_ERR_OPERATION_FAILED, @@ -1246,13 +1244,21 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver, break; case QEMU_MONITOR_MIGRATION_STATUS_ACTIVE: - priv->job.info.dataTotal = memTotal; - priv->job.info.dataRemaining = memRemaining; - priv->job.info.dataProcessed = memProcessed; - - priv->job.info.memTotal = memTotal; - priv->job.info.memRemaining = memRemaining; - priv->job.info.memProcessed = memProcessed; + priv->job.info.fileTotal = priv->job.status.disk_total; + priv->job.info.fileRemaining = priv->job.status.disk_remaining; + priv->job.info.fileProcessed = priv->job.status.disk_transferred; + + priv->job.info.memTotal = priv->job.status.ram_total; + priv->job.info.memRemaining = priv->job.status.ram_remaining; + priv->job.info.memProcessed = priv->job.status.ram_transferred; + + priv->job.info.dataTotal = + priv->job.status.ram_total + priv->job.status.disk_total; + priv->job.info.dataRemaining = + priv->job.status.ram_remaining + priv->job.status.disk_remaining; + priv->job.info.dataProcessed = + priv->job.status.ram_transferred + + priv->job.status.disk_transferred; ret = 0; break; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 631ff92..21489fb 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1805,10 +1805,7 @@ int qemuMonitorSetMigrationDowntime(qemuMonitorPtr mon, int qemuMonitorGetMigrationStatus(qemuMonitorPtr mon, - int *status, - unsigned long long *transferred, - unsigned long long *remaining, - unsigned long long *total) + qemuMonitorMigrationStatusPtr status) { int ret; VIR_DEBUG("mon=%p", mon); @@ -1820,15 +1817,9 @@ int qemuMonitorGetMigrationStatus(qemuMonitorPtr mon, } if (mon->json) - ret = qemuMonitorJSONGetMigrationStatus(mon, status, - transferred, - remaining, - total); + ret = qemuMonitorJSONGetMigrationStatus(mon, status); else - ret = qemuMonitorTextGetMigrationStatus(mon, status, - transferred, - remaining, - total); + ret = qemuMonitorTextGetMigrationStatus(mon, status); return ret; } diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index e3a4568..40e635d 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -338,11 +338,37 @@ enum { VIR_ENUM_DECL(qemuMonitorMigrationStatus) +typedef struct _qemuMonitorMigrationStatus qemuMonitorMigrationStatus; +typedef qemuMonitorMigrationStatus *qemuMonitorMigrationStatusPtr; +struct _qemuMonitorMigrationStatus { + int status; + unsigned long long total_time; + /* total or expected depending on status */ + bool downtime_set; + unsigned long long downtime; + + unsigned long long ram_transferred; + unsigned long long ram_remaining; + unsigned long long ram_total; + bool ram_duplicate_set; + unsigned long long ram_duplicate; + unsigned long long ram_normal; + unsigned long long ram_normal_bytes; + + unsigned long long disk_transferred; + unsigned long long disk_remaining; + unsigned long long disk_total; + + bool xbzrle_set; + unsigned long long xbzrle_cache_size; + unsigned long long xbzrle_bytes; + unsigned long long xbzrle_pages; + unsigned long long xbzrle_cache_miss; + unsigned long long xbzrle_overflow; +}; + int qemuMonitorGetMigrationStatus(qemuMonitorPtr mon, - int *status, - unsigned long long *transferred, - unsigned long long *remaining, - unsigned long long *total); + qemuMonitorMigrationStatusPtr status); int qemuMonitorGetSpiceMigrationStatus(qemuMonitorPtr mon, bool *spice_migrated); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 545d4d4..e8c1f81 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2258,14 +2258,11 @@ int qemuMonitorJSONSetMigrationDowntime(qemuMonitorPtr mon, static int qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply, - int *status, - unsigned long long *transferred, - unsigned long long *remaining, - unsigned long long *total) + qemuMonitorMigrationStatusPtr status) { virJSONValuePtr ret; const char *statusstr; - unsigned long long t; + int rc; if (!(ret = virJSONValueObjectGet(reply, "return"))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -2279,13 +2276,25 @@ qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply, return -1; } - if ((*status = qemuMonitorMigrationStatusTypeFromString(statusstr)) < 0) { + status->status = qemuMonitorMigrationStatusTypeFromString(statusstr); + if (status->status < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected migration status in %s"), statusstr); return -1; } - if (*status == QEMU_MONITOR_MIGRATION_STATUS_ACTIVE) { + virJSONValueObjectGetNumberUlong(ret, "total-time", &status->total_time); + if (status->status == QEMU_MONITOR_MIGRATION_STATUS_COMPLETED) { + rc = virJSONValueObjectGetNumberUlong(ret, "downtime", + &status->downtime); + } else { + rc = virJSONValueObjectGetNumberUlong(ret, "expected-downtime", + &status->downtime); + } + if (rc == 0) + status->downtime_set = true; + + if (status->status == QEMU_MONITOR_MIGRATION_STATUS_ACTIVE) { virJSONValuePtr ram = virJSONValueObjectGet(ret, "ram"); if (!ram) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -2294,51 +2303,112 @@ qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply, } if (virJSONValueObjectGetNumberUlong(ram, "transferred", - transferred) < 0) { + &status->ram_transferred) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("migration was active, but RAM 'transferred' " "data was missing")); return -1; } - if (virJSONValueObjectGetNumberUlong(ram, "remaining", remaining) < 0) { + if (virJSONValueObjectGetNumberUlong(ram, "remaining", + &status->ram_remaining) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("migration was active, but RAM 'remaining' " "data was missing")); return -1; } - if (virJSONValueObjectGetNumberUlong(ram, "total", total) < 0) { + if (virJSONValueObjectGetNumberUlong(ram, "total", + &status->ram_total) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("migration was active, but RAM 'total' " "data was missing")); return -1; } + if (virJSONValueObjectGetNumberUlong(ram, "duplicate", + &status->ram_duplicate) == 0) + status->ram_duplicate_set = true; + virJSONValueObjectGetNumberUlong(ram, "normal", &status->ram_normal); + virJSONValueObjectGetNumberUlong(ram, "normal-bytes", + &status->ram_normal_bytes); + virJSONValuePtr disk = virJSONValueObjectGet(ret, "disk"); - if (!disk) { - return 0; - } + if (disk) { + rc = virJSONValueObjectGetNumberUlong(disk, "transferred", + &status->disk_transferred); + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("disk migration was active, but " + "'transferred' data was missing")); + return -1; + } - if (virJSONValueObjectGetNumberUlong(disk, "transferred", &t) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("disk migration was active, but 'transferred' " - "data was missing")); - return -1; - } - *transferred += t; - if (virJSONValueObjectGetNumberUlong(disk, "remaining", &t) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("disk migration was active, but 'remaining' " - "data was missing")); - return -1; + rc = virJSONValueObjectGetNumberUlong(disk, "remaining", + &status->disk_remaining); + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("disk migration was active, but 'remaining' " + "data was missing")); + return -1; + } + + rc = virJSONValueObjectGetNumberUlong(disk, "total", + &status->disk_total); + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("disk migration was active, but 'total' " + "data was missing")); + return -1; + } } - *remaining += t; - if (virJSONValueObjectGetNumberUlong(disk, "total", &t) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("disk migration was active, but 'total' " - "data was missing")); - return -1; + + virJSONValuePtr comp = virJSONValueObjectGet(ret, "xbzrle-cache"); + if (comp) { + status->xbzrle_set = true; + rc = virJSONValueObjectGetNumberUlong(comp, "cache-size", + &status->xbzrle_cache_size); + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("XBZRLE is active, but 'cache-size' data " + "was missing")); + return -1; + } + + rc = virJSONValueObjectGetNumberUlong(comp, "bytes", + &status->xbzrle_bytes); + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("XBZRLE is active, but 'bytes' data " + "was missing")); + return -1; + } + + rc = virJSONValueObjectGetNumberUlong(comp, "pages", + &status->xbzrle_pages); + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("XBZRLE is active, but 'pages' data " + "was missing")); + return -1; + } + + rc = virJSONValueObjectGetNumberUlong(comp, "cache-miss", + &status->xbzrle_cache_miss); + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("XBZRLE is active, but 'cache-miss' data " + "was missing")); + return -1; + } + + rc = virJSONValueObjectGetNumberUlong(comp, "overflow", + &status->xbzrle_overflow); + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("XBZRLE is active, but 'overflow' data " + "was missing")); + return -1; + } } - *total += t; } return 0; @@ -2346,18 +2416,14 @@ qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply, int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon, - int *status, - unsigned long long *transferred, - unsigned long long *remaining, - unsigned long long *total) + qemuMonitorMigrationStatusPtr status) { int ret; virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-migrate", NULL); virJSONValuePtr reply = NULL; - *status = 0; - *transferred = *remaining = *total = 0; + memset(status, 0, sizeof(*status)); if (!cmd) return -1; @@ -2368,13 +2434,11 @@ int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon, ret = qemuMonitorJSONCheckError(cmd, reply); if (ret == 0 && - qemuMonitorJSONGetMigrationStatusReply(reply, - status, - transferred, - remaining, - total) < 0) + qemuMonitorJSONGetMigrationStatusReply(reply, status) < 0) ret = -1; + if (ret < 0) + memset(status, 0, sizeof(*status)); virJSONValueFree(cmd); virJSONValueFree(reply); return ret; diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 356c10a..66635fd 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -121,10 +121,7 @@ int qemuMonitorJSONSetMigrationDowntime(qemuMonitorPtr mon, unsigned long long downtime); int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon, - int *status, - unsigned long long *transferred, - unsigned long long *remaining, - unsigned long long *total); + qemuMonitorMigrationStatusPtr status); int qemuMonitorJSONGetMigrationCapability(qemuMonitorPtr mon, qemuMonitorMigrationCaps capability); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index bc0a11d..58f6323 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1474,22 +1474,14 @@ cleanup: #define MIGRATION_DISK_TOTAL_PREFIX "total disk: " int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon, - int *status, - unsigned long long *transferred, - unsigned long long *remaining, - unsigned long long *total) { + qemuMonitorMigrationStatusPtr status) +{ char *reply; char *tmp; char *end; - unsigned long long disk_transferred = 0; - unsigned long long disk_remaining = 0; - unsigned long long disk_total = 0; int ret = -1; - *status = QEMU_MONITOR_MIGRATION_STATUS_INACTIVE; - *transferred = 0; - *remaining = 0; - *total = 0; + memset(status, 0, sizeof(*status)); if (qemuMonitorHMPCommand(mon, "info migrate", &reply) < 0) return -1; @@ -1504,52 +1496,54 @@ int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon, } *end = '\0'; - if ((*status = qemuMonitorMigrationStatusTypeFromString(tmp)) < 0) { + status->status = qemuMonitorMigrationStatusTypeFromString(tmp); + if (status->status < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected migration status in %s"), reply); goto cleanup; } - if (*status == QEMU_MONITOR_MIGRATION_STATUS_ACTIVE) { + if (status->status == QEMU_MONITOR_MIGRATION_STATUS_ACTIVE) { tmp = end + 1; if (!(tmp = strstr(tmp, MIGRATION_TRANSFER_PREFIX))) goto done; tmp += strlen(MIGRATION_TRANSFER_PREFIX); - if (virStrToLong_ull(tmp, &end, 10, transferred) < 0) { + if (virStrToLong_ull(tmp, &end, 10, + &status->ram_transferred) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot parse migration data transferred " "statistic %s"), tmp); goto cleanup; } - *transferred *= 1024; + status->ram_transferred *= 1024; tmp = end; if (!(tmp = strstr(tmp, MIGRATION_REMAINING_PREFIX))) goto done; tmp += strlen(MIGRATION_REMAINING_PREFIX); - if (virStrToLong_ull(tmp, &end, 10, remaining) < 0) { + if (virStrToLong_ull(tmp, &end, 10, &status->ram_remaining) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot parse migration data remaining " "statistic %s"), tmp); goto cleanup; } - *remaining *= 1024; + status->ram_remaining *= 1024; tmp = end; if (!(tmp = strstr(tmp, MIGRATION_TOTAL_PREFIX))) goto done; tmp += strlen(MIGRATION_TOTAL_PREFIX); - if (virStrToLong_ull(tmp, &end, 10, total) < 0) { + if (virStrToLong_ull(tmp, &end, 10, &status->ram_total) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot parse migration data total " "statistic %s"), tmp); goto cleanup; } - *total *= 1024; + status->ram_total *= 1024; tmp = end; /* @@ -1559,39 +1553,40 @@ int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon, goto done; tmp += strlen(MIGRATION_DISK_TRANSFER_PREFIX); - if (virStrToLong_ull(tmp, &end, 10, &disk_transferred) < 0) { + if (virStrToLong_ull(tmp, &end, 10, + &status->disk_transferred) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot parse disk migration data " "transferred statistic %s"), tmp); goto cleanup; } - *transferred += disk_transferred * 1024; + status->disk_transferred *= 1024; tmp = end; if (!(tmp = strstr(tmp, MIGRATION_DISK_REMAINING_PREFIX))) goto done; tmp += strlen(MIGRATION_DISK_REMAINING_PREFIX); - if (virStrToLong_ull(tmp, &end, 10, &disk_remaining) < 0) { + if (virStrToLong_ull(tmp, &end, 10, &status->disk_remaining) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot parse disk migration data remaining " "statistic %s"), tmp); goto cleanup; } - *remaining += disk_remaining * 1024; + status->disk_remaining *= 1024; tmp = end; if (!(tmp = strstr(tmp, MIGRATION_DISK_TOTAL_PREFIX))) goto done; tmp += strlen(MIGRATION_DISK_TOTAL_PREFIX); - if (virStrToLong_ull(tmp, &end, 10, &disk_total) < 0) { + if (virStrToLong_ull(tmp, &end, 10, &status->disk_total) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot parse disk migration data total " "statistic %s"), tmp); goto cleanup; } - *total += disk_total * 1024; + status->disk_total *= 1024; } } @@ -1600,6 +1595,8 @@ done: cleanup: VIR_FREE(reply); + if (ret < 0) + memset(status, 0, sizeof(*status)); return ret; } diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 97abad6..fb8e904 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -117,10 +117,7 @@ int qemuMonitorTextSetMigrationDowntime(qemuMonitorPtr mon, unsigned long long downtime); int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon, - int *status, - unsigned long long *transferred, - unsigned long long *remaining, - unsigned long long *total); + qemuMonitorMigrationStatusPtr status); int qemuMonitorTextMigrate(qemuMonitorPtr mon, unsigned int flags, -- 1.8.1.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list