/* * vircgroupv2.c: methods for cgroups v2 backend * * Copyright (C) 2018 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #include #ifdef __linux__ # include #endif /* __linux__ */ #include "internal.h" #define __VIR_CGROUP_ALLOW_INCLUDE_PRIV_H__ #include "vircgrouppriv.h" #undef __VIR_CGROUP_ALLOW_INCLUDE_PRIV_H__ #include "vircgroup.h" #include "vircgroupbackend.h" #include "vircgroupv2.h" #include "virfile.h" #include "virlog.h" #include "virstring.h" #include "virsystemd.h" VIR_LOG_INIT("util.cgroup"); #define VIR_FROM_THIS VIR_FROM_CGROUP VIR_ENUM_DECL(virCgroupV2Controller); VIR_ENUM_IMPL(virCgroupV2Controller, VIR_CGROUP_CONTROLLER_LAST, "cpu", "cpuacct", "cpuset", "memory", "devices", "freezer", "io", "net_cls", "perf_event", "name=systemd"); #ifdef __linux__ /* We're looking for one 'cgroup2' fs mount which has some * controllers enabled. */ static bool virCgroupV2Available(void) { bool ret = false; FILE *mounts = NULL; struct mntent entry; char buf[CGROUP_MAX_VAL]; if (!(mounts = fopen("/proc/mounts", "r"))) return false; while (getmntent_r(mounts, &entry, buf, sizeof(buf)) != NULL) { VIR_AUTOFREE(char *) contFile = NULL; VIR_AUTOFREE(char *) contStr = NULL; if (STRNEQ(entry.mnt_type, "cgroup2")) continue; /* Systemd uses cgroup v2 for process tracking but no controller is * available. We should consider this configuration as cgroup v2 is * not available. */ if (virAsprintf(&contFile, "%s/cgroup.controllers", entry.mnt_dir) < 0) goto cleanup; if (virFileReadAll(contFile, 1024 * 1024, &contStr) < 0) goto cleanup; if (STREQ(contStr, "")) continue; ret = true; break; } cleanup: VIR_FORCE_FCLOSE(mounts); return ret; } static bool virCgroupV2ValidateMachineGroup(virCgroupPtr group, const char *name ATTRIBUTE_UNUSED, const char *drivername, const char *machinename) { VIR_AUTOFREE(char *) partmachinename = NULL; VIR_AUTOFREE(char *) scopename = NULL; char *tmp; if (virAsprintf(&partmachinename, "%s.libvirt-%s", machinename, drivername) < 0) { return false; } if (virCgroupPartitionEscape(&partmachinename) < 0) return false; if (!(scopename = virSystemdMakeScopeName(machinename, drivername, false))) { return false; } if (virCgroupPartitionEscape(&scopename) < 0) return false; if (!(tmp = strrchr(group->unified.placement, '/'))) return false; tmp++; if (STRNEQ(tmp, partmachinename) && STRNEQ(tmp, scopename)) { VIR_DEBUG("Name '%s' for unified does not match '%s' or '%s'", tmp, partmachinename, scopename); return false; } return true; } virCgroupBackend virCgroupV2Backend = { .type = VIR_CGROUP_BACKEND_TYPE_V2, .available = virCgroupV2Available, .validateMachineGroup = virCgroupV2ValidateMachineGroup, }; void virCgroupV2Register(void) { virCgroupBackendRegister(&virCgroupV2Backend); } #else /* !__linux__ */ void virCgroupV2Register(void) { VIR_INFO("Control groups not supported on this platform"); } #endif /* !__linux__ */