From fa1ce97917c055adb31d06d300cf8e09ce112d1c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 18 Mar 2015 11:14:55 +0000 Subject: [PATCH] qemu: add a max_core setting to qemu.conf for core dump size Currently the QEMU processes inherit their core dump rlimit from libvirtd, which is really suboptimal. This change allows their limit to be directly controlled from qemu.conf instead. --- src/libvirt_private.syms | 2 ++ src/qemu/libvirtd_qemu.aug | 4 +++ src/qemu/qemu.conf | 24 +++++++++++++++++- src/qemu/qemu_conf.c | 17 +++++++++++++ src/qemu/qemu_conf.h | 1 + src/qemu/qemu_process.c | 1 + src/qemu/test_libvirtd_qemu.aug.in | 1 + src/util/vircommand.c | 14 +++++++++++ src/util/vircommand.h | 1 + src/util/virprocess.c | 39 ++++++++++++++++++++++++++++++ src/util/virprocess.h | 1 + 11 files changed, 104 insertions(+), 1 deletion(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d62c74c39e..a5fa30562f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1392,6 +1392,7 @@ virCommandSetErrorFD; virCommandSetGID; virCommandSetInputBuffer; virCommandSetInputFD; +virCommandSetMaxCoreSize; virCommandSetMaxFiles; virCommandSetMaxMemLock; virCommandSetMaxProcesses; @@ -2203,6 +2204,7 @@ virProcessRunInMountNamespace; virProcessSchedPolicyTypeFromString; virProcessSchedPolicyTypeToString; virProcessSetAffinity; +virProcessSetMaxCoreSize; virProcessSetMaxFiles; virProcessSetMaxMemLock; virProcessSetMaxProcesses; diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug index 8bc23baa66..9ec8250840 100644 --- a/src/qemu/libvirtd_qemu.aug +++ b/src/qemu/libvirtd_qemu.aug @@ -22,6 +22,9 @@ module Libvirtd_qemu = let int_entry (kw:string) = [ key kw . value_sep . int_val ] let str_array_entry (kw:string) = [ key kw . value_sep . str_array_val ] + let unlimited_val = del /\"/ "\"" . store /unlimited/ . del /\"/ "\"" + let limits_entry (kw:string) = [ key kw . value_sep . unlimited_val ] | [ key kw . value_sep . int_val ] + (* Config entry grouped by function - same order as example config *) let vnc_entry = str_entry "vnc_listen" @@ -72,6 +75,7 @@ module Libvirtd_qemu = | bool_entry "set_process_name" | int_entry "max_processes" | int_entry "max_files" + | limits_entry "max_core" | str_entry "stdio_handler" let device_entry = bool_entry "mac_filter" diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index 20bfb745a5..b1ece732c9 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -401,7 +401,29 @@ #max_processes = 0 #max_files = 0 - +# If max_core is set to a non-zero integer, then QEMU will be +# permitted to create core dumps when it crashes, provided its +# RAM size is smaller than the limit set. +# +# Be warned that the core dump will include a full copy of the +# guest RAM, unless it has been disabled via the guest XML by +# setting: +# +# ...guest ram... +# +# If guest RAM is to be included, ensure the max_core limit +# is set to at least the size of the largest expected guest +# plus another 1GB for any QEMU host side memory mappings. +# +# As a special case it can be set to the string "unlimited" to +# to allow arbitrarily sized core dumps. +# +# By default the core dump size is set to 0 disabling all dumps +# +# Size is a positive integer specifying bytes or the +# string "unlimited" +# +#max_core = "unlimited" # mac_filter enables MAC addressed based filtering on bridge ports. # This currently requires ebtables to be installed. diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 7b971f14ff..b3db22c045 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -398,6 +398,7 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, char **controllers = NULL; char **hugetlbfs = NULL; char **nvram = NULL; + char *corestr = NULL; /* Just check the file is readable before opening it, otherwise * libvirt emits an error. @@ -638,6 +639,21 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, if (virConfGetValueUInt(conf, "max_files", &cfg->maxFiles) < 0) goto cleanup; + if (virConfGetValueType(conf, "max_core") == VIR_CONF_STRING) { + if (virConfGetValueString(conf, "max_core", &corestr) < 0) + goto cleanup; + if (STREQ(corestr, "unlimited")) { + cfg->maxCore = ULLONG_MAX; + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unknown core size '%s'"), + corestr); + goto cleanup; + } + } else if (virConfGetValueULLong(conf, "max_core", &cfg->maxCore) < 0) { + goto cleanup; + } + if (virConfGetValueString(conf, "lock_manager", &cfg->lockManagerName) < 0) goto cleanup; if (virConfGetValueString(conf, "stdio_handler", &stdioHandler) < 0) @@ -720,6 +736,7 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, virStringFreeList(controllers); virStringFreeList(hugetlbfs); virStringFreeList(nvram); + VIR_FREE(corestr); VIR_FREE(user); VIR_FREE(group); virConfFree(conf); diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 510cd9a541..b730202c5e 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -148,6 +148,7 @@ struct _virQEMUDriverConfig { unsigned int maxProcesses; unsigned int maxFiles; + unsigned long long maxCore; unsigned int maxQueuedJobs; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index b10b05359d..ec6b547c85 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5269,6 +5269,7 @@ qemuProcessLaunch(virConnectPtr conn, virCommandSetPreExecHook(cmd, qemuProcessHook, &hookData); virCommandSetMaxProcesses(cmd, cfg->maxProcesses); virCommandSetMaxFiles(cmd, cfg->maxFiles); + virCommandSetMaxCoreSize(cmd, cfg->maxCore); virCommandSetUmask(cmd, 0x002); VIR_DEBUG("Setting up security labelling"); diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in index 99bf90f26d..1d3c0b73a6 100644 --- a/src/qemu/test_libvirtd_qemu.aug.in +++ b/src/qemu/test_libvirtd_qemu.aug.in @@ -62,6 +62,7 @@ module Test_libvirtd_qemu = { "set_process_name" = "1" } { "max_processes" = "0" } { "max_files" = "0" } +{ "max_core" = "unlimited" } { "mac_filter" = "1" } { "relaxed_acs_check" = "1" } { "allow_disk_format_probing" = "1" } diff --git a/src/util/vircommand.c b/src/util/vircommand.c index 3c67c907aa..2a59bd1a41 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -124,6 +124,8 @@ struct _virCommand { unsigned long long maxMemLock; unsigned int maxProcesses; unsigned int maxFiles; + bool setMaxCore; + unsigned long long maxCore; uid_t uid; gid_t gid; @@ -687,6 +689,9 @@ virExec(virCommandPtr cmd) goto fork_error; if (virProcessSetMaxFiles(0, cmd->maxFiles) < 0) goto fork_error; + if (cmd->setMaxCore && + virProcessSetMaxCoreSize(0, cmd->maxCore) < 0) + goto fork_error; if (cmd->hook) { VIR_DEBUG("Run hook %p %p", cmd->hook, cmd->opaque); @@ -1105,6 +1110,15 @@ virCommandSetMaxFiles(virCommandPtr cmd, unsigned int files) cmd->maxFiles = files; } +void virCommandSetMaxCoreSize(virCommandPtr cmd, unsigned long long bytes) +{ + if (!cmd || cmd->has_error) + return; + + cmd->maxCore = bytes; + cmd->setMaxCore = true; +} + void virCommandSetUmask(virCommandPtr cmd, int mask) { if (!cmd || cmd->has_error) diff --git a/src/util/vircommand.h b/src/util/vircommand.h index 44818efe2a..99dcdeb541 100644 --- a/src/util/vircommand.h +++ b/src/util/vircommand.h @@ -75,6 +75,7 @@ void virCommandSetUID(virCommandPtr cmd, uid_t uid); void virCommandSetMaxMemLock(virCommandPtr cmd, unsigned long long bytes); void virCommandSetMaxProcesses(virCommandPtr cmd, unsigned int procs); void virCommandSetMaxFiles(virCommandPtr cmd, unsigned int files); +void virCommandSetMaxCoreSize(virCommandPtr cmd, unsigned long long bytes); void virCommandSetUmask(virCommandPtr cmd, int umask); void virCommandClearCaps(virCommandPtr cmd); diff --git a/src/util/virprocess.c b/src/util/virprocess.c index 09dd3c90f4..8b9f9c5d60 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -914,6 +914,45 @@ virProcessSetMaxFiles(pid_t pid ATTRIBUTE_UNUSED, unsigned int files) } #endif /* ! (HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)) */ +#if HAVE_SETRLIMIT && defined(RLIMIT_CORE) +int +virProcessSetMaxCoreSize(pid_t pid, unsigned long long bytes) +{ + struct rlimit rlim; + + rlim.rlim_cur = rlim.rlim_max = bytes; + if (pid == 0) { + if (setrlimit(RLIMIT_CORE, &rlim) < 0) { + virReportSystemError(errno, + _("cannot limit core file size to %llu"), + bytes); + return -1; + } + } else { + if (virProcessPrLimit(pid, RLIMIT_CORE, &rlim, NULL) < 0) { + virReportSystemError(errno, + _("cannot limit core file size " + "of process %lld to %llu"), + (long long int)pid, bytes); + return -1; + } + } + return 0; +} +#else /* ! (HAVE_SETRLIMIT && defined(RLIMIT_CORE)) */ +int +virProcessSetMaxCoreSize(pid_t pid ATTRIBUTE_UNUSED, + unsigned long long bytes) +{ + if (bytes == 0) + return 0; + + virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); + return -1; +} +#endif /* ! (HAVE_SETRLIMIT && defined(RLIMIT_CORE)) */ + + #ifdef __linux__ /* * Port of code from polkitunixprocess.c under terms diff --git a/src/util/virprocess.h b/src/util/virprocess.h index a7a1fe9200..04e9802aa6 100644 --- a/src/util/virprocess.h +++ b/src/util/virprocess.h @@ -75,6 +75,7 @@ int virProcessSetNamespaces(size_t nfdlist, int virProcessSetMaxMemLock(pid_t pid, unsigned long long bytes); int virProcessSetMaxProcesses(pid_t pid, unsigned int procs); int virProcessSetMaxFiles(pid_t pid, unsigned int files); +int virProcessSetMaxCoreSize(pid_t pid, unsigned long long bytes); int virProcessGetMaxMemLock(pid_t pid, unsigned long long *bytes);