From 9fbaff008c79c6ae0c745ed624137dab23637c45 Mon Sep 17 00:00:00 2001 From: Qiao Nuohan Date: Sun, 23 Mar 2014 11:51:12 +0800 Subject: [PATCH] add new virDomainCoreDumpWithFormat API --memory-only option is introduced without compression supported. Now qemu has support for dumping domain's memory in kdump-compressed format. This patch adds a new virDomainCoreDumpWithFormat API, so that the format in which qemu dumps domain's memory can be specified. Signed-off-by: Qiao Nuohan Signed-off-by: Eric Blake --- include/libvirt/libvirt.h.in | 31 +++++++++++ src/driver.h | 7 +++ src/libvirt.c | 101 +++++++++++++++++++++++++++++++++++ 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 | 34 ++++++++++-- 8 files changed, 195 insertions(+), 6 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 82c602b6d1..91e3e3b9a6 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 */ @@ -1731,6 +1754,14 @@ int virDomainCoreDump (virDomainPtr domain, const char *to, 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 */ diff --git a/src/driver.h b/src/driver.h index d728705623..e66fc7ae5f 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 c5c3136d0b..d42da389e5 100644 --- a/src/libvirt.c +++ b/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 @@ -2999,6 +3001,105 @@ 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. + * + * @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 + * 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 6ed6ce61db..9ab0c92172 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 f6d52e2065..72545dfb45 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 f1f23594f5..6c445cc431 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 5636d55b8b..456d0dae06 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 d88d3fcd7b..5694680cdf 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,14 +2499,29 @@ cleanup: return ret; } -static char *testDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) { + +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; ignore_value(VIR_STRDUP(ret, "linux")); return ret; } -static unsigned long long testDomainGetMaxMemory(virDomainPtr domain) + +static unsigned long long +testDomainGetMaxMemory(virDomainPtr domain) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; @@ -7383,6 +7406,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 */