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.
This commit is contained in:
Daniel P. Berrange 2015-03-18 11:14:55 +00:00
parent 3de7da9448
commit fa1ce97917
11 changed files with 104 additions and 1 deletions

View File

@ -1392,6 +1392,7 @@ virCommandSetErrorFD;
virCommandSetGID; virCommandSetGID;
virCommandSetInputBuffer; virCommandSetInputBuffer;
virCommandSetInputFD; virCommandSetInputFD;
virCommandSetMaxCoreSize;
virCommandSetMaxFiles; virCommandSetMaxFiles;
virCommandSetMaxMemLock; virCommandSetMaxMemLock;
virCommandSetMaxProcesses; virCommandSetMaxProcesses;
@ -2203,6 +2204,7 @@ virProcessRunInMountNamespace;
virProcessSchedPolicyTypeFromString; virProcessSchedPolicyTypeFromString;
virProcessSchedPolicyTypeToString; virProcessSchedPolicyTypeToString;
virProcessSetAffinity; virProcessSetAffinity;
virProcessSetMaxCoreSize;
virProcessSetMaxFiles; virProcessSetMaxFiles;
virProcessSetMaxMemLock; virProcessSetMaxMemLock;
virProcessSetMaxProcesses; virProcessSetMaxProcesses;

View File

@ -22,6 +22,9 @@ module Libvirtd_qemu =
let int_entry (kw:string) = [ key kw . value_sep . int_val ] 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 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 *) (* Config entry grouped by function - same order as example config *)
let vnc_entry = str_entry "vnc_listen" let vnc_entry = str_entry "vnc_listen"
@ -72,6 +75,7 @@ module Libvirtd_qemu =
| bool_entry "set_process_name" | bool_entry "set_process_name"
| int_entry "max_processes" | int_entry "max_processes"
| int_entry "max_files" | int_entry "max_files"
| limits_entry "max_core"
| str_entry "stdio_handler" | str_entry "stdio_handler"
let device_entry = bool_entry "mac_filter" let device_entry = bool_entry "mac_filter"

View File

@ -401,7 +401,29 @@
#max_processes = 0 #max_processes = 0
#max_files = 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:
#
# <memory dumpcore="off">...guest ram...</memory>
#
# 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. # mac_filter enables MAC addressed based filtering on bridge ports.
# This currently requires ebtables to be installed. # This currently requires ebtables to be installed.

View File

