[libvirt] [PATCH v8 resend 0/4] support dumping guest memory in compressed format

From: Qiao Nuohan <qiaonuohan@cn.fujitsu.com> dumping guest's memory is introduced without compression supported, but now qemu can dump guest's memory in kdump-compressed format. This patchset is used to add support in libvirt side to let qemu do the dump in compressed format and please refer the following address to see implementation of the qemu side, the lastest version of qemu side is v9. http://lists.nongnu.org/archive/html/qemu-devel/2014-02/msg03016.html ChangLog: Changes from v7 to v8: 1. add test for qemuMonitorGetDumpGuestMemoryCapability 2. fix a bug when dumping a elf core with the an older version of qemu Changes from v6 to v7: 1. revert changing dumpformat of virDomainCoreDumpWithFormat back to an enum Changes from v5 to v6: 1. add qemuMonitorGetDumpGuestMemoryCapability API to check the available dump format Changes from v4 to v5: 1. modify some restriction check Changes from v3 to v4: 1. dropping patch "add dump_memory_format in qemu.conf" 2. fix to follow some conventions Changes from v2 to v3: 1. address Jiri Denemark's comment about adding a new public API instead of changing an old one. Changes from v1 to v2: 1. address Daniel P. Berrange's comment about using a new parameter to replace flags like VIR_DUMP_COMPRESS_ZLIB. Qiao Nuohan (4): add new virDomainCoreDumpWithFormat API qemu: add qemuMonitorGetDumpGuestMemoryCapability qemu: add support for virDomainCoreDumpWithFormat API allow "virsh dump --memory-only" specify dump format include/libvirt/libvirt.h.in | 31 ++++++++++++++ src/driver.h | 7 ++++ src/libvirt.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++ src/qemu/qemu_driver.c | 75 ++++++++++++++++++++++++++++----- src/qemu/qemu_monitor.c | 27 ++++++++++-- src/qemu/qemu_monitor.h | 6 ++- src/qemu/qemu_monitor_json.c | 85 +++++++++++++++++++++++++++++++++++--- src/qemu/qemu_monitor_json.h | 6 ++- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 15 ++++++- src/remote_protocol-structs | 7 ++++ src/test/test_driver.c | 22 ++++++++-- tests/qemumonitorjsontest.c | 45 +++++++++++++++++++- tools/virsh-domain.c | 47 +++++++++++++++++++-- tools/virsh.pod | 6 +++ 16 files changed, 454 insertions(+), 29 deletions(-) -- 1.8.5.3

