qemu: Parse more fields from query-migrate QMP command

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.
This commit is contained in:
Jiri Denemark 2013-02-08 09:58:03 +01:00
parent 38ab12251e
commit 4121a77c1a
9 changed files with 191 additions and 111 deletions

View File

@ -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));
}

View File

@ -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 */
};

View File

@ -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.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 = memTotal;
priv->job.info.memRemaining = memRemaining;
priv->job.info.memProcessed = memProcessed;
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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}
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;
}
}
if (virJSONValueObjectGetNumberUlong(disk, "transferred", &t) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("disk migration was active, but 'transferred' "
"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;
}
}
*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;
}
*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;
}
*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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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,