[libvirt] [PATCH 0/3 v5] use qemu's dump-guest-meory when vm uses host device

Currently, we use migrate to dump guest's memory. There is one restriction in migrate command: the device's status should be stored in qemu because the device's status should be passed to target machine. If we passthrough a host device to guest, the device's status is stored in the real device. So migrate command will fail. We usually use dump when guest is panicked. So there is no need to store device's status in the vmcore. qemu have a new monitor command dump-guest-memory to dump guest memory, but it doesn't support async now(it will support later when the common async API is implemented). Changes from v4 to v5: 1. address Martin Kletzander's comment Changes from v3 to v4: 1. allow the user to specify the core file's format Changes from v2 to v3: 1. qemu supports the fd that is associated with a pipe, socket, or FIFO. So pass a pipe fd to qemu and O_DIRECT can work now. Change from v1 to v2: 1. remove the implemention for text mode. Wen Congyang (3): qemu: implement qemu's dump-guest-memory qemu: allow the client to choose the vmcore's format virsh: allow the user to specify vmcore's format include/libvirt/libvirt.h.in | 1 + src/qemu/qemu_capabilities.c | 5 +++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 60 ++++++++++++++++++++++++++++++++--------- src/qemu/qemu_monitor.c | 37 ++++++++++++++++++++++++++ src/qemu/qemu_monitor.h | 12 ++++++++ src/qemu/qemu_monitor_json.c | 34 +++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 ++++ tools/virsh.c | 3 ++ tools/virsh.pod | 5 +++- 12 files changed, 152 insertions(+), 14 deletions(-)