From: Qiao Nuohan <qiaonuohan@cn.fujitsu.com> --memory-only option is introduced without compression supported. Now qemu has support dumping domain's memory in kdump-compressed format. This patch is adding new virDomainCoreDumpWithFormat API, so that the format in which qemu dumps domain's memory can be specified. Signed-off-by: Qiao Nuohan <qiaonuohan@cn.fujitsu.com> --- include/libvirt/libvirt.h.in | 31 ++++++++++++++ src/driver.h | 7 ++++ src/libvirt.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 15 ++++++- src/remote_protocol-structs | 7 ++++ src/test/test_driver.c | 22 ++++++++-- 8 files changed, 182 insertions(+), 4 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 82c602b..91e3e3b 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1180,6 +1180,29 @@ typedef enum { VIR_DUMP_MEMORY_ONLY = (1 << 4), /* use dump-guest-memory */ } virDomainCoreDumpFlags; +/** + * virDomainCoreDumpFormat: + * + * Values for specifying different formats of domain core dumps. + */ +typedef enum { + VIR_DOMAIN_CORE_DUMP_FORMAT_RAW, /* dump guest memory in raw format */ + VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_ZLIB, /* kdump-compressed format, with + * zlib compression */ + VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_LZO, /* kdump-compressed format, with + * lzo compression */ + VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_SNAPPY, /* kdump-compressed format, with + * snappy compression */ +#ifdef VIR_ENUM_SENTINELS + VIR_DOMAIN_CORE_DUMP_FORMAT_LAST + /* + * NB: this enum value will increase over time as new events are + * added to the libvirt API. It reflects the last state supported + * by this version of the libvirt API. + */ +#endif +} virDomainCoreDumpFormat; + /* Domain migration flags. */ typedef enum { VIR_MIGRATE_LIVE = (1 << 0), /* live migration */ @@ -1732,6 +1755,14 @@ int virDomainCoreDump (virDomainPtr domain, unsigned int flags); /* + * Domain core dump with format specified + */ +int virDomainCoreDumpWithFormat (virDomainPtr domain, + const char *to, + unsigned int dumpformat, + unsigned int flags); + +/* * Screenshot of current domain console */ char * virDomainScreenshot (virDomainPtr domain, diff --git a/src/driver.h b/src/driver.h index d728705..e66fc7a 100644 --- a/src/driver.h +++ b/src/driver.h @@ -306,6 +306,12 @@ typedef int const char *to, unsigned int flags); +typedef int +(*virDrvDomainCoreDumpWithFormat)(virDomainPtr domain, + const char *to, + unsigned int dumpformat, + unsigned int flags); + typedef char * (*virDrvDomainScreenshot)(virDomainPtr domain, virStreamPtr stream, @@ -1213,6 +1219,7 @@ struct _virDriver { virDrvDomainSaveImageGetXMLDesc domainSaveImageGetXMLDesc; virDrvDomainSaveImageDefineXML domainSaveImageDefineXML; virDrvDomainCoreDump domainCoreDump; + virDrvDomainCoreDumpWithFormat domainCoreDumpWithFormat; virDrvDomainScreenshot domainScreenshot; virDrvDomainSetVcpus domainSetVcpus; virDrvDomainSetVcpusFlags domainSetVcpusFlags; diff --git a/src/libvirt.c b/src/libvirt.c index c5c3136..551b82f 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -2999,6 +2999,104 @@ error: return -1; } +/** + * virDomainCoreDumpWithFormat: + * @domain: a domain object + * @to: path for the core file + * @dumpformat: format of domain memory's dump + * @flags: bitwise-OR of virDomainCoreDumpFlags + * + * This method will dump the core of a domain on a given file for analysis. + * Note that for remote Xen Daemon the file path will be interpreted in + * the remote host. Hypervisors may require the user to manually ensure + * proper permissions on the file named by @to. + * + * If @flags includes VIR_DUMP_MEMORY_ONLY and dumpformat is set, libvirt + * will ask qemu dump domain's memory in kdump-compressed format. + * + * If @flags includes VIR_DUMP_CRASH, then leave the guest shut off with + * a crashed state after the dump completes. If @flags includes + * VIR_DUMP_LIVE, then make the core dump while continuing to allow + * the guest to run; otherwise, the guest is suspended during the dump. + * VIR_DUMP_RESET flag forces reset of the quest after dump. + * The above three flags are mutually exclusive. + * + * Additionally, if @flags includes VIR_DUMP_BYPASS_CACHE, then libvirt + * will attempt to bypass the file system cache while creating the file, + * or fail if it cannot do so for the given system; this can allow less + * pressure on file system cache, but also risks slowing saves to NFS. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainCoreDumpWithFormat(virDomainPtr domain, const char *to, unsigned int + dumpformat, unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "to=%s, dumpformat=%u, flags=%x", + to, dumpformat, flags); + + virResetLastError(); + + virCheckDomainReturn(domain, -1); + conn = domain->conn; + + virCheckReadOnlyGoto(conn->flags, error); + virCheckNonNullArgGoto(to, error); + + if (dumpformat >= VIR_DOMAIN_CORE_DUMP_FORMAT_LAST) { + virReportInvalidArg(flags, _("dumpformat '%d' is not supported"), + dumpformat); + goto error; + } + + if ((flags & VIR_DUMP_CRASH) && (flags & VIR_DUMP_LIVE)) { + virReportInvalidArg(flags, "%s", + _("crash and live flags are mutually exclusive")); + goto error; + } + + if ((flags & VIR_DUMP_CRASH) && (flags & VIR_DUMP_RESET)) { + virReportInvalidArg(flags, "%s", + _("crash and reset flags are mutually exclusive")); + goto error; + } + + if ((flags & VIR_DUMP_LIVE) && (flags & VIR_DUMP_RESET)) { + virReportInvalidArg(flags, "%s", + _("live and reset flags are mutually exclusive")); + goto error; + } + + if (conn->driver->domainCoreDumpWithFormat) { + int ret; + char *absolute_to; + + /* We must absolutize the file path as the save is done out of process */ + if (virFileAbsPath(to, &absolute_to) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not build absolute core file path")); + goto error; + } + + ret = conn->driver->domainCoreDumpWithFormat(domain, absolute_to, + dumpformat, flags); + + VIR_FREE(absolute_to); + + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + +error: + virDispatchError(domain->conn); + return -1; +} + /** * virDomainScreenshot: diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 6ed6ce6..9ab0c92 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -645,5 +645,10 @@ LIBVIRT_1.2.1 { virConnectNetworkEventDeregisterAny; } LIBVIRT_1.1.3; +LIBVIRT_1.2.3 { + global: + virDomainCoreDumpWithFormat; +} LIBVIRT_1.2.1; + # .... define new API here using predicted next version number .... diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index f6d52e2..72545df 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7653,6 +7653,7 @@ static virDriver remote_driver = { .domainSaveImageGetXMLDesc = remoteDomainSaveImageGetXMLDesc, /* 0.9.4 */ .domainSaveImageDefineXML = remoteDomainSaveImageDefineXML, /* 0.9.4 */ .domainCoreDump = remoteDomainCoreDump, /* 0.3.0 */ + .domainCoreDumpWithFormat = remoteDomainCoreDumpWithFormat, /* 1.2.3 */ .domainScreenshot = remoteDomainScreenshot, /* 0.9.2 */ .domainSetVcpus = remoteDomainSetVcpus, /* 0.3.0 */ .domainSetVcpusFlags = remoteDomainSetVcpusFlags, /* 0.8.5 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index f1f2359..6c445cc 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -904,6 +904,13 @@ struct remote_domain_core_dump_args { unsigned int flags; }; +struct remote_domain_core_dump_with_format_args { + remote_nonnull_domain dom; + remote_nonnull_string to; + unsigned int dumpformat; + unsigned int flags; +}; + struct remote_domain_screenshot_args { remote_nonnull_domain dom; unsigned int screen; @@ -5262,5 +5269,11 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED = 333 + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED = 333, + + /** + * @generate: both + * @acl: domain:core_dump + */ + REMOTE_PROC_DOMAIN_CORE_DUMP_WITH_FORMAT = 334 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 5636d55..456d0da 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -557,6 +557,12 @@ struct remote_domain_core_dump_args { remote_nonnull_string to; u_int flags; }; +struct remote_domain_core_dump_with_format_args { + remote_nonnull_domain dom; + remote_nonnull_string to; + u_int dumpformat; + u_int flags; +}; struct remote_domain_screenshot_args { remote_nonnull_domain dom; u_int screen; @@ -2755,4 +2761,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BALLOON_CHANGE = 331, REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND_DISK = 332, REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED = 333, + REMOTE_PROC_DOMAIN_CORE_DUMP_WITH_FORMAT = 334, }; diff --git a/src/test/test_driver.c b/src/test/test_driver.c index d88d3fc..38b56d7 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -2428,9 +2428,10 @@ testDomainRestore(virConnectPtr conn, return testDomainRestoreFlags(conn, path, NULL, 0); } -static int testDomainCoreDump(virDomainPtr domain, - const char *to, - unsigned int flags) +static int testDomainCoreDumpWithFormat(virDomainPtr domain, + const char *to, + unsigned int dumpformat, + unsigned int flags) { testConnPtr privconn = domain->conn->privateData; int fd = -1; @@ -2468,6 +2469,13 @@ static int testDomainCoreDump(virDomainPtr domain, goto cleanup; } + /* we don't support non-raw formats in test driver */ + if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("kdump-compressed format is not supported here")); + goto cleanup; + } + if (flags & VIR_DUMP_CRASH) { testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_CRASHED); event = virDomainEventLifecycleNewFromObj(privdom, @@ -2491,6 +2499,13 @@ cleanup: return ret; } +static int testDomainCoreDump(virDomainPtr domain, + const char *to, + unsigned int flags) { + return testDomainCoreDumpWithFormat(domain, to, + VIR_DOMAIN_CORE_DUMP_FORMAT_RAW, flags); +} + static char *testDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) { char *ret; @@ -7383,6 +7398,7 @@ static virDriver testDriver = { .domainRestore = testDomainRestore, /* 0.3.2 */ .domainRestoreFlags = testDomainRestoreFlags, /* 0.9.4 */ .domainCoreDump = testDomainCoreDump, /* 0.3.2 */ + .domainCoreDumpWithFormat = testDomainCoreDumpWithFormat, /* 1.2.3 */ .domainSetVcpus = testDomainSetVcpus, /* 0.1.4 */ .domainSetVcpusFlags = testDomainSetVcpusFlags, /* 0.8.5 */ .domainGetVcpusFlags = testDomainGetVcpusFlags, /* 0.8.5 */ -- 1.8.5.3

On 03/22/2014 09:51 PM, Wen Congyang wrote:
From: Qiao Nuohan <qiaonuohan@cn.fujitsu.com>
--memory-only option is introduced without compression supported. Now qemu has support dumping domain's memory in kdump-compressed format. This patch is adding new virDomainCoreDumpWithFormat API, so that the format in which qemu dumps domain's memory can be specified.
Signed-off-by: Qiao Nuohan <qiaonuohan@cn.fujitsu.com> --- include/libvirt/libvirt.h.in | 31 ++++++++++++++ src/driver.h | 7 ++++ src/libvirt.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 15 ++++++- src/remote_protocol-structs | 7 ++++ src/test/test_driver.c | 22 ++++++++-- 8 files changed, 182 insertions(+), 4 deletions(-)
I'm squashing this in ('make syntax-check' was tightened in the meantime, and didn't like your test_driver change; also, the grammar of the docs in libvirt.c wasn't quite right, and it never hurts to cross-reference related API documentation). diff --git i/src/libvirt.c w/src/libvirt.c index 551b82f..d42da38 100644 --- i/src/libvirt.c +++ w/src/libvirt.c @@ -2937,6 +2937,8 @@ error: * or fail if it cannot do so for the given system; this can allow less * pressure on file system cache, but also risks slowing saves to NFS. * + * For more control over the output format, see virDomainCoreDumpWithFormat(). + * * Returns 0 in case of success and -1 in case of failure. */ int @@ -3011,8 +3013,9 @@ error: * the remote host. Hypervisors may require the user to manually ensure * proper permissions on the file named by @to. * - * If @flags includes VIR_DUMP_MEMORY_ONLY and dumpformat is set, libvirt - * will ask qemu dump domain's memory in kdump-compressed format. + * @dumpformat controls which format the dump will have; use of + * VIR_DOMAIN_CORE_DUMP_FORMAT_RAW mirrors what virDomainCoreDump() will + * perform. Not all hypervisors are able to support all formats. * * If @flags includes VIR_DUMP_CRASH, then leave the guest shut off with * a crashed state after the dump completes. If @flags includes @@ -3029,8 +3032,8 @@ error: * Returns 0 in case of success and -1 in case of failure. */ int -virDomainCoreDumpWithFormat(virDomainPtr domain, const char *to, unsigned int - dumpformat, unsigned int flags) +virDomainCoreDumpWithFormat(virDomainPtr domain, const char *to, + unsigned int dumpformat, unsigned int flags) { virConnectPtr conn; -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

From: Qiao Nuohan <qiaonuohan@cn.fujitsu.com> This patch adds qemuMonitorGetDumpGuestMemoryCapability, which is used to check whether the specified dump-guest-memory format is supported by qemu. Signed-off-by: Qiao Nuohan <qiaonuohan@cn.fujitsu.com> --- src/qemu/qemu_monitor.c | 21 ++++++++++++++ src/qemu/qemu_monitor.h | 3 ++ src/qemu/qemu_monitor_json.c | 65 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 3 ++ tests/qemumonitorjsontest.c | 43 +++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 357c970..976a954 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2368,6 +2368,27 @@ int qemuMonitorMigrateCancel(qemuMonitorPtr mon) return ret; } +/** + * Returns 1 if @capability is supported, 0 if it's not, or -1 on error. + */ +int qemuMonitorGetDumpGuestMemoryCapability(qemuMonitorPtr mon, + const char *capability) +{ + VIR_DEBUG("mon=%p capability=%s", mon, capability); + + if (!mon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("monitor must not be NULL")); + return -1; + } + + /* No capability is supported without JSON monitor */ + if (!mon->json) + return 0; + + return qemuMonitorJSONGetDumpGuestMemoryCapability(mon, capability); +} + int qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd) { diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index d8f1d10..e896911 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -506,6 +506,9 @@ int qemuMonitorMigrateToUnix(qemuMonitorPtr mon, int qemuMonitorMigrateCancel(qemuMonitorPtr mon); +int qemuMonitorGetDumpGuestMemoryCapability(qemuMonitorPtr mon, + const char *capability); + int qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 7a6aac0..ab5890b 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2658,6 +2658,71 @@ int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon) } int +qemuMonitorJSONGetDumpGuestMemoryCapability(qemuMonitorPtr mon, + const char *capability) +{ + int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + virJSONValuePtr caps; + virJSONValuePtr formats; + size_t i; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-dump-guest-memory-capability", + NULL))) + return -1; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) { + if (qemuMonitorJSONHasError(reply, "CommandNotFound")) + goto cleanup; + ret = qemuMonitorJSONCheckError(cmd, reply); + } + + if (ret < 0) + goto cleanup; + + ret = -1; + + caps = virJSONValueObjectGet(reply, "return"); + if (!caps || caps->type != VIR_JSON_TYPE_OBJECT) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing dump guest memory capabilities")); + goto cleanup; + } + + formats = virJSONValueObjectGet(caps, "formats"); + if (!formats || formats->type != VIR_JSON_TYPE_ARRAY) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing supported dump formats")); + goto cleanup; + } + + for (i = 0; i < virJSONValueArraySize(formats); i++) { + virJSONValuePtr dumpformat = virJSONValueArrayGet(formats, i); + + if (!dumpformat || dumpformat->type != VIR_JSON_TYPE_STRING) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing entry in supported dump formats")); + goto cleanup; + } + + if (STREQ(virJSONValueGetString(dumpformat), capability)) { + ret = 1; + goto cleanup; + } + + ret = 0; + } + +cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + +int qemuMonitorJSONDump(qemuMonitorPtr mon, const char *protocol) { diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index ef71588..631b9e4 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -147,6 +147,9 @@ int qemuMonitorJSONGetSpiceMigrationStatus(qemuMonitorPtr mon, int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon); +int qemuMonitorJSONGetDumpGuestMemoryCapability(qemuMonitorPtr mon, + const char *capability); + int qemuMonitorJSONDump(qemuMonitorPtr mon, const char *protocol); diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index d7da5a8..d21e1ce 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -1959,6 +1959,48 @@ cleanup: return ret; } +static int +testQemuMonitorJSONqemuMonitorJSONGetDumpGuestMemoryCapability(const void *data) +{ + virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; + qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt); + int ret = -1; + int cap; + const char *reply = + "{" + " \"return\": {" + " \"formats\": [" + " \"elf\"," + " \"kdump-zlib\"," + " \"kdump-lzo\"," + " \"kdump-snappy\"" + " ]" + " }," + " \"id\": \"libvirt-9\"" + "}"; + + if (!test) + return -1; + + if (qemuMonitorTestAddItem(test, "query-dump-guest-memory-capability", + reply) < 0) + goto cleanup; + + cap = qemuMonitorJSONGetDumpGuestMemoryCapability( + qemuMonitorTestGetMonitor(test), "elf"); + + if (cap != 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Unexpected capability: %d, expecting 1", + cap); + goto cleanup; + } + + ret = 0; +cleanup: + qemuMonitorTestFree(test); + return ret; +} struct testCPUData { const char *name; @@ -2187,6 +2229,7 @@ mymain(void) DO_TEST(qemuMonitorJSONGetCPUInfo); DO_TEST(qemuMonitorJSONGetVirtType); DO_TEST(qemuMonitorJSONSendKey); + DO_TEST(qemuMonitorJSONGetDumpGuestMemoryCapability); DO_TEST_CPU_DATA("host"); DO_TEST_CPU_DATA("full"); -- 1.8.5.3

From: Qiao Nuohan <qiaonuohan@cn.fujitsu.com> This patch makes qemu driver support virDomainCoreDumpWithFormat API. Signed-off-by: Qiao Nuohan <qiaonuohan@cn.fujitsu.com> --- src/qemu/qemu_driver.c | 75 +++++++++++++++++++++++++++++++++++++------- src/qemu/qemu_monitor.c | 6 ++-- src/qemu/qemu_monitor.h | 3 +- src/qemu/qemu_monitor_json.c | 20 +++++++++--- src/qemu/qemu_monitor_json.h | 3 +- tests/qemumonitorjsontest.c | 2 +- 6 files changed, 87 insertions(+), 22 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a9d7615..9c6dd49 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2659,6 +2659,13 @@ VIR_ENUM_IMPL(qemuSaveCompression, QEMU_SAVE_FORMAT_LAST, "xz", "lzop") +VIR_ENUM_DECL(qemuDumpFormat) +VIR_ENUM_IMPL(qemuDumpFormat, VIR_DOMAIN_CORE_DUMP_FORMAT_LAST, + "elf", + "kdump-zlib", + "kdump-lzo", + "kdump-snappy") + typedef struct _virQEMUSaveHeader virQEMUSaveHeader; typedef virQEMUSaveHeader *virQEMUSaveHeaderPtr; struct _virQEMUSaveHeader { @@ -3373,7 +3380,8 @@ cleanup: } static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm, - int fd, enum qemuDomainAsyncJob asyncJob) + int fd, enum qemuDomainAsyncJob asyncJob, + const char *dumpformat) { qemuDomainObjPrivatePtr priv = vm->privateData; int ret = -1; @@ -3393,7 +3401,20 @@ static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm, if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) return -1; - ret = qemuMonitorDumpToFd(priv->mon, fd); + if (dumpformat) { + ret = qemuMonitorGetDumpGuestMemoryCapability(priv->mon, dumpformat); + + if (ret <= 0) { + virReportError(VIR_ERR_INVALID_ARG, + _("unsupported dumpformat '%s'"), dumpformat); + ret = -1; + goto cleanup; + } + } + + ret = qemuMonitorDumpToFd(priv->mon, fd, dumpformat); + +cleanup: qemuDomainObjExitMonitor(driver, vm); return ret; @@ -3404,13 +3425,15 @@ doCoreDump(virQEMUDriverPtr driver, virDomainObjPtr vm, const char *path, virQEMUSaveFormat compress, - unsigned int dump_flags) + unsigned int dump_flags, + unsigned int dumpformat) { int fd = -1; int ret = -1; virFileWrapperFdPtr wrapperFd = NULL; int directFlag = 0; unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING; + const char *memory_dump_format = NULL; /* Create an empty file with appropriate ownership. */ if (dump_flags & VIR_DUMP_BYPASS_CACHE) { @@ -3434,8 +3457,25 @@ doCoreDump(virQEMUDriverPtr driver, goto cleanup; if (dump_flags & VIR_DUMP_MEMORY_ONLY) { - ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP); + if (!(memory_dump_format = qemuDumpFormatTypeToString(dumpformat))) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown dumpformat '%d'"), dumpformat); + goto cleanup; + } + + /* qemu dumps in "elf" without dumpformat set */ + if (STREQ(memory_dump_format, "elf")) + memory_dump_format = NULL; + + ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP, + memory_dump_format); } else { + if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("kdump-compressed format is only supported with " + "memory-only dump")); + goto cleanup; + } ret = qemuMigrationToFile(driver, vm, fd, 0, path, qemuCompressProgramName(compress), false, QEMU_ASYNC_JOB_DUMP); @@ -3497,9 +3537,10 @@ cleanup: return ret; } -static int qemuDomainCoreDump(virDomainPtr dom, - const char *path, - unsigned int flags) +static int qemuDomainCoreDumpWithFormat(virDomainPtr dom, + const char *path, + unsigned int dumpformat, + unsigned int flags) { virQEMUDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; @@ -3515,7 +3556,7 @@ static int qemuDomainCoreDump(virDomainPtr dom, if (!(vm = qemuDomObjFromDomain(dom))) return -1; - if (virDomainCoreDumpEnsureACL(dom->conn, vm->def) < 0) + if (virDomainCoreDumpWithFormatEnsureACL(dom->conn, vm->def) < 0) goto cleanup; if (qemuDomainObjBeginAsyncJob(driver, vm, @@ -3547,7 +3588,8 @@ static int qemuDomainCoreDump(virDomainPtr dom, } } - ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags); + ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags, + dumpformat); if (ret < 0) goto endjob; @@ -3601,6 +3643,14 @@ cleanup: return ret; } +static int qemuDomainCoreDump(virDomainPtr dom, + const char *path, + unsigned int flags) +{ + return qemuDomainCoreDumpWithFormat(dom, path, + VIR_DOMAIN_CORE_DUMP_FORMAT_RAW, flags); +} + static char * qemuDomainScreenshot(virDomainPtr dom, virStreamPtr st, @@ -3724,7 +3774,8 @@ static void processWatchdogEvent(virQEMUDriverPtr driver, virDomainObjPtr vm, in flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0; ret = doCoreDump(driver, vm, dumpfile, - getCompressionType(driver), flags); + getCompressionType(driver), flags, + VIR_DOMAIN_CORE_DUMP_FORMAT_RAW); if (ret < 0) virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Dump failed")); @@ -3788,7 +3839,8 @@ doCoreDumpToAutoDumpPath(virQEMUDriverPtr driver, flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0; ret = doCoreDump(driver, vm, dumpfile, - getCompressionType(driver), flags); + getCompressionType(driver), flags, + VIR_DOMAIN_CORE_DUMP_FORMAT_RAW); if (ret < 0) virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Dump failed")); @@ -16648,6 +16700,7 @@ static virDriver qemuDriver = { .domainSaveImageGetXMLDesc = qemuDomainSaveImageGetXMLDesc, /* 0.9.4 */ .domainSaveImageDefineXML = qemuDomainSaveImageDefineXML, /* 0.9.4 */ .domainCoreDump = qemuDomainCoreDump, /* 0.7.0 */ + .domainCoreDumpWithFormat = qemuDomainCoreDumpWithFormat, /* 1.2.3 */ .domainScreenshot = qemuDomainScreenshot, /* 0.9.2 */ .domainSetVcpus = qemuDomainSetVcpus, /* 0.4.4 */ .domainSetVcpusFlags = qemuDomainSetVcpusFlags, /* 0.8.5 */ diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 976a954..5a3210b 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2390,10 +2390,10 @@ int qemuMonitorGetDumpGuestMemoryCapability(qemuMonitorPtr mon, } int -qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd) +qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd, const char *dumpformat) { int ret; - VIR_DEBUG("mon=%p fd=%d", mon, fd); + VIR_DEBUG("mon=%p fd=%d dumpformat=%s", mon, fd, dumpformat); if (!mon) { virReportError(VIR_ERR_INVALID_ARG, "%s", @@ -2413,7 +2413,7 @@ qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd) if (qemuMonitorSendFileHandle(mon, "dump", fd) < 0) return -1; - ret = qemuMonitorJSONDump(mon, "fd:dump"); + ret = qemuMonitorJSONDump(mon, "fd:dump", dumpformat); if (ret < 0) { if (qemuMonitorCloseFileHandle(mon, "dump") < 0) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index e896911..de724bf 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -510,7 +510,8 @@ int qemuMonitorGetDumpGuestMemoryCapability(qemuMonitorPtr mon, const char *capability); int qemuMonitorDumpToFd(qemuMonitorPtr mon, - int fd); + int fd, + const char *dumpformat); int qemuMonitorGraphicsRelocate(qemuMonitorPtr mon, int type, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index ab5890b..e167df4 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2724,16 +2724,26 @@ cleanup: int qemuMonitorJSONDump(qemuMonitorPtr mon, - const char *protocol) + const char *protocol, + const char *dumpformat) { int ret; virJSONValuePtr cmd = NULL; virJSONValuePtr reply = NULL; - cmd = qemuMonitorJSONMakeCommand("dump-guest-memory", - "b:paging", false, - "s:protocol", protocol, - 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); + } + if (!cmd) return -1; diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 631b9e4..5dda0ba 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -151,7 +151,8 @@ int qemuMonitorJSONGetDumpGuestMemoryCapability(qemuMonitorPtr mon, const char *capability); int qemuMonitorJSONDump(qemuMonitorPtr mon, - const char *protocol); + const char *protocol, + const char *dumpformat); int qemuMonitorJSONGraphicsRelocate(qemuMonitorPtr mon, int type, diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index d21e1ce..6b48296 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -1154,7 +1154,7 @@ 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") +GEN_TEST_FUNC(qemuMonitorJSONDump, "dummy_protocol", "dummy_memory_dump_format") GEN_TEST_FUNC(qemuMonitorJSONGraphicsRelocate, VIR_DOMAIN_GRAPHICS_TYPE_SPICE, "localhost", 12345, 12346, NULL) GEN_TEST_FUNC(qemuMonitorJSONAddNetdev, "some_dummy_netdevstr") -- 1.8.5.3

