Currently the QEMU processes inherit their core dump rlimit from libvirtd, which is really suboptimal. This change allows their limit to be directly controller from qemu.conf instead. --- src/libvirt_private.syms | 2 ++ src/qemu/libvirtd_qemu.aug | 1 + src/qemu/qemu.conf | 12 ++++++++++++ src/qemu/qemu_conf.c | 3 +++ src/qemu/qemu_conf.h | 2 ++ src/qemu/qemu_process.c | 2 ++ src/qemu/test_libvirtd_qemu.aug.in | 1 + src/util/vircommand.c | 14 ++++++++++++++ src/util/vircommand.h | 1 + src/util/virprocess.c | 35 +++++++++++++++++++++++++++++++++++ src/util/virprocess.h | 1 + 11 files changed, 74 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ca3520d..7446357 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1240,6 +1240,7 @@ virCommandSetErrorFD; virCommandSetGID; virCommandSetInputBuffer; virCommandSetInputFD; +virCommandSetMaxCoreSize; virCommandSetMaxFiles; virCommandSetMaxMemLock; virCommandSetMaxProcesses; @@ -1951,6 +1952,7 @@ virProcessRunInMountNamespace; virProcessSchedPolicyTypeFromString; virProcessSchedPolicyTypeToString; virProcessSetAffinity; +virProcessSetMaxCoreSize; virProcessSetMaxFiles; virProcessSetMaxMemLock; virProcessSetMaxProcesses; diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug index 62951da..029a55a 100644 --- a/src/qemu/libvirtd_qemu.aug +++ b/src/qemu/libvirtd_qemu.aug @@ -71,6 +71,7 @@ module Libvirtd_qemu = | bool_entry "set_process_name" | int_entry "max_processes" | int_entry "max_files" + | int_entry "max_core" let device_entry = bool_entry "mac_filter" | bool_entry "relaxed_acs_check" diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index 1c589a2..12e4326 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -390,6 +390,18 @@ #max_processes = 0 #max_files = 0 +# If max_core is set to a positive 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, so if +# the largest guest is 32 GB in size, the max_core limit will +# have to be at least 33/34 GB to allow enough overhead. +# +# By default it will inherit core limit from libvirtd, which +# is usually set to 0 by systemd/init. +# +# Size is in bytes +#max_core = 0 # mac_filter enables MAC addressed based filtering on bridge ports. diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index bca05c9..97bb8b8 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -770,6 +770,9 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, GET_VALUE_BOOL("set_process_name", cfg->setProcessName); GET_VALUE_ULONG("max_processes", cfg->maxProcesses); GET_VALUE_ULONG("max_files", cfg->maxFiles); + GET_VALUE_ULONG("max_core", cfg->maxCore); + if (virConfGetValue(conf, "max_core")) + cfg->setMaxCore = true; GET_VALUE_STR("lock_manager", cfg->lockManagerName); diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index cb01fb6..ac7a1bf 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -143,6 +143,8 @@ struct _virQEMUDriverConfig { int maxProcesses; int maxFiles; + bool setMaxCore; + unsigned long long maxCore; int maxQueuedJobs; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 37cdb8f..995d6ef 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4731,6 +4731,8 @@ int qemuProcessStart(virConnectPtr conn, virCommandSetPreExecHook(cmd, qemuProcessHook, &hookData); virCommandSetMaxProcesses(cmd, cfg->maxProcesses); virCommandSetMaxFiles(cmd, cfg->maxFiles); + if (cfg->setMaxCore) + 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 fc4935b..9bb3683 100644 --- a/src/qemu/test_libvirtd_qemu.aug.in +++ b/src/qemu/test_libvirtd_qemu.aug.in @@ -61,6 +61,7 @@ module Test_libvirtd_qemu = { "set_process_name" = "1" } { "max_processes" = "0" } { "max_files" = "0" } +{ "max_core" = "0" } { "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 648f5ed..1982401 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -123,6 +123,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; @@ -686,6 +688,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); @@ -1108,6 +1113,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 198da2f..4f2874d 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 aa00a99..02d91d9 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -825,6 +825,41 @@ 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) < 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) +{ + 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 c812882..cd7b7a2 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); /* Callback to run code within the mount namespace tied to the given * pid. This function must use only async-signal-safe functions, as -- 2.1.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list