[libvirt] [PATCH 1/2] qemu: add a max_core setting to qemu.conf for core dump size

John Ferlan jferlan at redhat.com
Wed Aug 17 21:04:48 UTC 2016



On 08/03/2016 11:31 AM, Daniel P. Berrange wrote:
> 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                 | 23 ++++++++++++++++++++++-
>  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              | 36 ++++++++++++++++++++++++++++++++++++
>  src/util/virprocess.h              |  1 +
>  11 files changed, 100 insertions(+), 1 deletion(-)
> 
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 419c33d..6dc2b23 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -1389,6 +1389,7 @@ virCommandSetErrorFD;
>  virCommandSetGID;
>  virCommandSetInputBuffer;
>  virCommandSetInputFD;
> +virCommandSetMaxCoreSize;
>  virCommandSetMaxFiles;
>  virCommandSetMaxMemLock;
>  virCommandSetMaxProcesses;
> @@ -2199,6 +2200,7 @@ virProcessRunInMountNamespace;
>  virProcessSchedPolicyTypeFromString;
>  virProcessSchedPolicyTypeToString;
>  virProcessSetAffinity;
> +virProcessSetMaxCoreSize;
>  virProcessSetMaxFiles;
>  virProcessSetMaxMemLock;
>  virProcessSetMaxProcesses;
> diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug
> index 8bc23ba..9ec8250 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 ]
> +

Is there no 'uulong_val'?  At the very least uint?  I don't know much
about this aug stuff, so I defer to you on this.

>  
>     (* 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 7964273..abf9938 100644
> --- a/src/qemu/qemu.conf
> +++ b/src/qemu/qemu.conf
> @@ -401,7 +401,28 @@
>  #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.

Providing a negative value will cause libvirtd startup failure... The
way this is worded could lead one to believe they could provide a signed
value.

> +#
> +# 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 in bytes or string "unlimited"
> +#
> +#max_core = "unlimited"
>  

Would it be overly complicated to alter max_core to be "unlimited" or a
sized value?  I would think it would be easier to type/see "5G" rather
than do the math! or fat-finger or cut-n-paste wrong...

>  # 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 fa9d65e..45d039c 100644
> --- a/src/qemu/qemu_conf.c
> +++ b/src/qemu/qemu_conf.c
> @@ -393,6 +393,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.
> @@ -633,6 +634,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)
> @@ -715,6 +731,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 510cd9a..b730202 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 f9efff9..2270fce 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -5056,6 +5056,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 c4d4f19..a4797af 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 3c67c90..2a59bd1 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;

Should this check if bytes == 0 before setting to true?  If not, then
another change probably would be necessary below... [1]

> +    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 44818ef..99dcdeb 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 09dd3c9..2b71445 100644
> --- a/src/util/virprocess.c
> +++ b/src/util/virprocess.c
> @@ -914,6 +914,42 @@ 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 ATTRIBUTE_UNUSED)
> +{

[1] Similar to other such functions should this have a :

    if (!bytes)
        return 0;

and of course a removed ATTRIBUTE_UNUSED on bytes above...

logic:

maxCore defaults to 0.
qemuProcessLaunch calls virCommandSetMaxCoreSize (setting setMaxCore)

in virExec if setMaxCore is true, then call virProcessSetMaxCoreSize


ACK - in principal - your call on the sized/scaled value, but I do think
this !bytes should be done...

John
> +    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 a7a1fe9..04e9802 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);
>  
> 




More information about the libvir-list mailing list