mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 03:12:22 +00:00
Add a watchdog action `dump'
`dump' watchdog action lets libvirtd to dump the guest when receives a watchdog event (which probably means a guest crash) Currently only qemu is supported.
This commit is contained in:
parent
b4560bf2ef
commit
e19cdbfcf1
@ -244,6 +244,7 @@ VIR_ENUM_IMPL(virDomainWatchdogAction, VIR_DOMAIN_WATCHDOG_ACTION_LAST,
|
||||
"shutdown",
|
||||
"poweroff",
|
||||
"pause",
|
||||
"dump",
|
||||
"none")
|
||||
|
||||
VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
|
||||
|
@ -462,6 +462,7 @@ enum virDomainWatchdogAction {
|
||||
VIR_DOMAIN_WATCHDOG_ACTION_SHUTDOWN,
|
||||
VIR_DOMAIN_WATCHDOG_ACTION_POWEROFF,
|
||||
VIR_DOMAIN_WATCHDOG_ACTION_PAUSE,
|
||||
VIR_DOMAIN_WATCHDOG_ACTION_DUMP,
|
||||
VIR_DOMAIN_WATCHDOG_ACTION_NONE,
|
||||
|
||||
VIR_DOMAIN_WATCHDOG_ACTION_LAST
|
||||
|
@ -37,6 +37,7 @@ module Libvirtd_qemu =
|
||||
| str_array_entry "cgroup_device_acl"
|
||||
| str_entry "save_image_format"
|
||||
| str_entry "dump_image_format"
|
||||
| str_entry "auto_dump_path"
|
||||
| str_entry "hugetlbfs_mount"
|
||||
| bool_entry "relaxed_acs_check"
|
||||
| bool_entry "vnc_allow_host_audio"
|
||||
|
@ -191,6 +191,11 @@
|
||||
# save_image_format = "raw"
|
||||
# dump_image_format = "raw"
|
||||
|
||||
# When a domain is configured to be auto-dumped when libvirtd receives a
|
||||
# watchdog event from qemu guest, libvirtd will save dump files in directory
|
||||
# specified by auto_dump_path. Default value is /var/lib/libvirt/qemu/dump
|
||||
#
|
||||
# auto_dump_path = "/var/lib/libvirt/qemu/dump"
|
||||
|
||||
# If provided by the host and a hugetlbfs mount point is configured,
|
||||
# a guest may request huge page backing. When this mount point is
|
||||
|
@ -386,6 +386,17 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
|
||||
}
|
||||
}
|
||||
|
||||
p = virConfGetValue (conf, "auto_dump_path");
|
||||
CHECK_TYPE ("auto_dump_path", VIR_CONF_STRING);
|
||||
if (p && p->str) {
|
||||
VIR_FREE(driver->autoDumpPath);
|
||||
if (!(driver->autoDumpPath = strdup(p->str))) {
|
||||
virReportOOMError();
|
||||
virConfFree(conf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
p = virConfGetValue (conf, "hugetlbfs_mount");
|
||||
CHECK_TYPE ("hugetlbfs_mount", VIR_CONF_STRING);
|
||||
if (p && p->str) {
|
||||
@ -5276,7 +5287,10 @@ qemudBuildCommandLine(virConnectPtr conn,
|
||||
virCommandAddArg(cmd, optstr);
|
||||
VIR_FREE(optstr);
|
||||
|
||||
const char *action = virDomainWatchdogActionTypeToString(watchdog->action);
|
||||
int act = watchdog->action;
|
||||
if (act == VIR_DOMAIN_WATCHDOG_ACTION_DUMP)
|
||||
act = VIR_DOMAIN_WATCHDOG_ACTION_PAUSE;
|
||||
const char *action = virDomainWatchdogActionTypeToString(act);
|
||||
if (!action) {
|
||||
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("invalid watchdog action"));
|
||||
|
@ -43,6 +43,7 @@
|
||||
# include "bitmap.h"
|
||||
# include "macvtap.h"
|
||||
# include "command.h"
|
||||
# include "threadpool.h"
|
||||
|
||||
# define QEMUD_CPUMASK_LEN CPU_SETSIZE
|
||||
|
||||
@ -108,6 +109,8 @@ enum qemud_cmd_flags {
|
||||
struct qemud_driver {
|
||||
virMutex lock;
|
||||
|
||||
virThreadPoolPtr workerPool;
|
||||
|
||||
int privileged;
|
||||
|
||||
uid_t user;
|
||||
@ -175,6 +178,8 @@ struct qemud_driver {
|
||||
char *saveImageFormat;
|
||||
char *dumpImageFormat;
|
||||
|
||||
char *autoDumpPath;
|
||||
|
||||
pciDeviceList *activePciHostdevs;
|
||||
|
||||
virBitmapPtr reservedVNCPorts;
|
||||
|
@ -85,6 +85,7 @@
|
||||
#include "files.h"
|
||||
#include "fdstream.h"
|
||||
#include "configmake.h"
|
||||
#include "threadpool.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||
|
||||
@ -138,6 +139,14 @@ struct _qemuDomainObjPrivate {
|
||||
int persistentAddrs;
|
||||
};
|
||||
|
||||
struct watchdogEvent
|
||||
{
|
||||
virDomainObjPtr vm;
|
||||
int action;
|
||||
};
|
||||
|
||||
static void processWatchdogEvent(void *data, void *opaque);
|
||||
|
||||
static int qemudShutdown(void);
|
||||
|
||||
static void qemuDriverLock(struct qemud_driver *driver)
|
||||
@ -1225,6 +1234,17 @@ qemuHandleDomainWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
||||
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
|
||||
VIR_WARN("Unable to save status on vm %s after IO error", vm->def->name);
|
||||
}
|
||||
|
||||
if (vm->def->watchdog->action == VIR_DOMAIN_WATCHDOG_ACTION_DUMP) {
|
||||
struct watchdogEvent *wdEvent;
|
||||
if (VIR_ALLOC(wdEvent) == 0) {
|
||||
wdEvent->action = VIR_DOMAIN_WATCHDOG_ACTION_DUMP;
|
||||
wdEvent->vm = vm;
|
||||
ignore_value(virThreadPoolSendJob(driver->workerPool, wdEvent));
|
||||
} else
|
||||
virReportOOMError();
|
||||
}
|
||||
|
||||
virDomainObjUnlock(vm);
|
||||
|
||||
if (watchdogEvent || lifecycleEvent) {
|
||||
@ -1808,6 +1828,9 @@ qemudStartup(int privileged) {
|
||||
if (virAsprintf(&qemu_driver->snapshotDir,
|
||||
"%s/lib/libvirt/qemu/snapshot", LOCALSTATEDIR) == -1)
|
||||
goto out_of_memory;
|
||||
if (virAsprintf(&qemu_driver->autoDumpPath,
|
||||
"%s/lib/libvirt/qemu/dump", LOCALSTATEDIR) == -1)
|
||||
goto out_of_memory;
|
||||
} else {
|
||||
uid_t uid = geteuid();
|
||||
char *userdir = virGetUserDirectory(uid);
|
||||
@ -1836,6 +1859,8 @@ qemudStartup(int privileged) {
|
||||
goto out_of_memory;
|
||||
if (virAsprintf(&qemu_driver->snapshotDir, "%s/qemu/snapshot", base) == -1)
|
||||
goto out_of_memory;
|
||||
if (virAsprintf(&qemu_driver->autoDumpPath, "%s/qemu/dump", base) == -1)
|
||||
goto out_of_memory;
|
||||
}
|
||||
|
||||
if (virFileMakePath(qemu_driver->stateDir) != 0) {
|
||||
@ -1868,6 +1893,12 @@ qemudStartup(int privileged) {
|
||||
qemu_driver->snapshotDir, virStrerror(errno, ebuf, sizeof ebuf));
|
||||
goto error;
|
||||
}
|
||||
if (virFileMakePath(qemu_driver->autoDumpPath) != 0) {
|
||||
char ebuf[1024];
|
||||
VIR_ERROR(_("Failed to create dump dir '%s': %s"),
|
||||
qemu_driver->autoDumpPath, virStrerror(errno, ebuf, sizeof ebuf));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Configuration paths are either ~/.libvirt/qemu/... (session) or
|
||||
* /etc/libvirt/qemu/... (system).
|
||||
@ -1993,6 +2024,10 @@ qemudStartup(int privileged) {
|
||||
|
||||
qemudAutostartConfigs(qemu_driver);
|
||||
|
||||
qemu_driver->workerPool = virThreadPoolNew(0, 1, processWatchdogEvent, qemu_driver);
|
||||
if (!qemu_driver->workerPool)
|
||||
goto error;
|
||||
|
||||
if (conn)
|
||||
virConnectClose(conn);
|
||||
|
||||
@ -2099,6 +2134,7 @@ qemudShutdown(void) {
|
||||
VIR_FREE(qemu_driver->cacheDir);
|
||||
VIR_FREE(qemu_driver->saveDir);
|
||||
VIR_FREE(qemu_driver->snapshotDir);
|
||||
VIR_FREE(qemu_driver->autoDumpPath);
|
||||
VIR_FREE(qemu_driver->vncTLSx509certdir);
|
||||
VIR_FREE(qemu_driver->vncListen);
|
||||
VIR_FREE(qemu_driver->vncPassword);
|
||||
@ -2134,6 +2170,7 @@ qemudShutdown(void) {
|
||||
|
||||
qemuDriverUnlock(qemu_driver);
|
||||
virMutexDestroy(&qemu_driver->lock);
|
||||
virThreadPoolFree(qemu_driver->workerPool);
|
||||
VIR_FREE(qemu_driver);
|
||||
|
||||
return 0;
|
||||
@ -6230,6 +6267,65 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void processWatchdogEvent(void *data, void *opaque)
|
||||
{
|
||||
int ret;
|
||||
struct watchdogEvent *wdEvent = data;
|
||||
struct qemud_driver *driver = opaque;
|
||||
|
||||
switch (wdEvent->action) {
|
||||
case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
|
||||
{
|
||||
char *dumpfile;
|
||||
int i;
|
||||
|
||||
qemuDomainObjPrivatePtr priv = wdEvent->vm->privateData;
|
||||
|
||||
i = virAsprintf(&dumpfile, "%s/%s-%u",
|
||||
driver->autoDumpPath,
|
||||
wdEvent->vm->def->name,
|
||||
(unsigned int)time(NULL));
|
||||
|
||||
qemuDriverLock(driver);
|
||||
virDomainObjLock(wdEvent->vm);
|
||||
|
||||
if (qemuDomainObjBeginJobWithDriver(driver, wdEvent->vm) < 0)
|
||||
break;
|
||||
|
||||
if (!virDomainObjIsActive(wdEvent->vm)) {
|
||||
qemuReportError(VIR_ERR_OPERATION_INVALID,
|
||||
"%s", _("domain is not running"));
|
||||
break;
|
||||
}
|
||||
|
||||
ret = doCoreDump(driver,
|
||||
wdEvent->vm,
|
||||
dumpfile,
|
||||
getCompressionType(driver));
|
||||
if (ret < 0)
|
||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||
"%s", _("Dump failed"));
|
||||
|
||||
qemuDomainObjEnterMonitorWithDriver(driver, wdEvent->vm);
|
||||
ret = qemuMonitorStartCPUs(priv->mon, NULL);
|
||||
qemuDomainObjExitMonitorWithDriver(driver, wdEvent->vm);
|
||||
|
||||
if (ret < 0)
|
||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||
"%s", _("Resuming after dump failed"));
|
||||
|
||||
if (qemuDomainObjEndJob(wdEvent->vm) > 0)
|
||||
virDomainObjUnlock(wdEvent->vm);
|
||||
|
||||
qemuDriverUnlock(driver);
|
||||
|
||||
VIR_FREE(dumpfile);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
VIR_FREE(wdEvent);
|
||||
}
|
||||
|
||||
static int qemudDomainHotplugVcpus(virDomainObjPtr vm, unsigned int nvcpus)
|
||||
{
|
||||
|
@ -96,6 +96,8 @@ save_image_format = \"gzip\"
|
||||
|
||||
dump_image_format = \"gzip\"
|
||||
|
||||
auto_dump_path = \"/var/lib/libvirt/qemu/dump\"
|
||||
|
||||
hugetlbfs_mount = \"/dev/hugepages\"
|
||||
|
||||
set_process_name = 1
|
||||
@ -213,6 +215,8 @@ allow_disk_format_probing = 1
|
||||
{ "#empty" }
|
||||
{ "dump_image_format" = "gzip" }
|
||||
{ "#empty" }
|
||||
{ "auto_dump_path" = "/var/lib/libvirt/qemu/dump" }
|
||||
{ "#empty" }
|
||||
{ "hugetlbfs_mount" = "/dev/hugepages" }
|
||||
{ "#empty" }
|
||||
{ "set_process_name" = "1" }
|
||||
|
Loading…
x
Reference in New Issue
Block a user