@ -398,6 +398,7 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
char **controllers = NULL; char **controllers = NULL;
char **hugetlbfs = NULL; char **hugetlbfs = NULL;
char **nvram = NULL; char **nvram = NULL;
char *corestr = NULL;
/* Just check the file is readable before opening it, otherwise /* Just check the file is readable before opening it, otherwise
* libvirt emits an error. * libvirt emits an error.
@ -638,6 +639,21 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
if (virConfGetValueUInt(conf, "max_files", &cfg->maxFiles) < 0) if (virConfGetValueUInt(conf, "max_files", &cfg->maxFiles) < 0)
goto cleanup; 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) if (virConfGetValueString(conf, "lock_manager", &cfg->lockManagerName) < 0)
goto cleanup; goto cleanup;
if (virConfGetValueString(conf, "stdio_handler", &stdioHandler) < 0) if (virConfGetValueString(conf, "stdio_handler", &stdioHandler) < 0)
@ -720,6 +736,7 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
virStringFreeList(controllers); virStringFreeList(controllers);
virStringFreeList(hugetlbfs); virStringFreeList(hugetlbfs);
virStringFreeList(nvram); virStringFreeList(nvram);
VIR_FREE(corestr);
VIR_FREE(user); VIR_FREE(user);
VIR_FREE(group); VIR_FREE(group);
virConfFree(conf); virConfFree(conf);

View File

@ -148,6 +148,7 @@ struct _virQEMUDriverConfig {
unsigned int maxProcesses; unsigned int maxProcesses;
unsigned int maxFiles; unsigned int maxFiles;
unsigned long long maxCore;
unsigned int maxQueuedJobs; unsigned int maxQueuedJobs;

View File

@ -5269,6 +5269,7 @@ qemuProcessLaunch(virConnectPtr conn,
virCommandSetPreExecHook(cmd, qemuProcessHook, &hookData); virCommandSetPreExecHook(cmd, qemuProcessHook, &hookData);
virCommandSetMaxProcesses(cmd, cfg->maxProcesses); virCommandSetMaxProcesses(cmd, cfg->maxProcesses);
virCommandSetMaxFiles(cmd, cfg->maxFiles); virCommandSetMaxFiles(cmd, cfg->maxFiles);
virCommandSetMaxCoreSize(cmd, cfg->maxCore);
virCommandSetUmask(cmd, 0x002); virCommandSetUmask(cmd, 0x002);
VIR_DEBUG("Setting up security labelling"); VIR_DEBUG("Setting up security labelling");

View File

@ -62,6 +62,7 @@ module Test_libvirtd_qemu =
{ "set_process_name" = "1" } { "set_process_name" = "1" }
{ "max_processes" = "0" } { "max_processes" = "0" }
{ "max_files" = "0" } { "max_files" = "0" }
{ "max_core" = "unlimited" }
{ "mac_filter" = "1" } { "mac_filter" = "1" }
{ "relaxed_acs_check" = "1" } { "relaxed_acs_check" = "1" }
{ "allow_disk_format_probing" = "1" } { "allow_disk_format_probing" = "1" }

View File

@ -124,6 +124,8 @@ struct _virCommand {
unsigned long long maxMemLock; unsigned long long maxMemLock;
unsigned int maxProcesses; unsigned int maxProcesses;
unsigned int maxFiles; unsigned int maxFiles;
bool setMaxCore;
unsigned long long maxCore;
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
@ -687,6 +689,9 @@ virExec(virCommandPtr cmd)
goto fork_error; goto fork_error;
if (virProcessSetMaxFiles(0, cmd->maxFiles) < 0) if (virProcessSetMaxFiles(0, cmd->maxFiles) < 0)
goto fork_error; goto fork_error;
if (cmd->setMaxCore &&
virProcessSetMaxCoreSize(0, cmd->maxCore) < 0)
goto fork_error;
if (cmd->hook) { if (cmd->hook) {
VIR_DEBUG("Run hook %p %p", cmd->hook, cmd->opaque); VIR_DEBUG("Run hook %p %p", cmd->hook, cmd->opaque);
@ -1105,6 +1110,15 @@ virCommandSetMaxFiles(virCommandPtr cmd, unsigned int files)
cmd->maxFiles = 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) void virCommandSetUmask(virCommandPtr cmd, int mask)
{ {
if (!cmd || cmd->has_error) if (!cmd || cmd->has_error)

View File

@ -75,6 +75,7 @@ void virCommandSetUID(virCommandPtr cmd, uid_t uid);
void virCommandSetMaxMemLock(virCommandPtr cmd, unsigned long long bytes); void virCommandSetMaxMemLock(virCommandPtr cmd, unsigned long long bytes);
void virCommandSetMaxProcesses(virCommandPtr cmd, unsigned int procs); void virCommandSetMaxProcesses(virCommandPtr cmd, unsigned int procs);
void virCommandSetMaxFiles(virCommandPtr cmd, unsigned int files); void virCommandSetMaxFiles(virCommandPtr cmd, unsigned int files);
void virCommandSetMaxCoreSize(virCommandPtr cmd, unsigned long long bytes);
void virCommandSetUmask(virCommandPtr cmd, int umask); void virCommandSetUmask(virCommandPtr cmd, int umask);
void virCommandClearCaps(virCommandPtr cmd); void virCommandClearCaps(virCommandPtr cmd);

View File

@ -914,6 +914,45 @@ virProcessSetMaxFiles(pid_t pid ATTRIBUTE_UNUSED, unsigned int files)
} }
#endif /* ! (HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)) */ #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__ #ifdef __linux__
/* /*
* Port of code from polkitunixprocess.c under terms * Port of code from polkitunixprocess.c under terms

View File

@ -75,6 +75,7 @@ int virProcessSetNamespaces(size_t nfdlist,
int virProcessSetMaxMemLock(pid_t pid, unsigned long long bytes); int virProcessSetMaxMemLock(pid_t pid, unsigned long long bytes);
int virProcessSetMaxProcesses(pid_t pid, unsigned int procs); int virProcessSetMaxProcesses(pid_t pid, unsigned int procs);
int virProcessSetMaxFiles(pid_t pid, unsigned int files); 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); int virProcessGetMaxMemLock(pid_t pid, unsigned long long *bytes);