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.
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));
}
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 */
};
{
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 */
/* 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;
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,
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;
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);
}
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;
}
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);
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",
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",
}
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;
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;
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;
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);
#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;
}
*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;
/*
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;
}
}
cleanup:
VIR_FREE(reply);
+ if (ret < 0)
+ memset(status, 0, sizeof(*status));
return ret;
}
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,