[libvirt] [REBASE PATCH v2 00/10] Implement query-dump command

Original v2: https://www.redhat.com/archives/libvir-list/2017-November/msg00779.html Rebase due to additional capabilitiies v2 Cover: v1: https://www.redhat.com/archives/libvir-list/2017-November/msg00731.html Differences from v1 (besides more patches) Rather than use a timing loop in order to fetch the dump stats and the presence of the 'query-dump' command, let's use the DUMP_COMPLETED event and wire that up in order to determine when the dump has been completed. In the mean time, the previous timing loop is converted into a qemuDomainGetJobInfoDumpStats to be called if the "right conditions" exist. Also found/fixed a couple of minor issues from v1 regarding usage "dumpformat" instead of just "format" from my patch 2 adjustment and a type for qemuMonitorDumpStatus (was qemuMontiorDumpStatus in v1). NB: (from v1 cover): Details in the patches. Essentially though QEMU 2.6 added the ability to perform the 'dump-guest-memory' via a thread by adding a 'detach' boolean to the command. In order to watch the progress of the thread the 'query-dump' command was added. The query-dump will return just the current status, the total size to be dumped, and the current progress. So using the migrate stats data in the DomainJobInfo we can then save our current progress allowing tools such as virsh to watch that progress. As an added benefit, the dump-guest-memory is now truly asynchronous. John Ferlan (10): qemu: Clean up style for the qemuDumpToFd definition qemu: Alter dump-guest-memory command generation qemu: Add support for DUMP_COMPLETED event qemu: Introduce qemuProcessHandleDumpCompleted qemu: Introduce qemuMonitor[JSON]QueryDump qemu: Add new parameter to qemuMonitorDumpToFd qemu: Introduce qemuDomainGetJobInfoMigrationStats qemu: Introduce qemuDomainGetJobInfoDumpStats qemu: Add dump completed event to the capabilities qemu: Allow showing the dump progress for memory only dump src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_domain.c | 2 + src/qemu/qemu_domain.h | 2 + src/qemu/qemu_driver.c | 157 ++++++++++++++++++--- src/qemu/qemu_monitor.c | 39 ++++- src/qemu/qemu_monitor.h | 33 ++++- src/qemu/qemu_monitor_json.c | 122 ++++++++++++++-- src/qemu/qemu_monitor_json.h | 7 +- src/qemu/qemu_process.c | 23 +++ .../caps_2.10.0-gicv2.aarch64.xml | 1 + .../caps_2.10.0-gicv3.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml | 1 + .../caps_2.6.0-gicv2.aarch64.xml | 1 + .../caps_2.6.0-gicv3.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.7.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml | 1 + tests/qemumonitorjsontest.c | 3 +- 27 files changed, 365 insertions(+), 42 deletions(-) -- 2.13.6

Alter the function definition to follow more recent style Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 5eae7d24a..f8ccc8879 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3750,9 +3750,13 @@ qemuDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags) return ret; } -static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm, - int fd, qemuDomainAsyncJob asyncJob, - const char *dumpformat) + +static int +qemuDumpToFd(virQEMUDriverPtr driver, + virDomainObjPtr vm, + int fd, + qemuDomainAsyncJob asyncJob, + const char *dumpformat) { qemuDomainObjPrivatePtr priv = vm->privateData; int ret = -1; @@ -3793,6 +3797,7 @@ static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm, return ret; } + static int doCoreDump(virQEMUDriverPtr driver, virDomainObjPtr vm, -- 2.13.6

On Tue, Dec 05, 2017 at 06:44:34 -0500, John Ferlan wrote:
Alter the function definition to follow more recent style
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
ACK Jirka

The qemuMonitorJSONMakeCommand can properly handle a NULL string by using the "S:" parameter instead of "s:", so let's use that of having in if/else condition that only adds the "s:". Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor_json.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 64394f76f..2c01c99bf 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -3165,19 +3165,11 @@ qemuMonitorJSONDump(qemuMonitorPtr mon, virJSONValuePtr cmd = NULL; virJSONValuePtr reply = NULL; - if (dumpformat) { - cmd = qemuMonitorJSONMakeCommand("dump-guest-memory", - "b:paging", false, - "s:protocol", protocol, - "s:format", dumpformat, - NULL); - } else { - cmd = qemuMonitorJSONMakeCommand("dump-guest-memory", - "b:paging", false, - "s:protocol", protocol, - NULL); - } - + cmd = qemuMonitorJSONMakeCommand("dump-guest-memory", + "b:paging", false, + "s:protocol", protocol, + "S:format", dumpformat, + NULL); if (!cmd) return -1; -- 2.13.6

On Tue, Dec 05, 2017 at 06:44:35 -0500, John Ferlan wrote:
The qemuMonitorJSONMakeCommand can properly handle a NULL string by using the "S:" parameter instead of "s:", so let's use that of having in if/else condition that only adds the "s:".
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor_json.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-)
ACK Jirka

