--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 used to add "--compress" and
"[--compression-format] <string>" to "virsh dump --memory-only"
and send
dump-guest-memory command to qemu with dump format specified to one of elf,
kdump-zlib, kdump-lzo and kdump-snappy.
Signed-off-by: Qiao Nuohan <qiaonuohan(a)cn.fujitsu.com>
---
include/libvirt/libvirt.h.in | 15 ++++++++++++++-
src/driver.h | 3 ++-
src/libvirt.c | 10 ++++++++--
src/qemu/qemu_driver.c | 30 +++++++++++++++++++++--------
src/qemu/qemu_monitor.c | 6 +++---
src/qemu/qemu_monitor.h | 3 ++-
src/qemu/qemu_monitor_json.c | 4 +++-
src/qemu/qemu_monitor_json.h | 3 ++-
src/remote/remote_protocol.x | 1 +
src/test/test_driver.c | 12 +++++++++++-
tests/qemumonitorjsontest.c | 2 +-
tools/virsh-domain.c | 45 +++++++++++++++++++++++++++++++++++++++++++-
12 files changed, 113 insertions(+), 21 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 295d551..aae3c49 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1180,6 +1180,18 @@ typedef enum {
VIR_DUMP_MEMORY_ONLY = (1 << 4), /* use dump-guest-memory */
} virDomainCoreDumpFlags;
+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 */
@@ -1728,7 +1740,8 @@ int
virDomainManagedSaveRemove(virDomainPtr dom,
*/
int virDomainCoreDump (virDomainPtr domain,
const char *to,
- unsigned int flags);
+ unsigned int flags,
+ const unsigned int
memory_dump_format);
/*
* Screenshot of current domain console
diff --git a/src/driver.h b/src/driver.h
index 5f4cd8d..c228fd0 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -303,7 +303,8 @@ typedef int
typedef int
(*virDrvDomainCoreDump)(virDomainPtr domain,
const char *to,
- unsigned int flags);
+ unsigned int flags,
+ const unsigned int memory_dump_format);
typedef char *
(*virDrvDomainScreenshot)(virDomainPtr domain,
diff --git a/src/libvirt.c b/src/libvirt.c
index 9cc5b1c..0659baf 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -2916,6 +2916,7 @@ error:
* @domain: a domain object
* @to: path for the core file
* @flags: bitwise-OR of virDomainCoreDumpFlags
+ * @memory_dump_format: format of guest memory's dump
*
* 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
@@ -2934,10 +2935,14 @@ 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.
*
+ * when @flags includes VIR_DUMP_MEMORY_ONLY and memory_dump_format is set,
+ * libvirt will ask qemu dump guest's memory in kdump-compressed format.
+ *
* Returns 0 in case of success and -1 in case of failure.
*/
int
-virDomainCoreDump(virDomainPtr domain, const char *to, unsigned int flags)
+virDomainCoreDump(virDomainPtr domain, const char *to, unsigned int flags,
+ const unsigned int memory_dump_format)
{
virConnectPtr conn;
@@ -2980,7 +2985,8 @@ virDomainCoreDump(virDomainPtr domain, const char *to,
unsigned int flags)
goto error;
}
- ret = conn->driver->domainCoreDump(domain, absolute_to, flags);
+ ret = conn->driver->domainCoreDump(domain, absolute_to, flags,
+ memory_dump_format);
VIR_FREE(absolute_to);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 59e018d..7b6fa43 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3383,7 +3383,8 @@ cleanup:
}
static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm,
- int fd, enum qemuDomainAsyncJob asyncJob)
+ int fd, enum qemuDomainAsyncJob asyncJob,
+ const char* dump_format)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
int ret = -1;
@@ -3403,7 +3404,7 @@ static int qemuDumpToFd(virQEMUDriverPtr driver,
virDomainObjPtr vm,
if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
return -1;
- ret = qemuMonitorDumpToFd(priv->mon, fd);
+ ret = qemuMonitorDumpToFd(priv->mon, fd, dump_format);
qemuDomainObjExitMonitor(driver, vm);
return ret;
@@ -3414,13 +3415,15 @@ doCoreDump(virQEMUDriverPtr driver,
virDomainObjPtr vm,
const char *path,
virQEMUSaveFormat compress,
- unsigned int dump_flags)
+ unsigned int dump_flags,
+ const unsigned int memory_dump_format)
{
int fd = -1;
int ret = -1;
virFileWrapperFdPtr wrapperFd = NULL;
int directFlag = 0;
unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
+ const char *dump_format;
/* Create an empty file with appropriate ownership. */
if (dump_flags & VIR_DUMP_BYPASS_CACHE) {
@@ -3444,7 +3447,16 @@ 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 == VIR_MEMORY_DUMP_COMPRESS_ZLIB)
+ dump_format = "kdump-zlib";
+ else if (memory_dump_format == VIR_MEMORY_DUMP_COMPRESS_LZO)
+ dump_format = "kdump-lzo";
+ else if (memory_dump_format == VIR_MEMORY_DUMP_COMPRESS_SNAPPY)
+ dump_format = "kdump-snappy";
+ else
+ dump_format = "elf";
+ ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP,
+ dump_format);
} else {
ret = qemuMigrationToFile(driver, vm, fd, 0, path,
qemuCompressProgramName(compress), false,
@@ -3509,7 +3521,8 @@ cleanup:
static int qemuDomainCoreDump(virDomainPtr dom,
const char *path,
- unsigned int flags)
+ unsigned int flags,
+ const unsigned int memory_dump_format)
{
virQEMUDriverPtr driver = dom->conn->privateData;
virDomainObjPtr vm;
@@ -3557,7 +3570,8 @@ static int qemuDomainCoreDump(virDomainPtr dom,
}
}
- ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags);
+ ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags,
+ memory_dump_format);
if (ret < 0)
goto endjob;
@@ -3734,7 +3748,7 @@ 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, 0);
if (ret < 0)
virReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("Dump failed"));
@@ -3798,7 +3812,7 @@ doCoreDumpToAutoDumpPath(virQEMUDriverPtr driver,
flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
ret = doCoreDump(driver, vm, dumpfile,
- getCompressionType(driver), flags);
+ getCompressionType(driver), flags, 0);
if (ret < 0)
virReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("Dump failed"));
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index a2769db..2722781 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2345,10 +2345,10 @@ int qemuMonitorMigrateCancel(qemuMonitorPtr mon)
}
int
-qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd)
+qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd, const char *dump_format)
{
int ret;
- VIR_DEBUG("mon=%p fd=%d", mon, fd);
+ VIR_DEBUG("mon=%p fd=%d dump_format=%s", mon, fd, dump_format);
if (!mon) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
@@ -2368,7 +2368,7 @@ qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd)
if (qemuMonitorSendFileHandle(mon, "dump", fd) < 0)
return -1;
- ret = qemuMonitorJSONDump(mon, "fd:dump");
+ ret = qemuMonitorJSONDump(mon, "fd:dump", dump_format);
if (ret < 0) {
if (qemuMonitorCloseFileHandle(mon, "dump") < 0)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index eabf000..f2e5763 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -495,7 +495,8 @@ int qemuMonitorMigrateToUnix(qemuMonitorPtr mon,
int qemuMonitorMigrateCancel(qemuMonitorPtr mon);
int qemuMonitorDumpToFd(qemuMonitorPtr mon,
- int fd);
+ int fd,
+ const char *dump_format);
int qemuMonitorGraphicsRelocate(qemuMonitorPtr mon,
int type,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 5e825ac..7c9625f 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2636,7 +2636,8 @@ int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon)
int
qemuMonitorJSONDump(qemuMonitorPtr mon,
- const char *protocol)
+ const char *protocol,
+ const char *dump_format)
{
int ret;
virJSONValuePtr cmd = NULL;
@@ -2645,6 +2646,7 @@ qemuMonitorJSONDump(qemuMonitorPtr mon,
cmd = qemuMonitorJSONMakeCommand("dump-guest-memory",
"b:paging", false,
"s:protocol", protocol,
+ "s:format", dump_format,
NULL);
if (!cmd)
return -1;
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index a93c51e..7691356 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -148,7 +148,8 @@ int qemuMonitorJSONGetSpiceMigrationStatus(qemuMonitorPtr mon,
int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon);
int qemuMonitorJSONDump(qemuMonitorPtr mon,
- const char *protocol);
+ const char *protocol,
+ const char *dump_format);
int qemuMonitorJSONGraphicsRelocate(qemuMonitorPtr mon,
int type,
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index f1f2359..cc6f68b 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -902,6 +902,7 @@ struct remote_domain_core_dump_args {
remote_nonnull_domain dom;
remote_nonnull_string to;
unsigned int flags;
+ unsigned int memory_dump_format;
};
struct remote_domain_screenshot_args {
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index b724f82..559933f 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -2429,7 +2429,8 @@ testDomainRestore(virConnectPtr conn,
static int testDomainCoreDump(virDomainPtr domain,
const char *to,
- unsigned int flags)
+ unsigned int flags,
+ const unsigned int memory_dump_format)
{
testConnPtr privconn = domain->conn->privateData;
int fd = -1;
@@ -2479,6 +2480,15 @@ static int testDomainCoreDump(virDomainPtr domain,
}
}
+ if (!(flags & VIR_DUMP_MEMORY_ONLY) && (memory_dump_format ==
+ VIR_MEMORY_DUMP_COMPRESS_ZLIB || memory_dump_format ==
+ VIR_MEMORY_DUMP_COMPRESS_LZO || memory_dump_format ==
+ VIR_MEMORY_DUMP_COMPRESS_SNAPPY)) {
+ virReportSystemError(errno,
+ _("%s"), "memory_dump_format is available
when "
+ "VIR_DUMP_MEMORY_ONLY is set");
+ }
+
ret = 0;
cleanup:
VIR_FORCE_CLOSE(fd);
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index d7da5a8..c02016f 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_dump_format")
GEN_TEST_FUNC(qemuMonitorJSONGraphicsRelocate, VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
"localhost", 12345, 12346, NULL)
GEN_TEST_FUNC(qemuMonitorJSONAddNetdev, "some_dummy_netdevstr")
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index c3db94c..ba17d10 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -4519,6 +4519,14 @@ static const vshCmdOptDef opts_dump[] = {
.type = VSH_OT_BOOL,
.help = N_("dump domain's memory only")
},
+ {.name = "compress",
+ .type = VSH_OT_BOOL,
+ .help = N_("make qemu dump domain's memory in kdump-compressed
format")
+ },
+ {.name = "compression-format",
+ .type = VSH_OT_DATA,
+ .help = N_("specify the compression format of kdump-compressed format")
+ },
{.name = NULL}
};
@@ -4533,6 +4541,9 @@ doDump(void *opaque)
sigset_t sigmask, oldsigmask;
const char *name = NULL;
const char *to = NULL;
+ bool optCompress;
+ const char *compression_format = NULL;
+ unsigned int memory_dump_format = 0;
unsigned int flags = 0;
sigemptyset(&sigmask);
@@ -4557,7 +4568,39 @@ doDump(void *opaque)
if (vshCommandOptBool(cmd, "memory-only"))
flags |= VIR_DUMP_MEMORY_ONLY;
- if (virDomainCoreDump(dom, to, flags) < 0) {
+ optCompress = vshCommandOptBool(cmd, "compress");
+ if (optCompress && !(flags & VIR_DUMP_MEMORY_ONLY)) {
+ vshError(ctl, "%s",
+ _("compress flag cannot be set without memory-only flag"));
+ goto out;
+ }
+
+ if (vshCommandOptString(cmd, "compression-format",
&compression_format)) {
+ if (!optCompress) {
+ vshError(ctl, "%s",
+ _("compression-format cannot be set without compress "
+ "flag"));
+ goto out;
+ }
+
+ if (STREQ(compression_format, "zlib"))
+ memory_dump_format = VIR_MEMORY_DUMP_COMPRESS_ZLIB;
+ else if (STREQ(compression_format, "lzo"))
+ memory_dump_format = VIR_MEMORY_DUMP_COMPRESS_LZO;
+ else if (STREQ(compression_format, "snappy"))
+ memory_dump_format = VIR_MEMORY_DUMP_COMPRESS_SNAPPY;
+ else {
+ vshError(ctl, _("compression format '%s' is not supported,
"
+ "expecting 'zlib', 'lzo' or
'snappy'."),
+ compression_format);
+ goto out;
+ }
+ } else {
+ if (optCompress)
+ memory_dump_format = VIR_MEMORY_DUMP_COMPRESS_ZLIB;
+ }
+
+ if (virDomainCoreDump(dom, to, flags, memory_dump_format) < 0) {
vshError(ctl, _("Failed to core dump domain %s to %s"), name, to);
goto out;
}