--memory-only option is introduced without compression supported. Therefore,
this is a freature regression of virsh dump. Now qemu has support dumping memory
in kdump-compressed format. This patch is adding new virDomainMemoryDump API,
so that the format in which qemu dump domain's memory can be specified.
Signed-off-by: Qiao Nuohan <qiaonuohan(a)cn.fujitsu.com>_
---
include/libvirt/libvirt.h.in | 21 ++++++++++
src/access/viraccessperm.c | 2 +-
src/access/viraccessperm.h | 6 +++
src/driver.h | 7 ++++
src/libvirt.c | 95 ++++++++++++++++++++++++++++++++++++++++++++
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 | 17 +++++++-
10 files changed, 172 insertions(+), 4 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 295d551..ab6efca 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1180,6 +1180,19 @@ typedef enum {
VIR_DUMP_MEMORY_ONLY = (1 << 4), /* use dump-guest-memory */
} virDomainCoreDumpFlags;
+/* Domain memory dump's format */
+typedef enum {
+ VIR_MEMORY_DUMP_COMPRESS_ZLIB = 1, /* dump guest memory in
+ kdump-compressed format, with
+ zlib-compressed */
+ VIR_MEMORY_DUMP_COMPRESS_LZO = 2, /* dump guest memory in
+ kdump-compressed format, with
+ lzo-compressed */
+ VIR_MEMORY_DUMP_COMPRESS_SNAPPY = 3, /* dump guest memory in
+ kdump-compressed format, with
+ snappy-compressed */
+} virMemoryDumpFormat;
+
/* Domain migration flags. */
typedef enum {
VIR_MIGRATE_LIVE = (1 << 0), /* live migration */
@@ -1731,6 +1744,14 @@ int virDomainCoreDump (virDomainPtr
domain,
unsigned int flags);
/*
+ * Domain core dump
+ */
+int virDomainMemoryDump (virDomainPtr domain,
+ const char *to,
+ unsigned int flags,
+ unsigned int dumpformat);
+
+/*
* Screenshot of current domain console
*/
char * virDomainScreenshot (virDomainPtr domain,
diff --git a/src/access/viraccessperm.c b/src/access/viraccessperm.c
index d517c66..af4f05e 100644
--- a/src/access/viraccessperm.c
+++ b/src/access/viraccessperm.c
@@ -42,7 +42,7 @@ VIR_ENUM_IMPL(virAccessPermDomain,
"init_control", "inject_nmi", "send_input",
"send_signal", "fs_trim",
"block_read", "block_write", "mem_read",
"open_graphics", "open_device",
"screenshot",
- "open_namespace");
+ "open_namespace", "memory_dump");
VIR_ENUM_IMPL(virAccessPermInterface,
VIR_ACCESS_PERM_INTERFACE_LAST,
diff --git a/src/access/viraccessperm.h b/src/access/viraccessperm.h
index 6d14f05..2537fbf 100644
--- a/src/access/viraccessperm.h
+++ b/src/access/viraccessperm.h
@@ -205,6 +205,12 @@ typedef enum {
VIR_ACCESS_PERM_DOMAIN_CORE_DUMP, /* Dump guest core */
/**
+ * @desc: Dump domain's memory only
+ * @message: Dumping domain's memory requires authorization
+ */
+ VIR_ACCESS_PERM_DOMAIN_MEMORY_DUMP, /* Dump guest's memory only */
+
+ /**
* @desc: Use domain power management
* @message: Using domain power management requires authoriation
*/
diff --git a/src/driver.h b/src/driver.h
index fbfaac4..7c001e6 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -306,6 +306,12 @@ typedef int
const char *to,
unsigned int flags);
+typedef int
+(*virDrvDomainMemoryDump)(virDomainPtr domain,
+ const char *to,
+ unsigned int flags,
+ unsigned int dumpformat);
+
typedef char *
(*virDrvDomainScreenshot)(virDomainPtr domain,
virStreamPtr stream,
@@ -1200,6 +1206,7 @@ struct _virDriver {
virDrvDomainSaveImageGetXMLDesc domainSaveImageGetXMLDesc;
virDrvDomainSaveImageDefineXML domainSaveImageDefineXML;
virDrvDomainCoreDump domainCoreDump;
+ virDrvDomainMemoryDump domainMemoryDump;
virDrvDomainScreenshot domainScreenshot;
virDrvDomainSetVcpus domainSetVcpus;
virDrvDomainSetVcpusFlags domainSetVcpusFlags;
diff --git a/src/libvirt.c b/src/libvirt.c
index dcf6b53..ec106a6 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -2999,6 +2999,101 @@ error:
return -1;
}
+/**
+ * virDomainMemoryDump:
+ * @domain: a domain object
+ * @to: path for the core file
+ * @flags: bitwise-OR of virDomainCoreDumpFlags
+ * @dumpformat: format of domain memory's dump
+ *
+ * This method will only dump the memory of a domain on a given file for
+ * analysis, so @flag must includes VIR_DUMP_MEMORY_ONLY.
+ *
+ * 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.
+ *
+ * when @flags includes VIR_DUMP_MEMORY_ONLY and dumpformat is set, libvirt
+ * will ask qemu dump domain's memory in kdump-compressed format.
+ *
+ * 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
+virDomainMemoryDump(virDomainPtr domain, const char *to, unsigned int flags,
+ unsigned int dumpformat)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(domain, "to=%s, flags=%x", to, flags);
+
+ virResetLastError();
+
+ virCheckDomainReturn(domain, -1);
+ conn = domain->conn;
+
+ virCheckReadOnlyGoto(conn->flags, error);
+ virCheckNonNullArgGoto(to, error);
+
+ if (!(flags & VIR_DUMP_MEMORY_ONLY)) {
+ virReportInvalidArg(flags, "%s",
+ _("memory-only flag is needed to dump domain's
memory only"));
+ 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->domainMemoryDump) {
+ 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->domainMemoryDump(domain, absolute_to, flags,
+ dumpformat);
+
+ 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..7135242 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:
+ virDomainMemoryDump;
+} 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 955465a..c5772ed 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -7516,6 +7516,7 @@ static virDriver remote_driver = {
.domainSaveImageGetXMLDesc = remoteDomainSaveImageGetXMLDesc, /* 0.9.4 */
.domainSaveImageDefineXML = remoteDomainSaveImageDefineXML, /* 0.9.4 */
.domainCoreDump = remoteDomainCoreDump, /* 0.3.0 */
+ .domainMemoryDump = remoteDomainMemoryDump, /* 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..680456f 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_memory_dump_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string to;
+ unsigned int flags;
+ unsigned int dumpformat;
+};
+
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:memory_dump
+ */
+ REMOTE_PROC_DOMAIN_MEMORY_DUMP = 334
};
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 5636d55..01a9dbe 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_memory_dump_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string to;
+ u_int flags;
+ u_int dumpformat;
+};
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_MEMORY_DUMP = 334,
};
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index b724f82..cf93f97 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -2427,9 +2427,10 @@ testDomainRestore(virConnectPtr conn,
return testDomainRestoreFlags(conn, path, NULL, 0);
}
-static int testDomainCoreDump(virDomainPtr domain,
+static int testDomainMemoryDump(virDomainPtr domain,
const char *to,
- unsigned int flags)
+ unsigned int flags,
+ unsigned int dumpformat)
{
testConnPtr privconn = domain->conn->privateData;
int fd = -1;
@@ -2479,6 +2480,12 @@ static int testDomainCoreDump(virDomainPtr domain,
}
}
+ if (dumpformat > VIR_MEMORY_DUMP_COMPRESS_SNAPPY) {
+ virReportSystemError(errno,
+ _("invalid value of dumpformat: %d"),
dumpformat);
+ goto cleanup;
+ }
+
ret = 0;
cleanup:
VIR_FORCE_CLOSE(fd);
@@ -2490,6 +2497,12 @@ cleanup:
return ret;
}
+static int testDomainCoreDump(virDomainPtr domain,
+ const char *to,
+ unsigned int flags) {
+ return testDomainMemoryDump(domain, to, flags, 0);
+}
+
static char *testDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) {
char *ret;
--
1.8.5.3