The event is fired when the domain memory only dump completes. Wire up the code to extract and send along the status. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor.c | 18 ++++++++++++++++++ src/qemu/qemu_monitor.h | 19 +++++++++++++++++++ src/qemu/qemu_monitor_json.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 473a52735..ae64edd95 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -202,6 +202,10 @@ VIR_ENUM_IMPL(qemuMonitorBlockIOStatus, QEMU_MONITOR_BLOCK_IO_STATUS_LAST, "ok", "failed", "nospace") +VIR_ENUM_IMPL(qemuMonitorDumpStatus, + QEMU_MONITOR_DUMP_STATUS_LAST, + "none", "active", "completed", "failed") + char * qemuMonitorEscapeArg(const char *in) { @@ -1655,6 +1659,20 @@ qemuMonitorEmitBlockThreshold(qemuMonitorPtr mon, int +qemuMonitorEmitDumpCompleted(qemuMonitorPtr mon, + qemuMonitorDumpStatus status) +{ + int ret = -1; + + VIR_DEBUG("mon=%p", mon); + + QEMU_MONITOR_CALLBACK(mon, ret, domainDumpCompleted, mon->vm, status); + + return ret; +} + + +int qemuMonitorSetCapabilities(qemuMonitorPtr mon) { QEMU_CHECK_MONITOR(mon); diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index f81fb7f2a..ab4c67ef3 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -245,6 +245,21 @@ typedef int (*qemuMonitorDomainBlockThresholdCallback)(qemuMonitorPtr mon, unsigned long long excess, void *opaque); +typedef enum { + QEMU_MONITOR_DUMP_STATUS_NONE, + QEMU_MONITOR_DUMP_STATUS_ACTIVE, + QEMU_MONITOR_DUMP_STATUS_COMPLETED, + QEMU_MONITOR_DUMP_STATUS_FAILED, + + QEMU_MONITOR_DUMP_STATUS_LAST, +} qemuMonitorDumpStatus; + +VIR_ENUM_DECL(qemuMonitorDumpStatus) + +typedef int (*qemuMonitorDomainDumpCompletedCallback)(qemuMonitorPtr mon, + virDomainObjPtr vm, + qemuMonitorDumpStatus status, + void *opaque); typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks; typedef qemuMonitorCallbacks *qemuMonitorCallbacksPtr; @@ -278,6 +293,7 @@ struct _qemuMonitorCallbacks { qemuMonitorDomainMigrationPassCallback domainMigrationPass; qemuMonitorDomainAcpiOstInfoCallback domainAcpiOstInfo; qemuMonitorDomainBlockThresholdCallback domainBlockThreshold; + qemuMonitorDomainDumpCompletedCallback domainDumpCompleted; }; char *qemuMonitorEscapeArg(const char *in); @@ -406,6 +422,9 @@ int qemuMonitorEmitBlockThreshold(qemuMonitorPtr mon, unsigned long long threshold, unsigned long long excess); +int qemuMonitorEmitDumpCompleted(qemuMonitorPtr mon, + qemuMonitorDumpStatus status); + int qemuMonitorStartCPUs(qemuMonitorPtr mon, virConnectPtr conn); int qemuMonitorStopCPUs(qemuMonitorPtr mon); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2c01c99bf..7e3cdce9c 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -90,6 +90,7 @@ static void qemuMonitorJSONHandleMigrationStatus(qemuMonitorPtr mon, virJSONValu static void qemuMonitorJSONHandleMigrationPass(qemuMonitorPtr mon, virJSONValuePtr data); static void qemuMonitorJSONHandleAcpiOstInfo(qemuMonitorPtr mon, virJSONValuePtr data); static void qemuMonitorJSONHandleBlockThreshold(qemuMonitorPtr mon, virJSONValuePtr data); +static void qemuMonitorJSONHandleDumpCompleted(qemuMonitorPtr mon, virJSONValuePtr data); typedef struct { const char *type; @@ -106,6 +107,7 @@ static qemuEventHandler eventHandlers[] = { { "BLOCK_WRITE_THRESHOLD", qemuMonitorJSONHandleBlockThreshold, }, { "DEVICE_DELETED", qemuMonitorJSONHandleDeviceDeleted, }, { "DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange, }, + { "DUMP_COMPLETED", qemuMonitorJSONHandleDumpCompleted, }, { "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, }, { "MIGRATION", qemuMonitorJSONHandleMigrationStatus, }, { "MIGRATION_PASS", qemuMonitorJSONHandleMigrationPass, }, @@ -1138,6 +1140,35 @@ qemuMonitorJSONHandleBlockThreshold(qemuMonitorPtr mon, virJSONValuePtr data) } +static void +qemuMonitorJSONHandleDumpCompleted(qemuMonitorPtr mon, + virJSONValuePtr data) +{ + const char *statusstr; + qemuMonitorDumpStatus status; + virJSONValuePtr result; + + if (!(result = virJSONValueObjectGetObject(data, "result"))) { + VIR_WARN("missing result in dump completed event"); + return; + } + + if (!(statusstr = virJSONValueObjectGetString(result, "status"))) { + VIR_WARN("missing status string in dump completed event"); + return; + } + + status = qemuMonitorDumpStatusTypeFromString(statusstr); + if (status < 0) { + VIR_WARN("invalid status string '%s' in dump completed event", + statusstr); + return; + } + + qemuMonitorEmitDumpCompleted(mon, status); +} + + int qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon, const char *cmd_str, -- 2.13.6

Add a couple of booleans to mark when there's a dump completion event waiting and when a dump completed event has been received. To ensure the dump completed event from a non memory-only dump doesn't cause the a dump completed event to be fired, only broadcast if there's a completion event waiting. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_domain.c | 2 ++ src/qemu/qemu_domain.h | 2 ++ src/qemu/qemu_process.c | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index e8e03134f..41da30eb8 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -334,6 +334,8 @@ qemuDomainObjResetAsyncJob(qemuDomainObjPrivatePtr priv) job->spiceMigration = false; job->spiceMigrated = false; job->postcopyEnabled = false; + job->dumpCompletion = false; + job->dumpCompleted = false; VIR_FREE(job->current); } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index c33af3671..441edb6dd 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -164,6 +164,8 @@ struct qemuDomainJobObj { * should wait for it to finish */ bool spiceMigrated; /* spice migration completed */ bool postcopyEnabled; /* post-copy migration was enabled */ + bool dumpCompletion; /* waiting for dump completion */ + bool dumpCompleted; /* dump completed */ }; typedef void (*qemuDomainCleanupCallback)(virQEMUDriverPtr driver, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index ea70885dd..d1c4c2175 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1687,6 +1687,28 @@ qemuProcessHandleMigrationPass(qemuMonitorPtr mon ATTRIBUTE_UNUSED, } +static int +qemuProcessHandleDumpCompleted(qemuMonitorPtr mon ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + qemuMonitorDumpStatus status, + void *opaque ATTRIBUTE_UNUSED) +{ + qemuDomainObjPrivatePtr priv; + + virObjectLock(vm); + + VIR_DEBUG("Dump completed for domain %p %s with status=%s", + vm, vm->def->name, qemuMonitorDumpStatusTypeToString(status)); + + priv = vm->privateData; + priv->job.dumpCompleted = true; + if (priv->job.dumpCompletion) + virDomainObjBroadcast(vm); + virObjectUnlock(vm); + return 0; +} + + static qemuMonitorCallbacks monitorCallbacks = { .eofNotify = qemuProcessHandleMonitorEOF, .errorNotify = qemuProcessHandleMonitorError, @@ -1715,6 +1737,7 @@ static qemuMonitorCallbacks monitorCallbacks = { .domainMigrationPass = qemuProcessHandleMigrationPass, .domainAcpiOstInfo = qemuProcessHandleAcpiOstInfo, .domainBlockThreshold = qemuProcessHandleBlockThreshold, + .domainDumpCompleted = qemuProcessHandleDumpCompleted, }; static void -- 2.13.6

Add the query-dump API's in order to allow the dump-guest-memory to be used to monitor progress. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor.c | 14 +++++++++ src/qemu/qemu_monitor.h | 11 +++++++ src/qemu/qemu_monitor_json.c | 69 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 +++ 4 files changed, 98 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index ae64edd95..41a04dd00 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2760,6 +2760,20 @@ qemuMonitorMigrateCancel(qemuMonitorPtr mon) } +int +qemuMonitorQueryDump(qemuMonitorPtr mon, + qemuMonitorDumpStatsPtr stats) +{ + QEMU_CHECK_MONITOR(mon); + + /* No capability is supported without JSON monitor */ + if (!mon->json) + return 0; + + return qemuMonitorJSONQueryDump(mon, stats); +} + + /** * Returns 1 if @capability is supported, 0 if it's not, or -1 on error. */ diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index ab4c67ef3..b4322e360 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -775,6 +775,17 @@ int qemuMonitorMigrateCancel(qemuMonitorPtr mon); int qemuMonitorGetDumpGuestMemoryCapability(qemuMonitorPtr mon, const char *capability); +typedef struct _qemuMonitorDumpStats qemuMonitorDumpStats; +typedef qemuMonitorDumpStats *qemuMonitorDumpStatsPtr; +struct _qemuMonitorDumpStats { + int status; /* qemuMonitorDumpStatus */ + unsigned long long completed; /* bytes written */ + unsigned long long total; /* total bytes to be written */ +}; + +int qemuMonitorQueryDump(qemuMonitorPtr mon, + qemuMonitorDumpStatsPtr stats); + int qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd, const char *dumpformat); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 7e3cdce9c..f29588c4d 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -3131,6 +3131,75 @@ int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon) return ret; } + +/* qemuMonitorJSONQueryDump: + * @mon: Monitor pointer + * @stats: Dump "stats" + * + * Attempt to make a "query-dump" call, check for errors, and get/return + * the current from the reply + * + * Returns: 0 on success, -1 on failure + */ +int +qemuMonitorJSONQueryDump(qemuMonitorPtr mon, + qemuMonitorDumpStatsPtr stats) +{ + int ret = -1; + virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-dump", NULL); + virJSONValuePtr reply = NULL; + virJSONValuePtr result = NULL; + const char *statusstr; + + if (!cmd) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + if (!(result = virJSONValueObjectGetObject(reply, "return"))) + goto cleanup; + + if (!(statusstr = virJSONValueObjectGetString(result, "status"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("incomplete result, failed to get status")); + goto cleanup; + } + + stats->status = qemuMonitorDumpStatusTypeFromString(statusstr); + if (stats->status < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("incomplete result, unknown status string '%s'"), + statusstr); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUlong(result, "completed", + &stats->completed) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("incomplete result, failed to get completed")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUlong(result, "total", &stats->total) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("incomplete result, failed to get total")); + goto cleanup; + } + + ret = 0; + + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + virJSONValueFree(result); + return ret; +} + + int qemuMonitorJSONGetDumpGuestMemoryCapability(qemuMonitorPtr mon, const char *capability) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 739a99293..090e3a144 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -162,6 +162,10 @@ int qemuMonitorJSONGetSpiceMigrationStatus(qemuMonitorPtr mon, int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon); +int +qemuMonitorJSONQueryDump(qemuMonitorPtr mon, + qemuMonitorDumpStatsPtr stats); + int qemuMonitorJSONGetDumpGuestMemoryCapability(qemuMonitorPtr mon, const char *capability); -- 2.13.6

Add a @detach parameter to the API in order allow running the QEMU code as a thread. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_monitor.c | 7 +++++-- src/qemu/qemu_monitor.h | 3 ++- src/qemu/qemu_monitor_json.c | 4 +++- src/qemu/qemu_monitor_json.h | 3 ++- tests/qemumonitorjsontest.c | 3 ++- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f8ccc8879..7c8233069 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3789,7 +3789,7 @@ qemuDumpToFd(virQEMUDriverPtr driver, } } - ret = qemuMonitorDumpToFd(priv->mon, fd, dumpformat); + ret = qemuMonitorDumpToFd(priv->mon, fd, dumpformat, false); cleanup: ignore_value(qemuDomainObjExitMonitor(driver, vm)); diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 41a04dd00..259030f94 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2794,7 +2794,10 @@ qemuMonitorGetDumpGuestMemoryCapability(qemuMonitorPtr mon, int -qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd, const char *dumpformat) +qemuMonitorDumpToFd(qemuMonitorPtr mon, + int fd, + const char *dumpformat, + bool detach) { int ret; VIR_DEBUG("fd=%d dumpformat=%s", fd, dumpformat); @@ -2804,7 +2807,7 @@ qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd, const char *dumpformat) if (qemuMonitorSendFileHandle(mon, "dump", fd) < 0) return -1; - ret = qemuMonitorJSONDump(mon, "fd:dump", dumpformat); + ret = qemuMonitorJSONDump(mon, "fd:dump", dumpformat, detach); if (ret < 0) { if (qemuMonitorCloseFileHandle(mon, "dump") < 0) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index b4322e360..c578a1f45 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -788,7 +788,8 @@ int qemuMonitorQueryDump(qemuMonitorPtr mon, int qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd, - const char *dumpformat); + const char *dumpformat, + bool detach); int qemuMonitorGraphicsRelocate(qemuMonitorPtr mon, int type, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index f29588c4d..90cc785f9 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -3259,7 +3259,8 @@ qemuMonitorJSONGetDumpGuestMemoryCapability(qemuMonitorPtr mon, int qemuMonitorJSONDump(qemuMonitorPtr mon, const char *protocol, - const char *dumpformat) + const char *dumpformat, + bool detach) { int ret = -1; virJSONValuePtr cmd = NULL; @@ -3269,6 +3270,7 @@ qemuMonitorJSONDump(qemuMonitorPtr mon, "b:paging", false, "s:protocol", protocol, "S:format", dumpformat, + "B:detach", detach, NULL); if (!cmd) return -1; diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 090e3a144..5baddbc8a 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -171,7 +171,8 @@ int qemuMonitorJSONGetDumpGuestMemoryCapability(qemuMonitorPtr mon, int qemuMonitorJSONDump(qemuMonitorPtr mon, const char *protocol, - const char *dumpformat); + const char *dumpformat, + bool detach); int qemuMonitorJSONGraphicsRelocate(qemuMonitorPtr mon, int type, diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index fe46a33eb..1eeefbce9 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -1330,7 +1330,8 @@ GEN_TEST_FUNC(qemuMonitorJSONSetMigrationDowntime, 1) GEN_TEST_FUNC(qemuMonitorJSONMigrate, QEMU_MONITOR_MIGRATE_BACKGROUND | QEMU_MONITOR_MIGRATE_NON_SHARED_DISK | QEMU_MONITOR_MIGRATE_NON_SHARED_INC, "tcp:localhost:12345") -GEN_TEST_FUNC(qemuMonitorJSONDump, "dummy_protocol", "dummy_memory_dump_format") +GEN_TEST_FUNC(qemuMonitorJSONDump, "dummy_protocol", "dummy_memory_dump_format", + true) GEN_TEST_FUNC(qemuMonitorJSONGraphicsRelocate, VIR_DOMAIN_GRAPHICS_TYPE_SPICE, "localhost", 12345, 12346, NULL) GEN_TEST_FUNC(qemuMonitorJSONAddNetdev, "some_dummy_netdevstr") -- 2.13.6

Extract out the parts of qemuDomainGetJobStatsInternal that get the migration stats. We're about to add the ability to get just dump information. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 52 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 7c8233069..cb67b0e2e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13146,13 +13146,43 @@ qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, static int +qemuDomainGetJobInfoMigrationStats(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuDomainJobInfoPtr jobInfo) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + bool events = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_EVENT); + + if (jobInfo->status == QEMU_DOMAIN_JOB_STATUS_ACTIVE || + jobInfo->status == QEMU_DOMAIN_JOB_STATUS_MIGRATING || + jobInfo->status == QEMU_DOMAIN_JOB_STATUS_QEMU_COMPLETED || + jobInfo->status == QEMU_DOMAIN_JOB_STATUS_POSTCOPY) { + if (events && + jobInfo->status != QEMU_DOMAIN_JOB_STATUS_ACTIVE && + qemuMigrationFetchStats(driver, vm, QEMU_ASYNC_JOB_NONE, + jobInfo, NULL) < 0) + return -1; + + if (jobInfo->status == QEMU_DOMAIN_JOB_STATUS_ACTIVE && + qemuMigrationFetchMirrorStats(driver, vm, QEMU_ASYNC_JOB_NONE, + jobInfo) < 0) + return -1; + + if (qemuDomainJobInfoUpdateTime(jobInfo) < 0) + return -1; + } + + return 0; +} + + +static int qemuDomainGetJobStatsInternal(virQEMUDriverPtr driver, virDomainObjPtr vm, bool completed, qemuDomainJobInfoPtr jobInfo) { qemuDomainObjPrivatePtr priv = vm->privateData; - bool events = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_EVENT); int ret = -1; if (completed) { @@ -13187,24 +13217,8 @@ qemuDomainGetJobStatsInternal(virQEMUDriverPtr driver, } *jobInfo = *priv->job.current; - if (jobInfo->status == QEMU_DOMAIN_JOB_STATUS_ACTIVE || - jobInfo->status == QEMU_DOMAIN_JOB_STATUS_MIGRATING || - jobInfo->status == QEMU_DOMAIN_JOB_STATUS_QEMU_COMPLETED || - jobInfo->status == QEMU_DOMAIN_JOB_STATUS_POSTCOPY) { - if (events && - jobInfo->status != QEMU_DOMAIN_JOB_STATUS_ACTIVE && - qemuMigrationFetchStats(driver, vm, QEMU_ASYNC_JOB_NONE, - jobInfo, NULL) < 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; - } + if (qemuDomainGetJobInfoMigrationStats(driver, vm, jobInfo) < 0) + goto cleanup; ret = 0; -- 2.13.6

Add an API to allow fetching the Dump statistics for the job via the qemuDomainGetJobInfo API. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index cb67b0e2e..d921a5e78 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13177,6 +13177,53 @@ qemuDomainGetJobInfoMigrationStats(virQEMUDriverPtr driver, static int +qemuDomainGetJobInfoDumpStats(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuDomainJobInfoPtr jobInfo) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + qemuMonitorDumpStats stats; + int rv; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_NONE) < 0) + return -1; + + rv = qemuMonitorQueryDump(priv->mon, &stats); + + if (qemuDomainObjExitMonitor(driver, vm) < 0 || rv < 0) + return -1; + + /* Save the stats in the migration stats so that qemuDomainJobInfoToInfo + * will be copy properly */ + jobInfo->stats.ram_total = stats.total; + jobInfo->stats.ram_remaining = stats.total - stats.completed; + jobInfo->stats.ram_transferred = stats.completed; + switch (stats.status) { + case QEMU_MONITOR_DUMP_STATUS_NONE: + case QEMU_MONITOR_DUMP_STATUS_FAILED: + case QEMU_MONITOR_DUMP_STATUS_LAST: + virReportError(VIR_ERR_OPERATION_FAILED, + _("dump query failed, status=%d"), stats.status); + return -1; + break; + + case QEMU_MONITOR_DUMP_STATUS_ACTIVE: + jobInfo->status = QEMU_DOMAIN_JOB_STATUS_ACTIVE; + VIR_DEBUG("dump active, bytes written='%llu' remaining='%llu'", + stats.completed, stats.total - stats.completed); + break; + + case QEMU_MONITOR_DUMP_STATUS_COMPLETED: + jobInfo->status = QEMU_DOMAIN_JOB_STATUS_COMPLETED; + VIR_DEBUG("dump completed, bytes written='%llu'", stats.completed); + break; + } + + return 0; +} + + +static int qemuDomainGetJobStatsInternal(virQEMUDriverPtr driver, virDomainObjPtr vm, bool completed, @@ -13217,8 +13264,13 @@ qemuDomainGetJobStatsInternal(virQEMUDriverPtr driver, } *jobInfo = *priv->job.current; - if (qemuDomainGetJobInfoMigrationStats(driver, vm, jobInfo) < 0) - goto cleanup; + if (priv->job.asyncJob == QEMU_ASYNC_JOB_DUMP && priv->job.dumpCompletion) { + if (qemuDomainGetJobInfoDumpStats(driver, vm, jobInfo) < 0) + goto cleanup; + } else { + if (qemuDomainGetJobInfoMigrationStats(driver, vm, jobInfo) < 0) + goto cleanup; + } ret = 0; -- 2.13.6

Add the DUMP_COMPLETED check to the capabilities. This is the mechanism used to determine whether the dump-guest-memory command can support the "-detach" option and thus be able to wait on the event and allow for a query of the progress of the dump. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_2.10.0-gicv2.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0-gicv3.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.7.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml | 1 + 18 files changed, 19 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 29714855b..8b5dc6a0a 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -456,6 +456,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, /* 280 */ "pl011", + "dump-completed", ); @@ -1589,6 +1590,7 @@ struct virQEMUCapsStringFlags virQEMUCapsEvents[] = { { "VSERPORT_CHANGE", QEMU_CAPS_VSERPORT_CHANGE }, { "DEVICE_TRAY_MOVED", QEMU_CAPS_DEVICE_TRAY_MOVED }, { "BLOCK_WRITE_THRESHOLD", QEMU_CAPS_BLOCK_WRITE_THRESHOLD }, + { "DUMP_COMPLETED", QEMU_CAPS_DUMP_COMPLETED }, }; struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 9f239a0ec..5b767b773 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -442,6 +442,7 @@ typedef enum { /* 280 */ QEMU_CAPS_DEVICE_PL011, /* -device pl011 (not user-instantiable) */ + QEMU_CAPS_DUMP_COMPLETED, /* DUMP_COMPLETED event */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_2.10.0-gicv2.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.10.0-gicv2.aarch64.xml index eeb1840d3..80283d25a 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0-gicv2.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0-gicv2.aarch64.xml @@ -185,6 +185,7 @@ <flag name='iscsi.password-secret'/> <flag name='isa-serial'/> <flag name='pl011'/> + <flag name='dump-completed'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <package> (v2.10.0)</package> diff --git a/tests/qemucapabilitiesdata/caps_2.10.0-gicv3.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.10.0-gicv3.aarch64.xml index 1e7b95ec0..dfccd319b 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0-gicv3.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0-gicv3.aarch64.xml @@ -185,6 +185,7 @@ <flag name='iscsi.password-secret'/> <flag name='isa-serial'/> <flag name='pl011'/> + <flag name='dump-completed'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <package> (v2.10.0)</package> diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml b/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml index ca55e11eb..51b5b7231 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml @@ -183,6 +183,7 @@ <flag name='disk-share-rw'/> <flag name='iscsi.password-secret'/> <flag name='isa-serial'/> + <flag name='dump-completed'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <package> (v2.10.0)</package> diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml index 64e70f54b..3bb6f8c61 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml @@ -145,6 +145,7 @@ <flag name='numa.dist'/> <flag name='disk-share-rw'/> <flag name='iscsi.password-secret'/> + <flag name='dump-completed'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml index 8fea70a52..a88bc3c2c 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml @@ -228,6 +228,7 @@ <flag name='disk-share-rw'/> <flag name='iscsi.password-secret'/> <flag name='isa-serial'/> + <flag name='dump-completed'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <package> (v2.10.0)</package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml index d3e2e18fa..816b80b41 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml @@ -174,6 +174,7 @@ <flag name='virtio-gpu.max_outputs'/> <flag name='isa-serial'/> <flag name='pl011'/> + <flag name='dump-completed'/> <version>2006000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml index bc86d0353..33064ebfd 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml @@ -174,6 +174,7 @@ <flag name='virtio-gpu.max_outputs'/> <flag name='isa-serial'/> <flag name='pl011'/> + <flag name='dump-completed'/> <version>2006000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64.xml b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64.xml index 27d99bd93..233afd41a 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64.xml @@ -169,6 +169,7 @@ <flag name='virtio-gpu.max_outputs'/> <flag name='spapr-vty'/> <flag name='isa-serial'/> + <flag name='dump-completed'/> <version>2006000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml index 97621612a..294eb7ec6 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml @@ -205,6 +205,7 @@ <flag name='chardev-reconnect'/> <flag name='virtio-gpu.max_outputs'/> <flag name='isa-serial'/> + <flag name='dump-completed'/> <version>2006000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.7.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.7.0.s390x.xml index c2f310cd4..d800c73b5 100644 --- a/tests/qemucapabilitiesdata/caps_2.7.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.7.0.s390x.xml @@ -136,6 +136,7 @@ <flag name='virtio-gpu.max_outputs'/> <flag name='virtio-blk.num-queues'/> <flag name='sclplmconsole'/> + <flag name='dump-completed'/> <version>2007000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml index e4ea9452c..9ab5a1e75 100644 --- a/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml @@ -209,6 +209,7 @@ <flag name='virtio-gpu.max_outputs'/> <flag name='virtio-blk.num-queues'/> <flag name='isa-serial'/> + <flag name='dump-completed'/> <version>2007000</version> <kvmVersion>0</kvmVersion> <package> (v2.7.0)</package> diff --git a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml index f6e024dc6..7c8ab6b8a 100644 --- a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml @@ -138,6 +138,7 @@ <flag name='virtio-gpu.max_outputs'/> <flag name='virtio-blk.num-queues'/> <flag name='sclplmconsole'/> + <flag name='dump-completed'/> <version>2007093</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml index c6d3e21d5..7b7f2d398 100644 --- a/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml @@ -211,6 +211,7 @@ <flag name='virtio-gpu.max_outputs'/> <flag name='virtio-blk.num-queues'/> <flag name='isa-serial'/> + <flag name='dump-completed'/> <version>2008000</version> <kvmVersion>0</kvmVersion> <package> (v2.8.0)</package> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml b/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml index 96aa5d59f..aff9310dc 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml @@ -177,6 +177,7 @@ <flag name='disk-share-rw'/> <flag name='iscsi.password-secret'/> <flag name='isa-serial'/> + <flag name='dump-completed'/> <version>2009000</version> <kvmVersion>0</kvmVersion> <package> (v2.9.0)</package> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml index baac0b7ae..be20d1e13 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml @@ -141,6 +141,7 @@ <flag name='sclplmconsole'/> <flag name='disk-share-rw'/> <flag name='iscsi.password-secret'/> + <flag name='dump-completed'/> <version>2009000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml index 9f489129f..5c1e8f012 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml @@ -224,6 +224,7 @@ <flag name='disk-share-rw'/> <flag name='iscsi.password-secret'/> <flag name='isa-serial'/> + <flag name='dump-completed'/> <version>2009000</version> <kvmVersion>0</kvmVersion> <package> (v2.9.0)</package> -- 2.13.6

https://bugzilla.redhat.com/show_bug.cgi?id=916061 If the QEMU version running is new enough (based on the DUMP_COMPLETED event), then we can add a 'detach' boolean to the dump-guest-memory command in order to tell QEMU to run in a thread. This ensures that we don't lock out other commands while the potentially long running dump memory is completed. This allows the usage of a qemuDumpWaitForCompletion which will wait for the event while the qemuDomainGetJobInfoDumpStats can be used via qemuDomainGetJobInfo in order to query QEMU in order to determine how far along the job is. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d921a5e78..c35963ae9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3751,6 +3751,34 @@ qemuDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags) } +/** + * qemuDumpWaitForCompletion: + * @vm: domain object + * + * If the query dump capability exists, then it's possible to start a + * guest memory dump operation using a thread via a 'detach' qualifier + * to the dump guest memory command. This allows the async check if the + * dump is done. + * + * Returns 0 on success, -1 on failure + */ +static int +qemuDumpWaitForCompletion(virDomainObjPtr vm) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + + if (!priv->job.dumpCompletion) + return 0; + + VIR_DEBUG("Waiting for dump completion"); + while (!priv->job.dumpCompleted && !priv->job.abortJob) { + if (virDomainObjWait(vm) < 0) + return -1; + } + return 0; +} + + static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm, @@ -3759,6 +3787,7 @@ qemuDumpToFd(virQEMUDriverPtr driver, const char *dumpformat) { qemuDomainObjPrivatePtr priv = vm->privateData; + bool detach = false; int ret = -1; if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY)) { @@ -3767,10 +3796,13 @@ qemuDumpToFd(virQEMUDriverPtr driver, return -1; } + detach = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_COMPLETED); + if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def, fd) < 0) return -1; - VIR_FREE(priv->job.current); + if (!detach) + VIR_FREE(priv->job.current); priv->job.dump_memory_only = true; if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) @@ -3785,15 +3817,23 @@ qemuDumpToFd(virQEMUDriverPtr driver, "for this QEMU binary"), dumpformat); ret = -1; + ignore_value(qemuDomainObjExitMonitor(driver, vm)); goto cleanup; } } - ret = qemuMonitorDumpToFd(priv->mon, fd, dumpformat, false); + ret = qemuMonitorDumpToFd(priv->mon, fd, dumpformat, detach); - cleanup: - ignore_value(qemuDomainObjExitMonitor(driver, vm)); + if (detach && ret == 0) + priv->job.dumpCompletion = true; + + if ((qemuDomainObjExitMonitor(driver, vm) < 0) || ret < 0) + goto cleanup; + + if (detach) + ret = qemuDumpWaitForCompletion(vm); + cleanup: return ret; } -- 2.13.6
participants (2)
-
Jiri Denemark
-
John Ferlan