From: Qiao Nuohan <qiaonuohan@cn.fujitsu.com> This patch adds "[--format] <string>" to "virsh dump --memory-only", which is changed to use the new virDomainCoreDumpWithFormat API. And "--compress" is added as an alias for "--format kdump-zlib". Signed-off-by: Qiao Nuohan <qiaonuohan@cn.fujitsu.com> --- tools/virsh-domain.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- tools/virsh.pod | 6 ++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 0664774..d897c72 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -4490,6 +4490,14 @@ static const vshCmdOptDef opts_dump[] = { .type = VSH_OT_BOOL, .help = N_("dump domain's memory only") }, + {.name = "compress", + .type = VSH_OT_ALIAS, + .help = "format=kdump-zlib", + }, + {.name = "format", + .type = VSH_OT_DATA, + .help = N_("specify the format of memory-only dump") + }, {.name = NULL} }; @@ -4505,6 +4513,8 @@ doDump(void *opaque) const char *name = NULL; const char *to = NULL; unsigned int flags = 0; + const char *format = NULL; + unsigned int dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_RAW; sigemptyset(&sigmask); sigaddset(&sigmask, SIGINT); @@ -4528,9 +4538,40 @@ doDump(void *opaque) if (vshCommandOptBool(cmd, "memory-only")) flags |= VIR_DUMP_MEMORY_ONLY; - if (virDomainCoreDump(dom, to, flags) < 0) { - vshError(ctl, _("Failed to core dump domain %s to %s"), name, to); - goto out; + if (vshCommandOptBool(cmd, "format")) { + if (!(flags & VIR_DUMP_MEMORY_ONLY)) { + vshError(ctl, "%s", _("--format only work with --memory-only")); + goto out; + } + + if (vshCommandOptString(cmd, "format", &format)) { + if (STREQ(format, "kdump-zlib")) + dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_ZLIB; + else if (STREQ(format, "kdump-lzo")) + dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_LZO; + else if (STREQ(format, "kdump-snappy")) + dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_SNAPPY; + else if (STREQ(format, "elf")) + dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_RAW; + else { + vshError(ctl, _("format '%s' is not supported, expecting " + "'kdump-zlib', 'kdump-lzo', 'kdump-snappy' " + "or 'elf'."), format); + goto out; + } + } + } + + if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) { + if (virDomainCoreDumpWithFormat(dom, to, dumpformat, flags) < 0) { + vshError(ctl, _("Failed to core dump domain %s to %s"), name, to); + goto out; + } + } else { + if (virDomainCoreDump(dom, to, flags) < 0) { + vshError(ctl, _("Failed to core dump domain %s to %s"), name, to); + goto out; + } } ret = '0'; diff --git a/tools/virsh.pod b/tools/virsh.pod index 4645be5..7e3ae5a 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1010,6 +1010,7 @@ I<format> argument may be B<xen-xm> or B<xen-sxpr>. =item B<dump> I<domain> I<corefilepath> [I<--bypass-cache>] { [I<--live>] | [I<--crash>] | [I<--reset>] } [I<--verbose>] [I<--memory-only>] +[I<--format> I<string>] Dumps the core of a domain to a file for analysis. If I<--live> is specified, the domain continues to run until the core @@ -1023,6 +1024,11 @@ cache, although this may slow down the operation. If I<--memory-only> is specified, the file is elf file, and will only include domain's memory and cpu common register value. It is very useful if the domain uses host devices directly. +I<--format> I<string> is used to specify the format of 'memory-only' +dump, and I<string> can be one of them: elf, kdump-zlib(kdump-compressed +format with zlib-compressed), kdump-lzo(kdump-compressed format with +lzo-compressed), kdump-snappy(kdump-compressed format with snappy-compressed) +I<--compress> is an alias for I<--format> I<kdump-zlib>. The progress may be monitored using B<domjobinfo> virsh command and canceled with B<domjobabort> command (sent by another virsh instance). Another option -- 1.8.5.3