dump-guest-memory is a new dump mechanism, and it can work when the guest uses host devices. This patch adds a API to use this new monitor command. We will always use json mode if qemu's version is >= 0.15, so I don't implement the API for text mode. --- src/qemu/qemu_monitor.c | 37 +++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.h | 12 ++++++++++++ src/qemu/qemu_monitor_json.c | 34 ++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 ++++++ 4 files changed, 89 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 7084c68..e2a39b8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2022,6 +2022,43 @@ int qemuMonitorMigrateCancel(qemuMonitorPtr mon) return ret; } +int qemuMonitorDumpToFd(qemuMonitorPtr mon, + unsigned int flags, + int fd, + unsigned long long begin, + unsigned long long length) +{ + int ret; + VIR_DEBUG("mon=%p fd=%d flags=%x begin=%llx length=%llx", + mon, fd, flags, begin, length); + + if (!mon) { + qemuReportError(VIR_ERR_INVALID_ARG, "%s", + _("monitor must not be NULL")); + return -1; + } + + if (!mon->json) { + /* We don't have qemuMonitorTextDump(), so we should check mon->json + * here. + */ + qemuReportError(VIR_ERR_NO_SUPPORT, "%s", + _("dump-guest-memory is not supported in text mode")); + return -1; + } + + if (qemuMonitorSendFileHandle(mon, "dump", fd) < 0) + return -1; + + ret = qemuMonitorJSONDump(mon, flags, "fd:dump", begin, length); + + if (ret < 0) { + if (qemuMonitorCloseFileHandle(mon, "dump") < 0) + VIR_WARN("failed to close dumping handle"); + } + + return ret; +} int qemuMonitorGraphicsRelocate(qemuMonitorPtr mon, int type, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index ffe8fe7..66bec38 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -379,6 +379,18 @@ int qemuMonitorMigrateToUnix(qemuMonitorPtr mon, int qemuMonitorMigrateCancel(qemuMonitorPtr mon); +typedef enum { + QEMU_MONITOR_DUMP_HAVE_FILTER = 1 << 0, + QEMU_MONITOR_DUMP_PAGING = 1 << 1, + QEMU_MONITOR_DUMP_FLAGS_LAST +} QEMU_MONITOR_DUMP; + +int qemuMonitorDumpToFd(qemuMonitorPtr mon, + unsigned int flags, + int fd, + unsigned long long begin, + unsigned long long length); + int qemuMonitorGraphicsRelocate(qemuMonitorPtr mon, int type, const char *hostname, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 9030347..6ca01c5 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2465,6 +2465,40 @@ int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon) return ret; } +int qemuMonitorJSONDump(qemuMonitorPtr mon, + unsigned int flags, + const char *protocol, + unsigned long long begin, + unsigned long long length) +{ + int ret; + virJSONValuePtr cmd = NULL; + virJSONValuePtr reply = NULL; + + if (flags & QEMU_MONITOR_DUMP_HAVE_FILTER) + cmd = qemuMonitorJSONMakeCommand("dump-guest-memory", + "b:paging", flags & QEMU_MONITOR_DUMP_PAGING ? 1 : 0, + "s:protocol", protocol, + "U:begin", begin, + "U:length", length, + NULL); + else + cmd = qemuMonitorJSONMakeCommand("dump-guest-memory", + "b:paging", flags & QEMU_MONITOR_DUMP_PAGING ? 1 : 0, + "s:protocol", protocol, + NULL); + if (!cmd) + return -1; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} int qemuMonitorJSONGraphicsRelocate(qemuMonitorPtr mon, int type, diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 22a3adf..e8bd9b8 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -136,6 +136,12 @@ int qemuMonitorJSONMigrate(qemuMonitorPtr mon, int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon); +int qemuMonitorJSONDump(qemuMonitorPtr mon, + unsigned int flags, + const char *protocol, + unsigned long long begin, + unsigned long long length); + int qemuMonitorJSONGraphicsRelocate(qemuMonitorPtr mon, int type, const char *hostname, -- 1.7.1

On 06/12/2012 05:04 AM, Wen Congyang wrote:
dump-guest-memory is a new dump mechanism, and it can work when the guest uses host devices. This patch adds a API to use this new monitor command. We will always use json mode if qemu's version is >= 0.15, so I don't implement the API for text mode. --- src/qemu/qemu_monitor.c | 37 +++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.h | 12 ++++++++++++ src/qemu/qemu_monitor_json.c | 34 ++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 ++++++ 4 files changed, 89 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 7084c68..e2a39b8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2022,6 +2022,43 @@ int qemuMonitorMigrateCancel(qemuMonitorPtr mon) return ret; }
+int qemuMonitorDumpToFd(qemuMonitorPtr mon, + unsigned int flags, + int fd, + unsigned long long begin, + unsigned long long length) +{ + int ret; + VIR_DEBUG("mon=%p fd=%d flags=%x begin=%llx length=%llx", + mon, fd, flags, begin, length); + + if (!mon) { + qemuReportError(VIR_ERR_INVALID_ARG, "%s", + _("monitor must not be NULL")); + return -1; + } + + if (!mon->json) { + /* We don't have qemuMonitorTextDump(), so we should check mon->json + * here. + */ + qemuReportError(VIR_ERR_NO_SUPPORT, "%s", + _("dump-guest-memory is not supported in text mode")); + return -1; + } + + if (qemuMonitorSendFileHandle(mon, "dump", fd) < 0) + return -1; + + ret = qemuMonitorJSONDump(mon, flags, "fd:dump", begin, length); + + if (ret < 0) { + if (qemuMonitorCloseFileHandle(mon, "dump") < 0) + VIR_WARN("failed to close dumping handle"); + } + + return ret; +}
int qemuMonitorGraphicsRelocate(qemuMonitorPtr mon, int type, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index ffe8fe7..66bec38 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -379,6 +379,18 @@ int qemuMonitorMigrateToUnix(qemuMonitorPtr mon,
int qemuMonitorMigrateCancel(qemuMonitorPtr mon);
+typedef enum { + QEMU_MONITOR_DUMP_HAVE_FILTER = 1 << 0, + QEMU_MONITOR_DUMP_PAGING = 1 << 1, + QEMU_MONITOR_DUMP_FLAGS_LAST +} QEMU_MONITOR_DUMP; + +int qemuMonitorDumpToFd(qemuMonitorPtr mon, + unsigned int flags, + int fd, + unsigned long long begin, + unsigned long long length); + int qemuMonitorGraphicsRelocate(qemuMonitorPtr mon, int type, const char *hostname, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 9030347..6ca01c5 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2465,6 +2465,40 @@ int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon) return ret; }
+int qemuMonitorJSONDump(qemuMonitorPtr mon, + unsigned int flags, + const char *protocol, + unsigned long long begin, + unsigned long long length) +{ + int ret; + virJSONValuePtr cmd = NULL; + virJSONValuePtr reply = NULL; + + if (flags & QEMU_MONITOR_DUMP_HAVE_FILTER) + cmd = qemuMonitorJSONMakeCommand("dump-guest-memory", + "b:paging", flags & QEMU_MONITOR_DUMP_PAGING ? 1 : 0, + "s:protocol", protocol, + "U:begin", begin, + "U:length", length, + NULL); + else + cmd = qemuMonitorJSONMakeCommand("dump-guest-memory", + "b:paging", flags & QEMU_MONITOR_DUMP_PAGING ? 1 : 0, + "s:protocol", protocol, + NULL); + if (!cmd) + return -1; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +}
int qemuMonitorJSONGraphicsRelocate(qemuMonitorPtr mon, int type, diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 22a3adf..e8bd9b8 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -136,6 +136,12 @@ int qemuMonitorJSONMigrate(qemuMonitorPtr mon,
int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon);
+int qemuMonitorJSONDump(qemuMonitorPtr mon, + unsigned int flags, + const char *protocol, + unsigned long long begin, + unsigned long long length); + int qemuMonitorJSONGraphicsRelocate(qemuMonitorPtr mon, int type, const char *hostname,
Looks fine with me, ACK. Martin

This patch updates qemu driver to allow the client to choose the vmcore's format: memory only or including device state. --- include/libvirt/libvirt.h.in | 1 + src/qemu/qemu_capabilities.c | 5 +++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 60 ++++++++++++++++++++++++++++++++--------- 6 files changed, 56 insertions(+), 13 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index fcb6695..120ed14 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -927,6 +927,7 @@ typedef enum { VIR_DUMP_LIVE = (1 << 1), /* live dump */ VIR_DUMP_BYPASS_CACHE = (1 << 2), /* avoid file system cache pollution */ VIR_DUMP_RESET = (1 << 3), /* reset domain after dump finishes */ + VIR_DUMP_MEMORY_ONLY = (1 << 4), /* use dump-guest-memory */ } virDomainCoreDumpFlags; /* Domain migration flags. */ diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index b410648..6eee8cd 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -164,6 +164,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "no-user-config", "hda-micro", /* 95 */ + "dump-guest-memory", ); @@ -1237,6 +1238,10 @@ qemuCapsComputeCmdFlags(const char *help, if (version >= 11000) qemuCapsSet(flags, QEMU_CAPS_CPU_HOST); + + if (version >= 1001050) + qemuCapsSet(flags, QEMU_CAPS_DUMP_GUEST_MEMORY); + return 0; } diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 64831e2..640f7f5 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -131,6 +131,7 @@ enum qemuCapsFlags { QEMU_CAPS_IDE_CD = 93, /* -device ide-cd */ QEMU_CAPS_NO_USER_CONFIG = 94, /* -no-user-config */ QEMU_CAPS_HDA_MICRO = 95, /* -device hda-micro */ + QEMU_CAPS_DUMP_GUEST_MEMORY = 96, /* dump-guest-memory command */ QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 3752ddf..91c0645 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -160,6 +160,7 @@ qemuDomainObjResetAsyncJob(qemuDomainObjPrivatePtr priv) job->phase = 0; job->mask = DEFAULT_JOB_MASK; job->start = 0; + job->dump_memory_only = false; memset(&job->info, 0, sizeof(job->info)); } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 1256c4e..3a5f1f3 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -104,6 +104,7 @@ struct qemuDomainJobObj { int phase; /* Job phase (mainly for migrations) */ unsigned long long mask; /* Jobs allowed during async job */ unsigned long long start; /* When the async job started */ + bool dump_memory_only; /* use dump-guest-memory to do dump */ virDomainJobInfo info; /* Async job progress data */ }; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d3f74d2..b2da838 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2986,12 +2986,39 @@ cleanup: return ret; } +static int qemuDumpToFd(struct qemud_driver *driver, virDomainObjPtr vm, + int fd, enum qemuDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + int ret = -1; + + if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY)) { + qemuReportError(VIR_ERR_NO_SUPPORT, "%s", + _("dump-guest-memory is not supported")); + return -1; + } + + if (virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def, + fd) < 0) + return -1; + + priv->job.dump_memory_only = true; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) + return -1; + + ret = qemuMonitorDumpToFd(priv->mon, 0, fd, 0, 0); + qemuDomainObjExitMonitorWithDriver(driver, vm); + + return ret; +} + static int doCoreDump(struct qemud_driver *driver, virDomainObjPtr vm, const char *path, enum qemud_save_formats compress, - bool bypass_cache) + unsigned int dump_flags) { int fd = -1; int ret = -1; @@ -3000,7 +3027,7 @@ doCoreDump(struct qemud_driver *driver, unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING; /* Create an empty file with appropriate ownership. */ - if (bypass_cache) { + if (dump_flags & VIR_DUMP_BYPASS_CACHE) { flags |= VIR_FILE_WRAPPER_BYPASS_CACHE; directFlag = virFileDirectFdFlag(); if (directFlag < 0) { @@ -3020,14 +3047,20 @@ doCoreDump(struct qemud_driver *driver, if (!(wrapperFd = virFileWrapperFdNew(&fd, path, flags))) goto cleanup; - if (qemuMigrationToFile(driver, vm, fd, 0, path, - qemuCompressProgramName(compress), false, - QEMU_ASYNC_JOB_DUMP) < 0) + if (dump_flags & VIR_DUMP_MEMORY_ONLY) { + ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP); + } else { + ret = qemuMigrationToFile(driver, vm, fd, 0, path, + qemuCompressProgramName(compress), false, + QEMU_ASYNC_JOB_DUMP); + } + + if (ret < 0) goto cleanup; if (VIR_CLOSE(fd) < 0) { virReportSystemError(errno, - _("unable to save file %s"), + _("unable to close file %s"), path); goto cleanup; } @@ -3085,7 +3118,8 @@ static int qemudDomainCoreDump(virDomainPtr dom, virDomainEventPtr event = NULL; virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH | - VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET, -1); + VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET | + VIR_DUMP_MEMORY_ONLY, -1); qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -3127,8 +3161,7 @@ static int qemudDomainCoreDump(virDomainPtr dom, } } - ret = doCoreDump(driver, vm, path, getCompressionType(driver), - (flags & VIR_DUMP_BYPASS_CACHE) != 0); + ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags); if (ret < 0) goto endjob; @@ -3289,6 +3322,7 @@ static void processWatchdogEvent(void *data, void *opaque) case VIR_DOMAIN_WATCHDOG_ACTION_DUMP: { char *dumpfile; + unsigned int flags = 0; if (virAsprintf(&dumpfile, "%s/%s-%u", driver->autoDumpPath, @@ -3311,9 +3345,9 @@ static void processWatchdogEvent(void *data, void *opaque) goto endjob; } + flags |= driver->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0; ret = doCoreDump(driver, wdEvent->vm, dumpfile, - getCompressionType(driver), - driver->autoDumpBypassCache); + getCompressionType(driver), flags); if (ret < 0) qemuReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Dump failed")); @@ -9402,7 +9436,7 @@ static int qemuDomainGetJobInfo(virDomainPtr dom, priv = vm->privateData; if (virDomainObjIsActive(vm)) { - if (priv->job.asyncJob) { + if (priv->job.asyncJob && !priv->job.dump_memory_only) { memcpy(info, &priv->job.info, sizeof(*info)); /* Refresh elapsed time again just to ensure it @@ -9460,7 +9494,7 @@ static int qemuDomainAbortJob(virDomainPtr dom) { priv = vm->privateData; - if (!priv->job.asyncJob) { + if (!priv->job.asyncJob || priv->job.dump_memory_only) { qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", _("no job is active on the domain")); goto endjob; -- 1.7.1

On 06/12/2012 05:06 AM, Wen Congyang wrote:
This patch updates qemu driver to allow the client to choose the vmcore's format: memory only or including device state. --- include/libvirt/libvirt.h.in | 1 + src/qemu/qemu_capabilities.c | 5 +++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 60 ++++++++++++++++++++++++++++++++--------- 6 files changed, 56 insertions(+), 13 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index fcb6695..120ed14 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -927,6 +927,7 @@ typedef enum { VIR_DUMP_LIVE = (1 << 1), /* live dump */ VIR_DUMP_BYPASS_CACHE = (1 << 2), /* avoid file system cache pollution */ VIR_DUMP_RESET = (1 << 3), /* reset domain after dump finishes */ + VIR_DUMP_MEMORY_ONLY = (1 << 4), /* use dump-guest-memory */ } virDomainCoreDumpFlags;
/* Domain migration flags. */ diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index b410648..6eee8cd 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -164,6 +164,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "no-user-config",
"hda-micro", /* 95 */ + "dump-guest-memory",
);
@@ -1237,6 +1238,10 @@ qemuCapsComputeCmdFlags(const char *help,
if (version >= 11000) qemuCapsSet(flags, QEMU_CAPS_CPU_HOST); + + if (version >= 1001050) + qemuCapsSet(flags, QEMU_CAPS_DUMP_GUEST_MEMORY); + return 0; }
Sorry for bothering you with this, but I tried newest qemu and it shows the proper list of commands with query-commands in qmp. Instead of this one hunk, I'd use this: diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 6ca01c5..7d2da21 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -991,6 +991,8 @@ qemuMonitorJSONCheckCommands(qemuMonitorPtr mon, qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC); else if (STREQ(name, "block-job-cancel")) qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC); + else if (STREQ(name, "dump-guest-memory")) + qemuCapsSet(qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY); } ret = 0;
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 64831e2..640f7f5 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -131,6 +131,7 @@ enum qemuCapsFlags { QEMU_CAPS_IDE_CD = 93, /* -device ide-cd */ QEMU_CAPS_NO_USER_CONFIG = 94, /* -no-user-config */ QEMU_CAPS_HDA_MICRO = 95, /* -device hda-micro */ + QEMU_CAPS_DUMP_GUEST_MEMORY = 96, /* dump-guest-memory command */
QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 3752ddf..91c0645 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -160,6 +160,7 @@ qemuDomainObjResetAsyncJob(qemuDomainObjPrivatePtr priv) job->phase = 0; job->mask = DEFAULT_JOB_MASK; job->start = 0; + job->dump_memory_only = false; memset(&job->info, 0, sizeof(job->info)); }
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 1256c4e..3a5f1f3 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -104,6 +104,7 @@ struct qemuDomainJobObj { int phase; /* Job phase (mainly for migrations) */ unsigned long long mask; /* Jobs allowed during async job */ unsigned long long start; /* When the async job started */ + bool dump_memory_only; /* use dump-guest-memory to do dump */ virDomainJobInfo info; /* Async job progress data */ };
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d3f74d2..b2da838 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2986,12 +2986,39 @@ cleanup: return ret; }
+static int qemuDumpToFd(struct qemud_driver *driver, virDomainObjPtr vm, + int fd, enum qemuDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + int ret = -1; + + if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY)) { + qemuReportError(VIR_ERR_NO_SUPPORT, "%s", + _("dump-guest-memory is not supported")); + return -1; + } + + if (virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def, + fd) < 0) + return -1; + + priv->job.dump_memory_only = true; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) + return -1; + + ret = qemuMonitorDumpToFd(priv->mon, 0, fd, 0, 0); + qemuDomainObjExitMonitorWithDriver(driver, vm); + + return ret; +} + static int doCoreDump(struct qemud_driver *driver, virDomainObjPtr vm, const char *path, enum qemud_save_formats compress, - bool bypass_cache) + unsigned int dump_flags) { int fd = -1; int ret = -1; @@ -3000,7 +3027,7 @@ doCoreDump(struct qemud_driver *driver, unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
/* Create an empty file with appropriate ownership. */ - if (bypass_cache) { + if (dump_flags & VIR_DUMP_BYPASS_CACHE) { flags |= VIR_FILE_WRAPPER_BYPASS_CACHE; directFlag = virFileDirectFdFlag(); if (directFlag < 0) { @@ -3020,14 +3047,20 @@ doCoreDump(struct qemud_driver *driver, if (!(wrapperFd = virFileWrapperFdNew(&fd, path, flags))) goto cleanup;
- if (qemuMigrationToFile(driver, vm, fd, 0, path, - qemuCompressProgramName(compress), false, - QEMU_ASYNC_JOB_DUMP) < 0) + if (dump_flags & VIR_DUMP_MEMORY_ONLY) { + ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP); + } else { + ret = qemuMigrationToFile(driver, vm, fd, 0, path, + qemuCompressProgramName(compress), false, + QEMU_ASYNC_JOB_DUMP); + } + + if (ret < 0) goto cleanup;
if (VIR_CLOSE(fd) < 0) { virReportSystemError(errno, - _("unable to save file %s"), + _("unable to close file %s"), path); goto cleanup; } @@ -3085,7 +3118,8 @@ static int qemudDomainCoreDump(virDomainPtr dom, virDomainEventPtr event = NULL;
virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH | - VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET, -1); + VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET | + VIR_DUMP_MEMORY_ONLY, -1);
qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -3127,8 +3161,7 @@ static int qemudDomainCoreDump(virDomainPtr dom, } }
- ret = doCoreDump(driver, vm, path, getCompressionType(driver), - (flags & VIR_DUMP_BYPASS_CACHE) != 0); + ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags); if (ret < 0) goto endjob;
@@ -3289,6 +3322,7 @@ static void processWatchdogEvent(void *data, void *opaque) case VIR_DOMAIN_WATCHDOG_ACTION_DUMP: { char *dumpfile; + unsigned int flags = 0;
if (virAsprintf(&dumpfile, "%s/%s-%u", driver->autoDumpPath, @@ -3311,9 +3345,9 @@ static void processWatchdogEvent(void *data, void *opaque) goto endjob; }
+ flags |= driver->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0; ret = doCoreDump(driver, wdEvent->vm, dumpfile, - getCompressionType(driver), - driver->autoDumpBypassCache); + getCompressionType(driver), flags); if (ret < 0) qemuReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Dump failed")); @@ -9402,7 +9436,7 @@ static int qemuDomainGetJobInfo(virDomainPtr dom, priv = vm->privateData;
if (virDomainObjIsActive(vm)) { - if (priv->job.asyncJob) { + if (priv->job.asyncJob && !priv->job.dump_memory_only) { memcpy(info, &priv->job.info, sizeof(*info));
/* Refresh elapsed time again just to ensure it @@ -9460,7 +9494,7 @@ static int qemuDomainAbortJob(virDomainPtr dom) {
priv = vm->privateData;
- if (!priv->job.asyncJob) { + if (!priv->job.asyncJob || priv->job.dump_memory_only) { qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", _("no job is active on the domain")); goto endjob;
, so ACK with that one hunk changed. Martin

On 06/13/2012 02:57 PM, Martin Kletzander wrote:
On 06/12/2012 05:06 AM, Wen Congyang wrote:
This patch updates qemu driver to allow the client to choose the vmcore's format: memory only or including device state. --- include/libvirt/libvirt.h.in | 1 + src/qemu/qemu_capabilities.c | 5 +++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 60 ++++++++++++++++++++++++++++++++--------- 6 files changed, 56 insertions(+), 13 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index fcb6695..120ed14 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -927,6 +927,7 @@ typedef enum { VIR_DUMP_LIVE = (1 << 1), /* live dump */ VIR_DUMP_BYPASS_CACHE = (1 << 2), /* avoid file system cache pollution */ VIR_DUMP_RESET = (1 << 3), /* reset domain after dump finishes */ + VIR_DUMP_MEMORY_ONLY = (1 << 4), /* use dump-guest-memory */ } virDomainCoreDumpFlags;
/* Domain migration flags. */ diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index b410648..6eee8cd 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -164,6 +164,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "no-user-config",
"hda-micro", /* 95 */ + "dump-guest-memory",
);
@@ -1237,6 +1238,10 @@ qemuCapsComputeCmdFlags(const char *help,
if (version >= 11000) qemuCapsSet(flags, QEMU_CAPS_CPU_HOST); + + if (version >= 1001050) + qemuCapsSet(flags, QEMU_CAPS_DUMP_GUEST_MEMORY); + return 0; }
Sorry for bothering you with this, but I tried newest qemu and it shows the proper list of commands with query-commands in qmp. Instead of this one hunk, I'd use this:
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 6ca01c5..7d2da21 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -991,6 +991,8 @@ qemuMonitorJSONCheckCommands(qemuMonitorPtr mon, qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC); else if (STREQ(name, "block-job-cancel")) qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC); + else if (STREQ(name, "dump-guest-memory")) + qemuCapsSet(qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY); }
ret = 0;
[...]
, so ACK with that one hunk changed.
Martin
To make it easier for you, you can squash this patch into it (this is what I tested it with). --- src/qemu/qemu_capabilities.c | 3 --- src/qemu/qemu_monitor_json.c | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 6eee8cd..7b368aa 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -1239,9 +1239,6 @@ qemuCapsComputeCmdFlags(const char *help, if (version >= 11000) qemuCapsSet(flags, QEMU_CAPS_CPU_HOST); - if (version >= 1001050) - qemuCapsSet(flags, QEMU_CAPS_DUMP_GUEST_MEMORY); - return 0; } diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 6ca01c5..7d2da21 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -991,6 +991,8 @@ qemuMonitorJSONCheckCommands(qemuMonitorPtr mon, qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC); else if (STREQ(name, "block-job-cancel")) qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC); + else if (STREQ(name, "dump-guest-memory")) + qemuCapsSet(qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY); } ret = 0; -- 1.7.8.6

