
--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@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; }