On 03/22/2014 09:51 PM, Wen Congyang wrote:
From: Qiao Nuohan <qiaonuohan@cn.fujitsu.com>
This patch adds "[--format] <string>" to "virsh dump --memory-only", which is changed to use the new virDomainCoreDumpWithFormat API. And "--compress" is added as an alias for "--format kdump-zlib".
Signed-off-by: Qiao Nuohan <qiaonuohan@cn.fujitsu.com> --- tools/virsh-domain.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- tools/virsh.pod | 6 ++++++ 2 files changed, 50 insertions(+), 3 deletions(-)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 0664774..d897c72 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -4490,6 +4490,14 @@ static const vshCmdOptDef opts_dump[] = { .type = VSH_OT_BOOL, .help = N_("dump domain's memory only") }, + {.name = "compress", + .type = VSH_OT_ALIAS, + .help = "format=kdump-zlib", + },
Remember that the alias mechanism intentionally results in undocumented support. Observe: $ tools/virsh dump --help | grep compress $ tools/virsh dump --help | grep format dump [--live] [--crash] [--bypass-cache] [--reset] <domain> <file> [--verbose] [--memory-only] [<format>] [--format] <string> specify the format of memory-only dump $ To date, we have only used aliases to fix warts in old interfaces while avoiding back-compat breaks. But you are attempting to use the alias as a brand new interface. I'd much rather NOT push the alias. Undocumented interfaces are evil, and should only exist when back-compat is at stake. But here, we've never had --compress in the past, so back-compat is not an issue. If you absolutely must have --compress (and can't stand to type --format=kdump-zlib in your scripts), it would be better to do that as a followup patch with a lot more justification and while ensuring it is a documented interface. Or even better would be adding support for generic user aliases (where I could create an alias 'd' for 'dump --format=kdump-zlib', then use 'virsh d $dom').
- if (virDomainCoreDump(dom, to, flags) < 0) { - vshError(ctl, _("Failed to core dump domain %s to %s"), name, to); - goto out; + if (vshCommandOptBool(cmd, "format")) { + if (!(flags & VIR_DUMP_MEMORY_ONLY)) { + vshError(ctl, "%s", _("--format only work with --memory-only")); + goto out;
Grammar is off.
+ + if (vshCommandOptString(cmd, "format", &format)) { + if (STREQ(format, "kdump-zlib")) + dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_ZLIB; + else if (STREQ(format, "kdump-lzo")) + dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_LZO; + else if (STREQ(format, "kdump-snappy")) + dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_SNAPPY; + else if (STREQ(format, "elf")) + dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_RAW; + else {
HACKING says that if the 'else' side has {}, the 'if' side must as well.
+ vshError(ctl, _("format '%s' is not supported, expecting " + "'kdump-zlib', 'kdump-lzo', 'kdump-snappy' " + "or 'elf'."), format);
We tend to avoid trailing . in messages I've pushed your series, with this squashed in: diff --git i/tools/virsh-domain.c w/tools/virsh-domain.c index d897c72..f2856a5 100644 --- i/tools/virsh-domain.c +++ w/tools/virsh-domain.c @@ -4490,10 +4490,6 @@ static const vshCmdOptDef opts_dump[] = { .type = VSH_OT_BOOL, .help = N_("dump domain's memory only") }, - {.name = "compress", - .type = VSH_OT_ALIAS, - .help = "format=kdump-zlib", - }, {.name = "format", .type = VSH_OT_DATA, .help = N_("specify the format of memory-only dump") @@ -4540,23 +4536,23 @@ doDump(void *opaque) if (vshCommandOptBool(cmd, "format")) { if (!(flags & VIR_DUMP_MEMORY_ONLY)) { - vshError(ctl, "%s", _("--format only work with --memory-only")); + vshError(ctl, "%s", _("--format only works with --memory-only")); goto out; } if (vshCommandOptString(cmd, "format", &format)) { - if (STREQ(format, "kdump-zlib")) + if (STREQ(format, "kdump-zlib")) { dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_ZLIB; - else if (STREQ(format, "kdump-lzo")) + } else if (STREQ(format, "kdump-lzo")) { dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_LZO; - else if (STREQ(format, "kdump-snappy")) + } else if (STREQ(format, "kdump-snappy")) { dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_SNAPPY; - else if (STREQ(format, "elf")) + } else if (STREQ(format, "elf")) { dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_RAW; - else { + } else { vshError(ctl, _("format '%s' is not supported, expecting " "'kdump-zlib', 'kdump-lzo', 'kdump-snappy' " - "or 'elf'."), format); + "or 'elf'"), format); goto out; } } diff --git i/tools/virsh.pod w/tools/virsh.pod index 7e3ae5a..20352cb 100644 --- i/tools/virsh.pod +++ w/tools/virsh.pod @@ -1027,8 +1027,7 @@ useful if the domain uses host devices directly. I<--format> I<string> is used to specify the format of 'memory-only' dump, and I<string> can be one of them: elf, kdump-zlib(kdump-compressed format with zlib-compressed), kdump-lzo(kdump-compressed format with -lzo-compressed), kdump-snappy(kdump-compressed format with snappy-compressed) -I<--compress> is an alias for I<--format> I<kdump-zlib>. +lzo-compressed), kdump-snappy(kdump-compressed format with snappy-compressed). The progress may be monitored using B<domjobinfo> virsh command and canceled with B<domjobabort> command (sent by another virsh instance). Another option -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (2)
-
Eric Blake
-
Wen Congyang