On 06/13/2012 08:57 PM, Martin Kletzander wrote:
On 06/12/2012 05:06 AM, Wen Congyang wrote:
This patch updates qemu driver to allow the client to choose the vmcore's format: memory only or including device state. --- include/libvirt/libvirt.h.in | 1 + src/qemu/qemu_capabilities.c | 5 +++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 60 ++++++++++++++++++++++++++++++++--------- 6 files changed, 56 insertions(+), 13 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index fcb6695..120ed14 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -927,6 +927,7 @@ typedef enum { VIR_DUMP_LIVE = (1<< 1), /* live dump */ VIR_DUMP_BYPASS_CACHE = (1<< 2), /* avoid file system cache pollution */ VIR_DUMP_RESET = (1<< 3), /* reset domain after dump finishes */ + VIR_DUMP_MEMORY_ONLY = (1<< 4), /* use dump-guest-memory */ } virDomainCoreDumpFlags;
/* Domain migration flags. */ diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index b410648..6eee8cd 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -164,6 +164,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "no-user-config",
"hda-micro", /* 95 */ + "dump-guest-memory",
);
@@ -1237,6 +1238,10 @@ qemuCapsComputeCmdFlags(const char *help,
if (version>= 11000) qemuCapsSet(flags, QEMU_CAPS_CPU_HOST); + + if (version>= 1001050) + qemuCapsSet(flags, QEMU_CAPS_DUMP_GUEST_MEMORY); + return 0; }
Sorry for bothering you with this, but I tried newest qemu and it shows the proper list of commands with query-commands in qmp. Instead of this one hunk, I'd use this:
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 6ca01c5..7d2da21 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -991,6 +991,8 @@ qemuMonitorJSONCheckCommands(qemuMonitorPtr mon, qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC); else if (STREQ(name, "block-job-cancel")) qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC); + else if (STREQ(name, "dump-guest-memory")) + qemuCapsSet(qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY); }
ret = 0;
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 64831e2..640f7f5 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -131,6 +131,7 @@ enum qemuCapsFlags { QEMU_CAPS_IDE_CD = 93, /* -device ide-cd */ QEMU_CAPS_NO_USER_CONFIG = 94, /* -no-user-config */ QEMU_CAPS_HDA_MICRO = 95, /* -device hda-micro */ + QEMU_CAPS_DUMP_GUEST_MEMORY = 96, /* dump-guest-memory command */
QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 3752ddf..91c0645 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -160,6 +160,7 @@ qemuDomainObjResetAsyncJob(qemuDomainObjPrivatePtr priv) job->phase = 0; job->mask = DEFAULT_JOB_MASK; job->start = 0; + job->dump_memory_only = false; memset(&job->info, 0, sizeof(job->info)); }
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 1256c4e..3a5f1f3 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -104,6 +104,7 @@ struct qemuDomainJobObj { int phase; /* Job phase (mainly for migrations) */ unsigned long long mask; /* Jobs allowed during async job */ unsigned long long start; /* When the async job started */ + bool dump_memory_only; /* use dump-guest-memory to do dump */ virDomainJobInfo info; /* Async job progress data */ };
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d3f74d2..b2da838 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2986,12 +2986,39 @@ cleanup: return ret; }
+static int qemuDumpToFd(struct qemud_driver *driver, virDomainObjPtr vm, + int fd, enum qemuDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + int ret = -1; + + if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY)) { + qemuReportError(VIR_ERR_NO_SUPPORT, "%s", + _("dump-guest-memory is not supported")); + return -1; + } + + if (virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def, + fd)< 0) + return -1; + + priv->job.dump_memory_only = true; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob)< 0) + return -1; + + ret = qemuMonitorDumpToFd(priv->mon, 0, fd, 0, 0); + qemuDomainObjExitMonitorWithDriver(driver, vm); + + return ret; +} + static int doCoreDump(struct qemud_driver *driver, virDomainObjPtr vm, const char *path, enum qemud_save_formats compress, - bool bypass_cache) + unsigned int dump_flags) { int fd = -1; int ret = -1; @@ -3000,7 +3027,7 @@ doCoreDump(struct qemud_driver *driver, unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
/* Create an empty file with appropriate ownership. */ - if (bypass_cache) { + if (dump_flags& VIR_DUMP_BYPASS_CACHE) { flags |= VIR_FILE_WRAPPER_BYPASS_CACHE; directFlag = virFileDirectFdFlag(); if (directFlag< 0) { @@ -3020,14 +3047,20 @@ doCoreDump(struct qemud_driver *driver, if (!(wrapperFd = virFileWrapperFdNew(&fd, path, flags))) goto cleanup;
- if (qemuMigrationToFile(driver, vm, fd, 0, path, - qemuCompressProgramName(compress), false, - QEMU_ASYNC_JOB_DUMP)< 0) + if (dump_flags& VIR_DUMP_MEMORY_ONLY) { + ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP); + } else { + ret = qemuMigrationToFile(driver, vm, fd, 0, path, + qemuCompressProgramName(compress), false, + QEMU_ASYNC_JOB_DUMP); + } + + if (ret< 0) goto cleanup;
if (VIR_CLOSE(fd)< 0) { virReportSystemError(errno, - _("unable to save file %s"), + _("unable to close file %s"), path); goto cleanup; } @@ -3085,7 +3118,8 @@ static int qemudDomainCoreDump(virDomainPtr dom, virDomainEventPtr event = NULL;
virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH | - VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET, -1); + VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET | + VIR_DUMP_MEMORY_ONLY, -1);
qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -3127,8 +3161,7 @@ static int qemudDomainCoreDump(virDomainPtr dom, } }
- ret = doCoreDump(driver, vm, path, getCompressionType(driver), - (flags& VIR_DUMP_BYPASS_CACHE) != 0); + ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags); if (ret< 0) goto endjob;
@@ -3289,6 +3322,7 @@ static void processWatchdogEvent(void *data, void *opaque) case VIR_DOMAIN_WATCHDOG_ACTION_DUMP: { char *dumpfile; + unsigned int flags = 0;
if (virAsprintf(&dumpfile, "%s/%s-%u", driver->autoDumpPath, @@ -3311,9 +3345,9 @@ static void processWatchdogEvent(void *data, void *opaque) goto endjob; }
+ flags |= driver->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0; ret = doCoreDump(driver, wdEvent->vm, dumpfile, - getCompressionType(driver), - driver->autoDumpBypassCache); + getCompressionType(driver), flags); if (ret< 0) qemuReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Dump failed")); @@ -9402,7 +9436,7 @@ static int qemuDomainGetJobInfo(virDomainPtr dom, priv = vm->privateData;
if (virDomainObjIsActive(vm)) { - if (priv->job.asyncJob) { + if (priv->job.asyncJob&& !priv->job.dump_memory_only) { memcpy(info,&priv->job.info, sizeof(*info));
/* Refresh elapsed time again just to ensure it @@ -9460,7 +9494,7 @@ static int qemuDomainAbortJob(virDomainPtr dom) {
priv = vm->privateData;
- if (!priv->job.asyncJob) { + if (!priv->job.asyncJob || priv->job.dump_memory_only) { qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", _("no job is active on the domain")); goto endjob;
, so ACK with that one hunk changed.
Thanks, pushed with this hunck changed Wen Congyang
Martin
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

Add a new parameter --memory-only for 'virsh dump' command. So the user can decide the vmcore's format. --- tools/virsh.c | 3 +++ tools/virsh.pod | 5 ++++- 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index abcfbff..c875a90 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -4006,6 +4006,7 @@ static const vshCmdOptDef opts_dump[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("where to dump the core")}, {"verbose", VSH_OT_BOOL, 0, N_("display the progress of dump")}, + {"memory-only", VSH_OT_BOOL, 0, N_("dump domain's memory only")}, {NULL, 0, 0, NULL} }; @@ -4044,6 +4045,8 @@ doDump(void *opaque) flags |= VIR_DUMP_BYPASS_CACHE; if (vshCommandOptBool(cmd, "reset")) flags |= VIR_DUMP_RESET; + 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); diff --git a/tools/virsh.pod b/tools/virsh.pod index ef71717..e870c03 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -827,7 +827,7 @@ the I<format> argument must be B<qemu-argv>. For Xen hypervisor, the I<format> argument may be B<xen-xm> or B<xen-sxpr>. =item B<dump> I<domain-id> I<corefilepath> [I<--bypass-cache>] -{ [I<--live>] | [I<--crash>] | [I<--reset>] } [I<--verbose>] +{ [I<--live>] | [I<--crash>] | [I<--reset>] } [I<--verbose>] [I<--memory-only>] Dumps the core of a domain to a file for analysis. If I<--live> is specified, the domain continues to run until the core @@ -838,6 +838,9 @@ If I<--reset> is specified, the domain is reset after successful dump. Note, these three switches are mutually exclusive. If I<--bypass-cache> is specified, the save will avoid the file system 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. The progress may be monitored using B<domjobinfo> virsh command and canceled with B<domjobabort> command (sent by another virsh instance). Another option -- 1.7.1

On 06/12/2012 05:07 AM, Wen Congyang wrote:
Add a new parameter --memory-only for 'virsh dump' command. So the user can decide the vmcore's format. --- tools/virsh.c | 3 +++ tools/virsh.pod | 5 ++++- 2 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c index abcfbff..c875a90 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -4006,6 +4006,7 @@ static const vshCmdOptDef opts_dump[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("where to dump the core")}, {"verbose", VSH_OT_BOOL, 0, N_("display the progress of dump")}, + {"memory-only", VSH_OT_BOOL, 0, N_("dump domain's memory only")}, {NULL, 0, 0, NULL} };
@@ -4044,6 +4045,8 @@ doDump(void *opaque) flags |= VIR_DUMP_BYPASS_CACHE; if (vshCommandOptBool(cmd, "reset")) flags |= VIR_DUMP_RESET; + 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); diff --git a/tools/virsh.pod b/tools/virsh.pod index ef71717..e870c03 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -827,7 +827,7 @@ the I<format> argument must be B<qemu-argv>. For Xen hypervisor, the I<format> argument may be B<xen-xm> or B<xen-sxpr>.
=item B<dump> I<domain-id> I<corefilepath> [I<--bypass-cache>] -{ [I<--live>] | [I<--crash>] | [I<--reset>] } [I<--verbose>] +{ [I<--live>] | [I<--crash>] | [I<--reset>] } [I<--verbose>] [I<--memory-only>]
Dumps the core of a domain to a file for analysis. If I<--live> is specified, the domain continues to run until the core @@ -838,6 +838,9 @@ If I<--reset> is specified, the domain is reset after successful dump. Note, these three switches are mutually exclusive. If I<--bypass-cache> is specified, the save will avoid the file system 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.
The progress may be monitored using B<domjobinfo> virsh command and canceled with B<domjobabort> command (sent by another virsh instance). Another option
ACK. Martin
participants (3)
-
Martin Kletzander
-
Wen Congyang
-
Wen Congyang