2008-10-03 17:58:02 +00:00
|
|
|
/*
|
2012-12-03 15:03:47 +00:00
|
|
|
* vircgroup.c: methods for managing control cgroups
|
2008-10-03 17:58:02 +00:00
|
|
|
*
|
2015-03-11 10:15:29 +00:00
|
|
|
* Copyright (C) 2010-2015 Red Hat, Inc.
|
2008-10-03 17:58:02 +00:00
|
|
|
* Copyright IBM Corp. 2008
|
|
|
|
*
|
2012-07-27 09:39:53 +00:00
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-27 09:39:53 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2008-10-03 17:58:02 +00:00
|
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
|
2018-09-27 10:19:17 +00:00
|
|
|
#ifdef __linux__
|
2010-03-09 18:22:22 +00:00
|
|
|
# include <mntent.h>
|
2013-04-05 11:48:47 +00:00
|
|
|
# include <sys/mount.h>
|
2018-09-27 10:19:17 +00:00
|
|
|
# include <fcntl.h>
|
|
|
|
# include <sys/stat.h>
|
2020-01-24 17:32:48 +00:00
|
|
|
# include <sys/sysmacros.h>
|
2018-09-27 10:19:17 +00:00
|
|
|
# include <sys/types.h>
|
|
|
|
# include <signal.h>
|
|
|
|
# include <dirent.h>
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif /* __linux__ */
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2018-12-13 14:53:50 +00:00
|
|
|
#define LIBVIRT_VIRCGROUPPRIV_H_ALLOW
|
2013-03-28 14:32:23 +00:00
|
|
|
#include "vircgrouppriv.h"
|
|
|
|
|
2012-12-13 17:44:57 +00:00
|
|
|
#include "virutil.h"
|
2018-07-30 09:04:26 +00:00
|
|
|
#include "viralloc.h"
|
2018-09-13 14:27:56 +00:00
|
|
|
#include "vircgroupbackend.h"
|
2013-04-05 11:48:47 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2012-01-25 16:13:59 +00:00
|
|
|
#include "virhash.h"
|
2013-04-26 09:23:51 +00:00
|
|
|
#include "virstring.h"
|
2013-07-22 15:34:51 +00:00
|
|
|
#include "virsystemd.h"
|
2014-02-14 17:49:01 +00:00
|
|
|
#include "virtypedparam.h"
|
2016-04-13 17:53:02 +00:00
|
|
|
#include "virhostcpu.h"
|
2016-12-06 12:03:29 +00:00
|
|
|
#include "virthread.h"
|
2014-02-14 17:49:02 +00:00
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("util.cgroup");
|
|
|
|
|
2013-04-05 11:48:47 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_CGROUP
|
|
|
|
|
2014-02-14 17:49:01 +00:00
|
|
|
#define CGROUP_NB_TOTAL_CPU_STAT_PARAM 3
|
2014-02-14 17:49:02 +00:00
|
|
|
#define CGROUP_NB_PER_CPU_STAT_PARAM 1
|
2014-02-14 17:49:01 +00:00
|
|
|
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_ENUM_IMPL(virCgroupController,
|
|
|
|
VIR_CGROUP_CONTROLLER_LAST,
|
2009-09-21 14:31:22 +00:00
|
|
|
"cpu", "cpuacct", "cpuset", "memory", "devices",
|
2013-07-25 18:13:44 +00:00
|
|
|
"freezer", "blkio", "net_cls", "perf_event",
|
2019-01-20 16:30:15 +00:00
|
|
|
"name=systemd",
|
|
|
|
);
|
2009-07-09 13:10:41 +00:00
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2014-07-08 15:34:56 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetDevicePermsString:
|
|
|
|
*
|
|
|
|
* @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits
|
|
|
|
*
|
|
|
|
* Returns string corresponding to the appropriate bits set.
|
|
|
|
*/
|
|
|
|
const char *
|
|
|
|
virCgroupGetDevicePermsString(int perms)
|
|
|
|
{
|
|
|
|
if (perms & VIR_CGROUP_DEVICE_READ) {
|
|
|
|
if (perms & VIR_CGROUP_DEVICE_WRITE) {
|
|
|
|
if (perms & VIR_CGROUP_DEVICE_MKNOD)
|
|
|
|
return "rwm";
|
|
|
|
else
|
|
|
|
return "rw";
|
|
|
|
} else {
|
|
|
|
if (perms & VIR_CGROUP_DEVICE_MKNOD)
|
|
|
|
return "rm";
|
|
|
|
else
|
|
|
|
return "r";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (perms & VIR_CGROUP_DEVICE_WRITE) {
|
|
|
|
if (perms & VIR_CGROUP_DEVICE_MKNOD)
|
|
|
|
return "wm";
|
|
|
|
else
|
|
|
|
return "w";
|
|
|
|
} else {
|
|
|
|
if (perms & VIR_CGROUP_DEVICE_MKNOD)
|
|
|
|
return "m";
|
|
|
|
else
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-27 10:16:57 +00:00
|
|
|
#ifdef __linux__
|
2013-08-12 19:52:06 +00:00
|
|
|
bool
|
|
|
|
virCgroupAvailable(void)
|
2013-07-04 15:49:24 +00:00
|
|
|
{
|
2018-09-13 14:27:56 +00:00
|
|
|
size_t i;
|
|
|
|
virCgroupBackendPtr *backends = virCgroupBackendGetAll();
|
2013-07-04 15:49:24 +00:00
|
|
|
|
2018-09-13 14:27:56 +00:00
|
|
|
if (!backends)
|
2013-07-04 15:49:24 +00:00
|
|
|
return false;
|
|
|
|
|
2018-09-13 14:27:56 +00:00
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (backends[i] && backends[i]->available())
|
|
|
|
return true;
|
2013-07-04 15:49:24 +00:00
|
|
|
}
|
|
|
|
|
2018-09-13 14:27:56 +00:00
|
|
|
return false;
|
2013-07-04 15:49:24 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 21:01:30 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
virCgroupPartitionNeedsEscaping(const char *path)
|
|
|
|
{
|
|
|
|
FILE *fp = NULL;
|
|
|
|
int ret = 0;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *line = NULL;
|
2013-08-12 21:01:30 +00:00
|
|
|
size_t buflen;
|
|
|
|
|
|
|
|
/* If it starts with 'cgroup.' or a '_' of any
|
|
|
|
* of the controller names from /proc/cgroups,
|
|
|
|
* then we must prefix a '_'
|
|
|
|
*/
|
|
|
|
if (STRPREFIX(path, "cgroup."))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (path[0] == '_' ||
|
|
|
|
path[0] == '.')
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (!(fp = fopen("/proc/cgroups", "r"))) {
|
|
|
|
/* The API contract is that we return ENXIO
|
|
|
|
* if cgroups are not available on a host */
|
|
|
|
if (errno == ENOENT)
|
|
|
|
errno = ENXIO;
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Cannot open /proc/cgroups"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Data looks like this:
|
|
|
|
* #subsys_name hierarchy num_cgroups enabled
|
|
|
|
* cpuset 2 4 1
|
|
|
|
* cpu 3 48 1
|
|
|
|
* cpuacct 3 48 1
|
|
|
|
* memory 4 4 1
|
|
|
|
* devices 5 4 1
|
|
|
|
* freezer 6 4 1
|
|
|
|
* net_cls 7 1 1
|
|
|
|
*/
|
|
|
|
while (getline(&line, &buflen, fp) > 0) {
|
|
|
|
char *tmp;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (STRPREFIX(line, "#subsys_name"))
|
|
|
|
continue;
|
|
|
|
|
2020-01-14 10:43:37 +00:00
|
|
|
tmp = strchr(line, ' ');
|
|
|
|
if (tmp) {
|
|
|
|
*tmp = '\0';
|
|
|
|
len = tmp - line;
|
|
|
|
} else {
|
|
|
|
len = strlen(line);
|
|
|
|
}
|
2013-08-12 21:01:30 +00:00
|
|
|
|
|
|
|
if (STRPREFIX(path, line) &&
|
|
|
|
path[len] == '.') {
|
|
|
|
ret = 1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ferror(fp)) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Error while reading /proc/cgroups"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2013-08-12 21:01:30 +00:00
|
|
|
VIR_FORCE_FCLOSE(fp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-14 11:21:19 +00:00
|
|
|
int
|
2013-08-12 21:01:30 +00:00
|
|
|
virCgroupPartitionEscape(char **path)
|
|
|
|
{
|
|
|
|
int rc;
|
2016-06-14 06:02:30 +00:00
|
|
|
char *newstr = NULL;
|
2013-08-12 21:01:30 +00:00
|
|
|
|
|
|
|
if ((rc = virCgroupPartitionNeedsEscaping(*path)) <= 0)
|
|
|
|
return rc;
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
newstr = g_strdup_printf("_%s", *path);
|
2013-08-12 21:01:30 +00:00
|
|
|
|
2016-06-14 06:02:30 +00:00
|
|
|
VIR_FREE(*path);
|
|
|
|
*path = newstr;
|
|
|
|
|
2013-08-12 21:01:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-07-29 14:55:05 +00:00
|
|
|
|
|
|
|
|
2020-10-14 09:08:21 +00:00
|
|
|
static int
|
|
|
|
virCgroupSetBackends(virCgroupPtr group)
|
|
|
|
{
|
|
|
|
virCgroupBackendPtr *backends = virCgroupBackendGetAll();
|
|
|
|
bool backendAvailable = false;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!backends)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (backends[i] && backends[i]->available()) {
|
|
|
|
group->backends[i] = backends[i];
|
|
|
|
backendAvailable = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!backendAvailable) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("no cgroup backend available"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-14 09:12:46 +00:00
|
|
|
static int
|
|
|
|
virCgroupCopyMounts(virCgroupPtr group,
|
|
|
|
virCgroupPtr parent)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (group->backends[i] &&
|
|
|
|
group->backends[i]->copyMounts(group, parent) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-09 13:10:41 +00:00
|
|
|
/*
|
|
|
|
* Process /proc/mounts figuring out what controllers are
|
|
|
|
* mounted and where
|
|
|
|
*/
|
2018-09-14 11:17:07 +00:00
|
|
|
static int
|
2018-09-14 10:38:54 +00:00
|
|
|
virCgroupDetectMounts(virCgroupPtr group)
|
2008-10-03 17:58:02 +00:00
|
|
|
{
|
2009-03-16 10:41:37 +00:00
|
|
|
FILE *mounts = NULL;
|
2008-10-03 17:58:02 +00:00
|
|
|
struct mntent entry;
|
|
|
|
char buf[CGROUP_MAX_VAL];
|
2017-07-11 08:46:52 +00:00
|
|
|
int ret = -1;
|
2018-09-28 17:53:05 +00:00
|
|
|
size_t i;
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2018-09-14 10:38:54 +00:00
|
|
|
mounts = fopen("/proc/mounts", "r");
|
2008-10-03 17:58:02 +00:00
|
|
|
if (mounts == NULL) {
|
2018-09-14 10:38:54 +00:00
|
|
|
virReportSystemError(errno, "%s", _("Unable to open /proc/mounts"));
|
2013-07-04 15:49:24 +00:00
|
|
|
return -1;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
while (getmntent_r(mounts, &entry, buf, sizeof(buf)) != NULL) {
|
2018-09-28 17:53:05 +00:00
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (group->backends[i] &&
|
|
|
|
group->backends[i]->detectMounts(group,
|
|
|
|
entry.mnt_type,
|
|
|
|
entry.mnt_opts,
|
|
|
|
entry.mnt_dir) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-07-09 13:10:41 +00:00
|
|
|
}
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2017-07-11 08:46:52 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
2010-11-17 02:13:29 +00:00
|
|
|
VIR_FORCE_FCLOSE(mounts);
|
2017-07-11 08:46:52 +00:00
|
|
|
return ret;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2009-07-09 13:10:41 +00:00
|
|
|
|
2020-10-14 09:14:34 +00:00
|
|
|
static int
|
|
|
|
virCgroupCopyPlacement(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
virCgroupPtr parent)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (group->backends[i] &&
|
|
|
|
group->backends[i]->copyPlacement(group, path, parent) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-09 13:10:41 +00:00
|
|
|
/*
|
2013-03-22 11:11:34 +00:00
|
|
|
* virCgroupDetectPlacement:
|
|
|
|
* @group: the group to process
|
|
|
|
* @path: the relative path to append, not starting with '/'
|
|
|
|
*
|
2009-07-09 13:10:41 +00:00
|
|
|
* Process /proc/self/cgroup figuring out what cgroup
|
|
|
|
* sub-path the current process is assigned to. ie not
|
2013-03-22 11:11:34 +00:00
|
|
|
* necessarily in the root. The contents of this file
|
|
|
|
* looks like
|
|
|
|
*
|
|
|
|
* 9:perf_event:/
|
|
|
|
* 8:blkio:/
|
|
|
|
* 7:net_cls:/
|
|
|
|
* 6:freezer:/
|
|
|
|
* 5:devices:/
|
|
|
|
* 4:memory:/
|
|
|
|
* 3:cpuacct,cpu:/
|
|
|
|
* 2:cpuset:/
|
|
|
|
* 1:name=systemd:/user/berrange/2
|
|
|
|
*
|
|
|
|
* It then appends @path to each detected path.
|
2008-10-03 17:58:02 +00:00
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
static int
|
|
|
|
virCgroupDetectPlacement(virCgroupPtr group,
|
|
|
|
pid_t pid,
|
|
|
|
const char *path)
|
2008-10-03 17:58:02 +00:00
|
|
|
{
|
2009-07-09 13:10:41 +00:00
|
|
|
FILE *mapping = NULL;
|
|
|
|
char line[1024];
|
2013-07-04 15:49:24 +00:00
|
|
|
int ret = -1;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *procfile = NULL;
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2013-07-25 18:13:44 +00:00
|
|
|
VIR_DEBUG("Detecting placement for pid %lld path %s",
|
2016-10-06 14:54:41 +00:00
|
|
|
(long long) pid, path);
|
2013-07-19 10:13:05 +00:00
|
|
|
if (pid == -1) {
|
2019-10-20 11:49:46 +00:00
|
|
|
procfile = g_strdup("/proc/self/cgroup");
|
2013-07-19 10:13:05 +00:00
|
|
|
} else {
|
2019-10-22 13:26:14 +00:00
|
|
|
procfile = g_strdup_printf("/proc/%lld/cgroup", (long long)pid);
|
2013-07-19 10:13:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mapping = fopen(procfile, "r");
|
2009-07-09 13:10:41 +00:00
|
|
|
if (mapping == NULL) {
|
2013-07-19 10:13:05 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to open '%s'"),
|
|
|
|
procfile);
|
|
|
|
goto cleanup;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2009-07-09 13:10:41 +00:00
|
|
|
while (fgets(line, sizeof(line), mapping) != NULL) {
|
2018-09-28 17:53:05 +00:00
|
|
|
size_t i;
|
2009-07-09 13:10:41 +00:00
|
|
|
char *controllers = strchr(line, ':');
|
2013-03-22 11:11:34 +00:00
|
|
|
char *selfpath = controllers ? strchr(controllers + 1, ':') : NULL;
|
|
|
|
char *nl = selfpath ? strchr(selfpath, '\n') : NULL;
|
2009-07-09 13:10:41 +00:00
|
|
|
|
2013-03-22 11:11:34 +00:00
|
|
|
if (!controllers || !selfpath)
|
2009-07-09 13:10:41 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (nl)
|
|
|
|
*nl = '\0';
|
|
|
|
|
2013-03-22 11:11:34 +00:00
|
|
|
*selfpath = '\0';
|
2009-07-09 13:10:41 +00:00
|
|
|
controllers++;
|
2013-03-22 11:11:34 +00:00
|
|
|
selfpath++;
|
2009-07-09 13:10:41 +00:00
|
|
|
|
2018-09-28 17:53:05 +00:00
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (group->backends[i] &&
|
|
|
|
group->backends[i]->detectPlacement(group, path, controllers,
|
|
|
|
selfpath) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-07-09 13:10:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-04 15:49:24 +00:00
|
|
|
ret = 0;
|
2009-07-09 13:10:41 +00:00
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2010-11-17 02:13:29 +00:00
|
|
|
VIR_FORCE_FCLOSE(mapping);
|
2013-07-04 15:49:24 +00:00
|
|
|
return ret;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2020-10-21 12:35:48 +00:00
|
|
|
static int
|
|
|
|
virCgroupSetPlacement(virCgroupPtr group,
|
|
|
|
const char *path)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (group->backends[i] &&
|
|
|
|
group->backends[i]->setPlacement(group, path) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-14 09:15:53 +00:00
|
|
|
static int
|
|
|
|
virCgroupValidatePlacement(virCgroupPtr group,
|
|
|
|
pid_t pid)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (group->backends[i] &&
|
|
|
|
group->backends[i]->validatePlacement(group, pid) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-14 09:17:26 +00:00
|
|
|
static int
|
|
|
|
virCgroupDetectControllers(virCgroupPtr group,
|
|
|
|
int controllers,
|
|
|
|
virCgroupPtr parent)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
int controllersAvailable = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (!group->backends[i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
rc = group->backends[i]->detectControllers(group, controllers, parent,
|
|
|
|
controllersAvailable);
|
|
|
|
if (rc < 0)
|
|
|
|
return -1;
|
|
|
|
controllersAvailable |= rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check that at least 1 controller is available */
|
|
|
|
if (controllersAvailable == 0) {
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("At least one cgroup controller is required"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-17 13:30:21 +00:00
|
|
|
char *
|
2015-08-03 12:44:14 +00:00
|
|
|
virCgroupGetBlockDevString(const char *path)
|
|
|
|
{
|
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
if (stat(path, &sb) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Path '%s' is not accessible"),
|
|
|
|
path);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_ISBLK(sb.st_mode)) {
|
|
|
|
virReportSystemError(EINVAL,
|
|
|
|
_("Path '%s' must be a block device"),
|
|
|
|
path);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Automatically append space after the string since all callers
|
|
|
|
* use it anyway */
|
2020-05-04 15:03:42 +00:00
|
|
|
return g_strdup_printf("%d:%d ", major(sb.st_rdev), minor(sb.st_rdev));
|
2015-08-03 12:44:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-18 14:11:47 +00:00
|
|
|
int
|
2019-06-18 13:01:39 +00:00
|
|
|
virCgroupSetValueRaw(const char *path,
|
2013-08-12 19:52:06 +00:00
|
|
|
const char *value)
|
2008-10-03 17:58:02 +00:00
|
|
|
{
|
2019-06-18 13:01:39 +00:00
|
|
|
char *tmp;
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2019-06-18 13:01:39 +00:00
|
|
|
VIR_DEBUG("Set value '%s' to '%s'", path, value);
|
|
|
|
if (virFileWriteStr(path, value, 0) < 0) {
|
2013-10-11 13:41:23 +00:00
|
|
|
if (errno == EINVAL &&
|
2019-06-18 13:01:39 +00:00
|
|
|
(tmp = strrchr(path, '/'))) {
|
2013-10-11 13:41:23 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Invalid value '%s' for '%s'"),
|
|
|
|
value, tmp + 1);
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2013-10-11 13:41:23 +00:00
|
|
|
}
|
2013-07-08 10:08:46 +00:00
|
|
|
virReportSystemError(errno,
|
2019-06-18 13:01:39 +00:00
|
|
|
_("Unable to write to '%s'"), path);
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2018-07-24 15:52:10 +00:00
|
|
|
return 0;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2018-09-18 14:11:47 +00:00
|
|
|
int
|
2019-06-18 13:01:39 +00:00
|
|
|
virCgroupGetValueRaw(const char *path,
|
2013-08-12 19:52:06 +00:00
|
|
|
char **value)
|
2008-10-03 17:58:02 +00:00
|
|
|
{
|
2018-07-24 15:52:10 +00:00
|
|
|
int rc;
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2009-07-09 13:10:06 +00:00
|
|
|
*value = NULL;
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2019-06-18 13:01:39 +00:00
|
|
|
VIR_DEBUG("Get value %s", path);
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2019-06-18 13:01:39 +00:00
|
|
|
if ((rc = virFileReadAll(path, 1024*1024, value)) < 0) {
|
2013-07-08 10:08:46 +00:00
|
|
|
virReportSystemError(errno,
|
2019-06-18 13:01:39 +00:00
|
|
|
_("Unable to read from '%s'"), path);
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
/* Terminated with '\n' has sometimes harmful effects to the caller */
|
|
|
|
if (rc > 0 && (*value)[rc - 1] == '\n')
|
|
|
|
(*value)[rc - 1] = '\0';
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2018-07-24 15:52:10 +00:00
|
|
|
return 0;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2019-06-18 13:01:39 +00:00
|
|
|
int
|
|
|
|
virCgroupSetValueStr(virCgroupPtr group,
|
|
|
|
int controller,
|
|
|
|
const char *key,
|
|
|
|
const char *value)
|
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *keypath = NULL;
|
2019-06-18 13:01:39 +00:00
|
|
|
|
|
|
|
if (virCgroupPathOfController(group, controller, key, &keypath) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virCgroupSetValueRaw(keypath, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupGetValueStr(virCgroupPtr group,
|
|
|
|
int controller,
|
|
|
|
const char *key,
|
|
|
|
char **value)
|
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *keypath = NULL;
|
2019-06-18 13:01:39 +00:00
|
|
|
|
|
|
|
if (virCgroupPathOfController(group, controller, key, &keypath) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virCgroupGetValueRaw(keypath, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-24 10:20:19 +00:00
|
|
|
int
|
2019-06-18 13:24:41 +00:00
|
|
|
virCgroupGetValueForBlkDev(const char *str,
|
2015-08-03 13:10:20 +00:00
|
|
|
const char *path,
|
|
|
|
char **value)
|
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *prefix = NULL;
|
2018-07-30 09:03:16 +00:00
|
|
|
char **lines = NULL;
|
|
|
|
int ret = -1;
|
2015-08-03 13:10:20 +00:00
|
|
|
|
|
|
|
if (!(prefix = virCgroupGetBlockDevString(path)))
|
2018-07-30 09:03:16 +00:00
|
|
|
goto error;
|
2015-08-03 13:10:20 +00:00
|
|
|
|
|
|
|
if (!(lines = virStringSplit(str, "\n", -1)))
|
2018-07-30 09:03:16 +00:00
|
|
|
goto error;
|
2015-08-03 13:10:20 +00:00
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
*value = g_strdup(virStringListGetFirstWithPrefix(lines, prefix));
|
2015-08-03 13:10:20 +00:00
|
|
|
|
2018-07-30 09:03:16 +00:00
|
|
|
ret = 0;
|
|
|
|
error:
|
2020-08-02 17:36:03 +00:00
|
|
|
g_strfreev(lines);
|
2018-07-30 09:03:16 +00:00
|
|
|
return ret;
|
2015-08-03 13:10:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-18 14:11:47 +00:00
|
|
|
int
|
2013-08-12 19:52:06 +00:00
|
|
|
virCgroupSetValueU64(virCgroupPtr group,
|
|
|
|
int controller,
|
|
|
|
const char *key,
|
|
|
|
unsigned long long int value)
|
2009-07-09 13:10:06 +00:00
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *strval = NULL;
|
2009-07-09 13:10:06 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
strval = g_strdup_printf("%llu", value);
|
2009-07-09 13:10:06 +00:00
|
|
|
|
2018-07-24 15:52:10 +00:00
|
|
|
return virCgroupSetValueStr(group, controller, key, strval);
|
2009-07-09 13:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-24 23:14:36 +00:00
|
|
|
int
|
2013-08-12 19:52:06 +00:00
|
|
|
virCgroupSetValueI64(virCgroupPtr group,
|
|
|
|
int controller,
|
|
|
|
const char *key,
|
|
|
|
long long int value)
|
2008-10-08 16:28:48 +00:00
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *strval = NULL;
|
2008-10-08 16:28:48 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
strval = g_strdup_printf("%lld", value);
|
2008-10-08 16:28:48 +00:00
|
|
|
|
2018-07-24 15:52:10 +00:00
|
|
|
return virCgroupSetValueStr(group, controller, key, strval);
|
2008-10-08 16:28:48 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2018-08-17 14:22:56 +00:00
|
|
|
int
|
2013-08-12 19:52:06 +00:00
|
|
|
virCgroupGetValueI64(virCgroupPtr group,
|
|
|
|
int controller,
|
|
|
|
const char *key,
|
|
|
|
long long int *value)
|
2008-10-03 17:58:02 +00:00
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *strval = NULL;
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupGetValueStr(group, controller, key, &strval) < 0)
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virStrToLong_ll(strval, NULL, 10, value) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to parse '%s' as an integer"),
|
|
|
|
strval);
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2013-07-08 10:08:46 +00:00
|
|
|
}
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2018-07-24 15:52:10 +00:00
|
|
|
return 0;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2018-09-18 14:11:47 +00:00
|
|
|
int
|
2013-08-12 19:52:06 +00:00
|
|
|
virCgroupGetValueU64(virCgroupPtr group,
|
|
|
|
int controller,
|
|
|
|
const char *key,
|
|
|
|
unsigned long long int *value)
|
2008-10-03 17:58:02 +00:00
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *strval = NULL;
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupGetValueStr(group, controller, key, &strval) < 0)
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virStrToLong_ull(strval, NULL, 10, value) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to parse '%s' as an integer"),
|
|
|
|
strval);
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2013-07-08 10:08:46 +00:00
|
|
|
}
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2018-07-24 15:52:10 +00:00
|
|
|
return 0;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
static int
|
|
|
|
virCgroupMakeGroup(virCgroupPtr parent,
|
|
|
|
virCgroupPtr group,
|
|
|
|
bool create,
|
|
|
|
unsigned int flags)
|
2008-10-03 17:58:02 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (group->backends[i] &&
|
|
|
|
group->backends[i]->makeGroup(parent, group, create, flags) < 0) {
|
|
|
|
virCgroupRemove(group);
|
|
|
|
return -1;
|
|
|
|
}
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2018-07-24 15:52:10 +00:00
|
|
|
return 0;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2009-07-09 13:10:41 +00:00
|
|
|
|
2013-03-22 11:11:34 +00:00
|
|
|
/**
|
|
|
|
* virCgroupNew:
|
|
|
|
* @path: path for the new group
|
|
|
|
* @controllers: bitmask of controllers to activate
|
|
|
|
*
|
|
|
|
* Create a new cgroup storing it in @group.
|
|
|
|
*
|
2013-07-04 15:49:24 +00:00
|
|
|
* Returns 0 on success, -1 on error
|
2013-03-22 11:11:34 +00:00
|
|
|
*/
|
2018-08-17 14:18:38 +00:00
|
|
|
int
|
2020-10-15 15:05:17 +00:00
|
|
|
virCgroupNew(const char *path,
|
2013-08-12 19:52:06 +00:00
|
|
|
int controllers,
|
|
|
|
virCgroupPtr *group)
|
2008-10-03 17:58:02 +00:00
|
|
|
{
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) newGroup = NULL;
|
|
|
|
|
2020-10-15 15:05:17 +00:00
|
|
|
VIR_DEBUG("path=%s controllers=%d group=%p",
|
|
|
|
path, controllers, group);
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
*group = NULL;
|
|
|
|
newGroup = g_new0(virCgroup, 1);
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2020-10-15 11:11:28 +00:00
|
|
|
if (virCgroupSetBackends(newGroup) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupDetectMounts(newGroup) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2020-10-21 12:35:48 +00:00
|
|
|
if (virCgroupSetPlacement(newGroup, path) < 0)
|
2020-10-15 11:11:28 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* ... but use /proc/cgroups to fill in the rest */
|
2020-10-15 15:05:17 +00:00
|
|
|
if (virCgroupDetectPlacement(newGroup, -1, path) < 0)
|
2020-10-15 11:11:28 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Check that for every mounted controller, we found our placement */
|
2020-10-15 15:05:17 +00:00
|
|
|
if (virCgroupValidatePlacement(newGroup, -1) < 0)
|
2020-10-15 11:11:28 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupDetectControllers(newGroup, controllers, NULL) < 0)
|
2020-10-09 14:09:46 +00:00
|
|
|
return -1;
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
*group = g_steal_pointer(&newGroup);
|
2013-07-04 15:49:24 +00:00
|
|
|
return 0;
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
2009-07-10 10:40:04 +00:00
|
|
|
|
2013-03-21 13:27:13 +00:00
|
|
|
|
2018-09-28 17:53:05 +00:00
|
|
|
static int
|
|
|
|
virCgroupAddTaskInternal(virCgroupPtr group,
|
|
|
|
pid_t pid,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (group->backends[i] &&
|
|
|
|
group->backends[i]->addTask(group, pid, flags) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-05 15:26:00 +00:00
|
|
|
/**
|
2018-09-11 13:03:22 +00:00
|
|
|
* virCgroupAddProcess:
|
2017-01-05 15:26:00 +00:00
|
|
|
*
|
2018-09-11 13:03:22 +00:00
|
|
|
* @group: The cgroup to add a process to
|
|
|
|
* @pid: The pid of the process to add
|
2017-01-05 15:26:00 +00:00
|
|
|
*
|
2018-09-11 13:03:22 +00:00
|
|
|
* Will add the process to all controllers, except the
|
2017-01-05 15:26:00 +00:00
|
|
|
* systemd unit controller.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
|
|
|
int
|
2018-09-11 13:03:22 +00:00
|
|
|
virCgroupAddProcess(virCgroupPtr group, pid_t pid)
|
2017-01-05 15:26:00 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
return virCgroupAddTaskInternal(group, pid, VIR_CGROUP_TASK_PROCESS);
|
2017-01-05 15:26:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-09-11 13:03:22 +00:00
|
|
|
* virCgroupAddMachineProcess:
|
2017-01-05 15:26:00 +00:00
|
|
|
*
|
2018-09-11 13:03:22 +00:00
|
|
|
* @group: The cgroup to add a process to
|
|
|
|
* @pid: The pid of the process to add
|
2017-01-05 15:26:00 +00:00
|
|
|
*
|
2018-09-11 13:03:22 +00:00
|
|
|
* Will add the process to all controllers, including the
|
2017-01-05 15:26:00 +00:00
|
|
|
* systemd unit controller.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
|
|
|
int
|
2018-09-11 13:03:22 +00:00
|
|
|
virCgroupAddMachineProcess(virCgroupPtr group, pid_t pid)
|
2017-01-05 15:26:00 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
return virCgroupAddTaskInternal(group, pid,
|
|
|
|
VIR_CGROUP_TASK_PROCESS |
|
|
|
|
VIR_CGROUP_TASK_SYSTEMD);
|
2017-01-05 15:26:00 +00:00
|
|
|
}
|
|
|
|
|
2018-09-24 22:54:04 +00:00
|
|
|
/**
|
|
|
|
* virCgroupAddThread:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to add a thread to
|
|
|
|
* @pid: The pid of the thread to add
|
|
|
|
*
|
|
|
|
* Will add the thread to all controllers, except the
|
|
|
|
* systemd unit controller.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupAddThread(virCgroupPtr group,
|
|
|
|
pid_t pid)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
return virCgroupAddTaskInternal(group, pid, VIR_CGROUP_TASK_THREAD);
|
2018-09-24 22:54:04 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
virCgroupSetPartitionSuffix(const char *path, char **res)
|
2013-04-26 09:23:51 +00:00
|
|
|
{
|
2018-07-30 09:03:16 +00:00
|
|
|
char **tokens;
|
2013-04-26 09:23:51 +00:00
|
|
|
size_t i;
|
2018-07-30 09:03:16 +00:00
|
|
|
int ret = -1;
|
2013-04-26 09:23:51 +00:00
|
|
|
|
2013-07-04 15:49:24 +00:00
|
|
|
if (!(tokens = virStringSplit(path, "/", 0)))
|
2018-07-30 09:03:16 +00:00
|
|
|
return ret;
|
2013-04-26 09:23:51 +00:00
|
|
|
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; tokens[i] != NULL; i++) {
|
2020-06-16 10:24:48 +00:00
|
|
|
/* Special case the 3 top level fixed dirs
|
2013-04-26 09:23:51 +00:00
|
|
|
* NB i == 0 is "", since we have leading '/'
|
|
|
|
*/
|
|
|
|
if (i == 1 &&
|
|
|
|
(STREQ(tokens[i], "machine") ||
|
|
|
|
STREQ(tokens[i], "system") ||
|
|
|
|
STREQ(tokens[i], "user"))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* If there is no suffix set already, then
|
|
|
|
* add ".partition"
|
|
|
|
*/
|
|
|
|
if (STRNEQ(tokens[i], "") &&
|
|
|
|
!strchr(tokens[i], '.')) {
|
2020-09-22 09:18:51 +00:00
|
|
|
g_autofree char *oldtoken = tokens[i];
|
|
|
|
tokens[i] = g_strdup_printf("%s.partition", oldtoken);
|
2013-04-26 09:23:51 +00:00
|
|
|
}
|
2013-04-26 09:50:24 +00:00
|
|
|
|
2013-07-04 15:49:24 +00:00
|
|
|
if (virCgroupPartitionEscape(&(tokens[i])) < 0)
|
2018-07-30 09:03:16 +00:00
|
|
|
goto cleanup;
|
2013-04-26 09:23:51 +00:00
|
|
|
}
|
|
|
|
|
2016-11-25 08:18:35 +00:00
|
|
|
if (!(*res = virStringListJoin((const char **)tokens, "/")))
|
2018-07-30 09:03:16 +00:00
|
|
|
goto cleanup;
|
2013-04-26 09:23:51 +00:00
|
|
|
|
2018-07-30 09:03:16 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2020-08-02 17:36:03 +00:00
|
|
|
g_strfreev(tokens);
|
2018-07-30 09:03:16 +00:00
|
|
|
return ret;
|
2013-04-26 09:23:51 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2020-11-03 12:27:08 +00:00
|
|
|
static int
|
|
|
|
virCgroupNewFromParent(virCgroupPtr parent,
|
|
|
|
const char *path,
|
|
|
|
int controllers,
|
|
|
|
virCgroupPtr *group)
|
|
|
|
{
|
|
|
|
g_autoptr(virCgroup) new = g_new0(virCgroup, 1);
|
|
|
|
|
|
|
|
VIR_DEBUG("parent=%p path=%s controllers=%d group=%p",
|
|
|
|
parent, path, controllers, group);
|
|
|
|
|
|
|
|
if (virCgroupSetBackends(new) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupCopyMounts(new, parent) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupCopyPlacement(new, path, parent) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupDetectPlacement(new, -1, path) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupValidatePlacement(new, -1) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupDetectControllers(new, controllers, parent) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
*group = g_steal_pointer(&new);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-28 18:08:39 +00:00
|
|
|
/**
|
|
|
|
* virCgroupNewPartition:
|
|
|
|
* @path: path for the partition
|
|
|
|
* @create: true to create the cgroup tree
|
|
|
|
* @controllers: mask of controllers to create
|
|
|
|
*
|
|
|
|
* Creates a new cgroup to represent the resource
|
2015-03-27 10:24:16 +00:00
|
|
|
* partition path identified by @path.
|
2013-03-28 18:08:39 +00:00
|
|
|
*
|
2013-07-04 15:49:24 +00:00
|
|
|
* Returns 0 on success, -1 on failure
|
2013-03-28 18:08:39 +00:00
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupNewPartition(const char *path,
|
|
|
|
bool create,
|
|
|
|
int controllers,
|
|
|
|
virCgroupPtr *group)
|
2013-03-28 18:08:39 +00:00
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *newPath = NULL;
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) parent = NULL;
|
|
|
|
g_autoptr(virCgroup) newGroup = NULL;
|
2020-11-02 21:50:58 +00:00
|
|
|
char *partition = NULL;
|
2020-10-09 14:09:46 +00:00
|
|
|
|
2013-03-28 18:08:39 +00:00
|
|
|
VIR_DEBUG("path=%s create=%d controllers=%x",
|
|
|
|
path, create, controllers);
|
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
*group = NULL;
|
|
|
|
|
2013-07-04 15:49:24 +00:00
|
|
|
if (path[0] != '/') {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Partition path '%s' must start with '/'"),
|
|
|
|
path);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-03-28 18:08:39 +00:00
|
|
|
|
2013-12-06 03:38:14 +00:00
|
|
|
if (virCgroupSetPartitionSuffix(path, &newPath) < 0)
|
2020-10-09 14:09:46 +00:00
|
|
|
return -1;
|
2013-04-26 09:23:51 +00:00
|
|
|
|
2013-12-06 03:38:14 +00:00
|
|
|
if (STRNEQ(newPath, "/")) {
|
2013-03-28 18:08:39 +00:00
|
|
|
char *tmp;
|
2020-11-02 21:50:58 +00:00
|
|
|
const char *parentPath;
|
2013-03-28 18:08:39 +00:00
|
|
|
|
2020-11-02 21:50:58 +00:00
|
|
|
tmp = strrchr(newPath, '/');
|
2013-03-28 18:08:39 +00:00
|
|
|
*tmp = '\0';
|
|
|
|
|
2020-11-02 21:50:58 +00:00
|
|
|
if (tmp == newPath) {
|
|
|
|
parentPath = "/";
|
|
|
|
} else {
|
|
|
|
parentPath = newPath;
|
|
|
|
}
|
|
|
|
|
2020-10-15 15:05:17 +00:00
|
|
|
if (virCgroupNew(parentPath, controllers, &parent) < 0)
|
2020-10-09 14:09:46 +00:00
|
|
|
return -1;
|
2020-11-02 21:50:58 +00:00
|
|
|
|
|
|
|
partition = tmp + 1;
|
|
|
|
} else {
|
|
|
|
partition = newPath;
|
2019-11-04 14:55:23 +00:00
|
|
|
}
|
2013-03-28 18:08:39 +00:00
|
|
|
|
2020-11-02 21:50:58 +00:00
|
|
|
if (virCgroupNewFromParent(parent, partition, controllers, &newGroup) < 0)
|
2020-10-09 14:09:46 +00:00
|
|
|
return -1;
|
2019-11-04 14:55:23 +00:00
|
|
|
|
|
|
|
if (parent) {
|
2020-10-09 14:09:46 +00:00
|
|
|
if (virCgroupMakeGroup(parent, newGroup, create, VIR_CGROUP_NONE) < 0)
|
|
|
|
return -1;
|
2013-03-28 18:08:39 +00:00
|
|
|
}
|
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
*group = g_steal_pointer(&newGroup);
|
|
|
|
return 0;
|
2013-03-28 18:08:39 +00:00
|
|
|
}
|
|
|
|
|
2008-10-03 17:58:02 +00:00
|
|
|
|
2012-11-12 07:02:26 +00:00
|
|
|
/**
|
2013-03-28 16:33:22 +00:00
|
|
|
* virCgroupNewSelf:
|
2012-11-12 07:02:26 +00:00
|
|
|
*
|
|
|
|
* @group: Pointer to returned virCgroupPtr
|
|
|
|
*
|
2013-03-21 11:53:14 +00:00
|
|
|
* Obtain a cgroup representing the config of the
|
|
|
|
* current process
|
|
|
|
*
|
2013-07-04 15:49:24 +00:00
|
|
|
* Returns 0 on success, or -1 on error
|
2012-11-12 07:02:26 +00:00
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupNewSelf(virCgroupPtr *group)
|
2012-11-12 07:02:26 +00:00
|
|
|
{
|
2013-07-24 16:31:25 +00:00
|
|
|
return virCgroupNewDetect(-1, -1, group);
|
2012-11-12 07:02:26 +00:00
|
|
|
}
|
2013-07-19 10:13:05 +00:00
|
|
|
|
2009-07-10 10:40:04 +00:00
|
|
|
|
2013-03-28 18:08:39 +00:00
|
|
|
/**
|
|
|
|
* virCgroupNewDomainPartition:
|
|
|
|
*
|
|
|
|
* @partition: partition holding the domain
|
|
|
|
* @driver: name of the driver
|
|
|
|
* @name: name of the domain
|
|
|
|
* @group: Pointer to returned virCgroupPtr
|
|
|
|
*
|
2013-07-04 15:49:24 +00:00
|
|
|
* Returns 0 on success, or -1 on error
|
2013-03-28 18:08:39 +00:00
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupNewDomainPartition(virCgroupPtr partition,
|
|
|
|
const char *driver,
|
|
|
|
const char *name,
|
|
|
|
virCgroupPtr *group)
|
2013-03-28 18:08:39 +00:00
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *grpname = NULL;
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) newGroup = NULL;
|
2013-03-28 18:08:39 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
grpname = g_strdup_printf("%s.libvirt-%s", name, driver);
|
2013-03-28 18:08:39 +00:00
|
|
|
|
2013-07-04 15:49:24 +00:00
|
|
|
if (virCgroupPartitionEscape(&grpname) < 0)
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2013-04-26 09:50:24 +00:00
|
|
|
|
2020-11-03 12:27:08 +00:00
|
|
|
if (virCgroupNewFromParent(partition, grpname, -1, &newGroup) < 0)
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2013-07-04 15:49:24 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a cgroup with memory.use_hierarchy enabled to
|
|
|
|
* surely account memory usage of lxc with ns subsystem
|
|
|
|
* enabled. (To be exact, memory and ns subsystems are
|
|
|
|
* enabled at the same time.)
|
|
|
|
*
|
|
|
|
* The reason why doing it here, not a upper group, say
|
|
|
|
* a group for driver, is to avoid overhead to track
|
|
|
|
* cumulative usage that we don't need.
|
|
|
|
*/
|
2020-10-21 23:43:57 +00:00
|
|
|
if (virCgroupMakeGroup(partition, newGroup, true,
|
2013-08-12 19:52:06 +00:00
|
|
|
VIR_CGROUP_MEM_HIERACHY) < 0) {
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2013-03-28 18:08:39 +00:00
|
|
|
}
|
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
*group = g_steal_pointer(&newGroup);
|
2018-07-24 15:52:10 +00:00
|
|
|
return 0;
|
2013-03-28 18:08:39 +00:00
|
|
|
}
|
2009-07-10 10:40:04 +00:00
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2015-04-07 12:28:05 +00:00
|
|
|
/**
|
|
|
|
* virCgroupNewThread:
|
|
|
|
*
|
|
|
|
* @domain: group for the domain
|
|
|
|
* @name: enum to generate the name for the new thread
|
|
|
|
* @id: id of the vcpu or iothread
|
|
|
|
* @create: true to create if not already existing
|
|
|
|
* @group: Pointer to returned virCgroupPtr
|
|
|
|
*
|
|
|
|
* Returns 0 on success, or -1 on error
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupNewThread(virCgroupPtr domain,
|
|
|
|
virCgroupThreadName nameval,
|
|
|
|
int id,
|
|
|
|
bool create,
|
|
|
|
virCgroupPtr *group)
|
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *name = NULL;
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) newGroup = NULL;
|
2015-04-07 12:28:05 +00:00
|
|
|
int controllers;
|
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
*group = NULL;
|
|
|
|
|
2015-04-07 12:28:05 +00:00
|
|
|
switch (nameval) {
|
|
|
|
case VIR_CGROUP_THREAD_VCPU:
|
2019-10-22 13:26:14 +00:00
|
|
|
name = g_strdup_printf("vcpu%d", id);
|
2015-04-07 12:28:05 +00:00
|
|
|
break;
|
|
|
|
case VIR_CGROUP_THREAD_EMULATOR:
|
2019-10-20 11:49:46 +00:00
|
|
|
name = g_strdup("emulator");
|
2015-04-07 12:28:05 +00:00
|
|
|
break;
|
|
|
|
case VIR_CGROUP_THREAD_IOTHREAD:
|
2019-10-22 13:26:14 +00:00
|
|
|
name = g_strdup_printf("iothread%d", id);
|
2015-04-07 12:28:05 +00:00
|
|
|
break;
|
|
|
|
case VIR_CGROUP_THREAD_LAST:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected name value %d"), nameval);
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2015-04-07 12:28:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
controllers = ((1 << VIR_CGROUP_CONTROLLER_CPU) |
|
|
|
|
(1 << VIR_CGROUP_CONTROLLER_CPUACCT) |
|
|
|
|
(1 << VIR_CGROUP_CONTROLLER_CPUSET));
|
|
|
|
|
2020-11-03 12:27:08 +00:00
|
|
|
if (virCgroupNewFromParent(domain, name, controllers, &newGroup) < 0)
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2015-04-07 12:28:05 +00:00
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
if (virCgroupMakeGroup(domain, newGroup, create, VIR_CGROUP_THREAD) < 0)
|
2018-07-24 15:52:10 +00:00
|
|
|
return -1;
|
2015-04-07 12:28:05 +00:00
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
*group = g_steal_pointer(&newGroup);
|
2018-07-24 15:52:10 +00:00
|
|
|
return 0;
|
2015-04-07 12:28:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupNewDetect(pid_t pid,
|
|
|
|
int controllers,
|
|
|
|
virCgroupPtr *group)
|
2013-07-19 10:13:05 +00:00
|
|
|
{
|
2020-10-14 09:23:27 +00:00
|
|
|
g_autoptr(virCgroup) new = g_new0(virCgroup, 1);
|
|
|
|
|
|
|
|
VIR_DEBUG("pid=%lld controllers=%d group=%p",
|
|
|
|
(long long) pid, controllers, group);
|
|
|
|
|
|
|
|
if (virCgroupSetBackends(new) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupDetectMounts(new) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupDetectPlacement(new, pid, "") < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupValidatePlacement(new, pid) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupDetectControllers(new, controllers, NULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
*group = g_steal_pointer(&new);
|
|
|
|
return 0;
|
2013-07-19 10:13:05 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2013-07-24 16:36:42 +00:00
|
|
|
/*
|
|
|
|
* Returns 0 on success (but @group may be NULL), -1 on fatal error
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupNewDetectMachine(const char *name,
|
|
|
|
const char *drivername,
|
|
|
|
pid_t pid,
|
|
|
|
int controllers,
|
2017-07-21 13:51:03 +00:00
|
|
|
char *machinename,
|
2013-08-12 19:52:06 +00:00
|
|
|
virCgroupPtr *group)
|
2013-07-24 16:36:42 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
size_t i;
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) newGroup = NULL;
|
|
|
|
|
|
|
|
*group = NULL;
|
2018-09-28 17:53:05 +00:00
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
if (virCgroupNewDetect(pid, controllers, &newGroup) < 0) {
|
2013-07-24 16:36:42 +00:00
|
|
|
if (virCgroupNewIgnoreError())
|
|
|
|
return 0;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-28 17:53:05 +00:00
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
2020-10-09 14:09:46 +00:00
|
|
|
if (newGroup->backends[i] &&
|
|
|
|
!newGroup->backends[i]->validateMachineGroup(newGroup, name,
|
2018-09-28 17:53:05 +00:00
|
|
|
drivername,
|
|
|
|
machinename)) {
|
|
|
|
VIR_DEBUG("Failed to validate machine name for '%s' driver '%s'",
|
|
|
|
name, drivername);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-07-24 16:36:42 +00:00
|
|
|
}
|
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
*group = g_steal_pointer(&newGroup);
|
2013-07-24 16:36:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2018-07-31 10:09:40 +00:00
|
|
|
static int
|
|
|
|
virCgroupEnableMissingControllers(char *path,
|
|
|
|
int controllers,
|
|
|
|
virCgroupPtr *group)
|
|
|
|
{
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) parent = NULL;
|
2020-11-02 15:05:07 +00:00
|
|
|
VIR_AUTOSTRINGLIST tokens = virStringSplit(path, "/", 0);
|
|
|
|
size_t i;
|
2018-07-31 10:09:40 +00:00
|
|
|
|
2020-11-02 15:05:07 +00:00
|
|
|
if (virCgroupNew("/", controllers, &parent) < 0)
|
2020-10-09 14:09:46 +00:00
|
|
|
return -1;
|
2018-07-31 10:09:40 +00:00
|
|
|
|
2020-11-02 15:05:07 +00:00
|
|
|
/* Skip the first token as it is empty string. */
|
|
|
|
for (i = 1; tokens[i]; i++) {
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) tmp = NULL;
|
2018-07-31 10:09:40 +00:00
|
|
|
|
2020-11-03 12:27:08 +00:00
|
|
|
if (virCgroupNewFromParent(parent,
|
2020-11-02 15:05:07 +00:00
|
|
|
tokens[i],
|
2020-11-03 12:27:08 +00:00
|
|
|
controllers,
|
|
|
|
&tmp) < 0)
|
2020-10-09 14:09:46 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupMakeGroup(parent, tmp, true, VIR_CGROUP_SYSTEMD) < 0)
|
|
|
|
return -1;
|
2018-07-31 10:09:40 +00:00
|
|
|
|
2020-11-02 15:05:07 +00:00
|
|
|
parent = g_steal_pointer(&tmp);
|
2018-07-31 10:09:40 +00:00
|
|
|
}
|
|
|
|
|
2020-11-02 15:05:07 +00:00
|
|
|
*group = g_steal_pointer(&parent);
|
2020-10-09 14:09:46 +00:00
|
|
|
return 0;
|
2018-07-31 10:09:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-22 15:34:51 +00:00
|
|
|
/*
|
|
|
|
* Returns 0 on success, -1 on fatal error, -2 on systemd not available
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virCgroupNewMachineSystemd(const char *name,
|
|
|
|
const char *drivername,
|
|
|
|
const unsigned char *uuid,
|
|
|
|
const char *rootdir,
|
|
|
|
pid_t pidleader,
|
|
|
|
bool isContainer,
|
2014-11-11 17:38:43 +00:00
|
|
|
size_t nnicindexes,
|
|
|
|
int *nicindexes,
|
2013-07-22 15:34:51 +00:00
|
|
|
const char *partition,
|
|
|
|
int controllers,
|
2019-05-22 23:12:14 +00:00
|
|
|
unsigned int maxthreads,
|
2013-07-22 15:34:51 +00:00
|
|
|
virCgroupPtr *group)
|
2013-07-18 15:55:37 +00:00
|
|
|
{
|
2013-07-22 15:34:51 +00:00
|
|
|
int rv;
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) init = NULL;
|
|
|
|
g_autoptr(virCgroup) newGroup = NULL;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *path = NULL;
|
2018-09-28 17:53:05 +00:00
|
|
|
size_t i;
|
2013-07-22 15:34:51 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Trying to setup machine '%s' via systemd", name);
|
|
|
|
if ((rv = virSystemdCreateMachine(name,
|
|
|
|
drivername,
|
|
|
|
uuid,
|
|
|
|
rootdir,
|
|
|
|
pidleader,
|
|
|
|
isContainer,
|
2014-11-11 17:38:43 +00:00
|
|
|
nnicindexes,
|
|
|
|
nicindexes,
|
2019-05-22 23:12:14 +00:00
|
|
|
partition,
|
|
|
|
maxthreads)) < 0)
|
2013-07-22 15:34:51 +00:00
|
|
|
return rv;
|
|
|
|
|
|
|
|
if (controllers != -1)
|
|
|
|
controllers |= (1 << VIR_CGROUP_CONTROLLER_SYSTEMD);
|
|
|
|
|
|
|
|
VIR_DEBUG("Detecting systemd placement");
|
|
|
|
if (virCgroupNewDetect(pidleader,
|
|
|
|
controllers,
|
|
|
|
&init) < 0)
|
|
|
|
return -1;
|
2013-07-18 15:55:37 +00:00
|
|
|
|
2018-09-28 17:53:05 +00:00
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (init->backends[i] &&
|
|
|
|
(path = init->backends[i]->stealPlacement(init))) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-07-22 15:34:51 +00:00
|
|
|
|
|
|
|
if (!path || STREQ(path, "/") || path[0] != '/') {
|
2019-09-26 19:25:52 +00:00
|
|
|
VIR_DEBUG("Systemd didn't setup its controller, path=%s",
|
|
|
|
NULLSTR(path));
|
2018-07-31 10:09:40 +00:00
|
|
|
return -2;
|
2013-07-22 15:34:51 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 14:59:03 +00:00
|
|
|
if (virCgroupEnableMissingControllers(path, controllers, &newGroup) < 0)
|
2018-09-27 14:11:19 +00:00
|
|
|
return -1;
|
2013-07-22 15:34:51 +00:00
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
if (virCgroupAddProcess(newGroup, pidleader) < 0) {
|
2018-12-06 17:33:39 +00:00
|
|
|
virErrorPtr saved;
|
|
|
|
|
|
|
|
virErrorPreserveLast(&saved);
|
2020-10-09 14:09:46 +00:00
|
|
|
virCgroupRemove(newGroup);
|
2018-12-06 17:33:39 +00:00
|
|
|
virErrorRestore(&saved);
|
2020-10-09 14:09:46 +00:00
|
|
|
return 0;
|
2018-09-10 12:46:24 +00:00
|
|
|
}
|
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
*group = g_steal_pointer(&newGroup);
|
2018-09-27 14:11:19 +00:00
|
|
|
return 0;
|
2013-07-22 15:34:51 +00:00
|
|
|
}
|
2013-07-18 15:55:37 +00:00
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2014-09-25 11:32:58 +00:00
|
|
|
/*
|
|
|
|
* Returns 0 on success, -1 on fatal error
|
|
|
|
*/
|
2016-02-01 15:50:54 +00:00
|
|
|
int virCgroupTerminateMachine(const char *name)
|
2014-09-25 11:32:58 +00:00
|
|
|
{
|
2016-02-01 15:50:54 +00:00
|
|
|
return virSystemdTerminateMachine(name);
|
2014-09-25 11:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-22 15:34:51 +00:00
|
|
|
static int
|
|
|
|
virCgroupNewMachineManual(const char *name,
|
|
|
|
const char *drivername,
|
2016-01-14 16:00:25 +00:00
|
|
|
pid_t pidleader,
|
2013-07-22 15:34:51 +00:00
|
|
|
const char *partition,
|
|
|
|
int controllers,
|
|
|
|
virCgroupPtr *group)
|
|
|
|
{
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) parent = NULL;
|
|
|
|
g_autoptr(virCgroup) newGroup = NULL;
|
2013-07-22 15:34:51 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Fallback to non-systemd setup");
|
2013-07-18 15:55:37 +00:00
|
|
|
if (virCgroupNewPartition(partition,
|
|
|
|
STREQ(partition, "/machine"),
|
|
|
|
controllers,
|
|
|
|
&parent) < 0) {
|
|
|
|
if (virCgroupNewIgnoreError())
|
2020-10-09 14:09:46 +00:00
|
|
|
return 0;
|
2013-07-18 15:55:37 +00:00
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
return -1;
|
2013-07-18 15:55:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virCgroupNewDomainPartition(parent,
|
|
|
|
drivername,
|
|
|
|
name,
|
2020-10-09 14:09:46 +00:00
|
|
|
&newGroup) < 0)
|
|
|
|
return -1;
|
2013-07-18 15:55:37 +00:00
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
if (virCgroupAddProcess(newGroup, pidleader) < 0) {
|
2018-12-06 17:33:39 +00:00
|
|
|
virErrorPtr saved;
|
|
|
|
|
|
|
|
virErrorPreserveLast(&saved);
|
2020-10-09 14:09:46 +00:00
|
|
|
virCgroupRemove(newGroup);
|
2018-12-06 17:33:39 +00:00
|
|
|
virErrorRestore(&saved);
|
2016-01-14 16:00:25 +00:00
|
|
|
}
|
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
*group = g_steal_pointer(&newGroup);
|
|
|
|
return 0;
|
2013-07-18 15:55:37 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupNewMachine(const char *name,
|
|
|
|
const char *drivername,
|
|
|
|
const unsigned char *uuid,
|
|
|
|
const char *rootdir,
|
|
|
|
pid_t pidleader,
|
|
|
|
bool isContainer,
|
2014-11-11 17:38:43 +00:00
|
|
|
size_t nnicindexes,
|
|
|
|
int *nicindexes,
|
2013-08-12 19:52:06 +00:00
|
|
|
const char *partition,
|
|
|
|
int controllers,
|
2019-05-22 23:12:14 +00:00
|
|
|
unsigned int maxthreads,
|
2013-08-12 19:52:06 +00:00
|
|
|
virCgroupPtr *group)
|
2013-07-22 15:34:51 +00:00
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
*group = NULL;
|
|
|
|
|
|
|
|
if ((rv = virCgroupNewMachineSystemd(name,
|
|
|
|
drivername,
|
|
|
|
uuid,
|
|
|
|
rootdir,
|
|
|
|
pidleader,
|
|
|
|
isContainer,
|
2014-11-11 17:38:43 +00:00
|
|
|
nnicindexes,
|
|
|
|
nicindexes,
|
2013-07-22 15:34:51 +00:00
|
|
|
partition,
|
|
|
|
controllers,
|
2019-05-22 23:12:14 +00:00
|
|
|
maxthreads,
|
2013-07-22 15:34:51 +00:00
|
|
|
group)) == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (rv == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virCgroupNewMachineManual(name,
|
|
|
|
drivername,
|
2016-01-14 16:00:25 +00:00
|
|
|
pidleader,
|
2013-07-22 15:34:51 +00:00
|
|
|
partition,
|
|
|
|
controllers,
|
|
|
|
group);
|
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
|
|
|
bool
|
|
|
|
virCgroupNewIgnoreError(void)
|
2013-07-04 15:49:24 +00:00
|
|
|
{
|
|
|
|
if (virLastErrorIsSystemErrno(ENXIO) ||
|
|
|
|
virLastErrorIsSystemErrno(EPERM) ||
|
|
|
|
virLastErrorIsSystemErrno(EACCES)) {
|
|
|
|
virResetLastError();
|
|
|
|
VIR_DEBUG("No cgroups present/configured/accessible, ignoring error");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2013-08-12 21:20:59 +00:00
|
|
|
/**
|
|
|
|
* virCgroupHasController: query whether a cgroup controller is present
|
|
|
|
*
|
|
|
|
* @cgroup: The group structure to be queried, or NULL
|
|
|
|
* @controller: cgroup subsystem id
|
|
|
|
*
|
|
|
|
* Returns true if a cgroup controller is mounted and is associated
|
|
|
|
* with this cgroup object.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
virCgroupHasController(virCgroupPtr cgroup, int controller)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
size_t i;
|
|
|
|
|
2013-08-12 21:20:59 +00:00
|
|
|
if (!cgroup)
|
|
|
|
return false;
|
|
|
|
if (controller < 0 || controller >= VIR_CGROUP_CONTROLLER_LAST)
|
|
|
|
return false;
|
2018-08-19 17:17:27 +00:00
|
|
|
|
2018-09-28 17:53:05 +00:00
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (cgroup->backends[i] &&
|
|
|
|
cgroup->backends[i]->hasController(cgroup, controller)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2013-08-12 21:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupPathOfController(virCgroupPtr group,
|
2018-08-15 15:21:47 +00:00
|
|
|
unsigned int controller,
|
2013-08-12 21:20:59 +00:00
|
|
|
const char *key,
|
|
|
|
char **path)
|
|
|
|
{
|
2018-08-15 15:21:47 +00:00
|
|
|
if (controller >= VIR_CGROUP_CONTROLLER_LAST) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid controller id '%d'"), controller);
|
2013-08-12 21:20:59 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, controller, pathOfController, -1,
|
|
|
|
controller, key, path);
|
2013-08-12 21:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-14 17:48:59 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetBlkioIoServiced:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to get throughput for
|
|
|
|
* @bytes_read: Pointer to returned bytes read
|
|
|
|
* @bytes_write: Pointer to returned bytes written
|
|
|
|
* @requests_read: Pointer to returned read io ops
|
|
|
|
* @requests_write: Pointer to returned write io ops
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupGetBlkioIoServiced(virCgroupPtr group,
|
|
|
|
long long *bytes_read,
|
|
|
|
long long *bytes_write,
|
|
|
|
long long *requests_read,
|
|
|
|
long long *requests_write)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
getBlkioIoServiced, -1,
|
2018-08-17 13:29:39 +00:00
|
|
|
bytes_read, bytes_write,
|
|
|
|
requests_read, requests_write);
|
2014-02-14 17:48:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupGetBlkioIoDeviceServiced:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to get throughput for
|
|
|
|
* @path: The device to get throughput for
|
|
|
|
* @bytes_read: Pointer to returned bytes read
|
|
|
|
* @bytes_write: Pointer to returned bytes written
|
|
|
|
* @requests_read: Pointer to returned read io ops
|
|
|
|
* @requests_write: Pointer to returned write io ops
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupGetBlkioIoDeviceServiced(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
long long *bytes_read,
|
|
|
|
long long *bytes_write,
|
|
|
|
long long *requests_read,
|
|
|
|
long long *requests_write)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
getBlkioIoDeviceServiced, -1,
|
2018-08-17 13:30:21 +00:00
|
|
|
path, bytes_read, bytes_write,
|
|
|
|
requests_read, requests_write);
|
2014-02-14 17:48:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-08 06:56:39 +00:00
|
|
|
/**
|
|
|
|
* virCgroupSetBlkioWeight:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to change io weight for
|
|
|
|
* @weight: The Weight for this cgroup
|
|
|
|
*
|
2013-07-08 10:08:46 +00:00
|
|
|
* Returns: 0 on success, -1 on error
|
2011-02-08 06:56:39 +00:00
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupSetBlkioWeight(virCgroupPtr group, unsigned int weight)
|
2011-02-08 06:56:39 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
setBlkioWeight, -1, weight);
|
2011-02-08 06:56:39 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2011-02-08 06:56:39 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetBlkioWeight:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to get weight for
|
|
|
|
* @Weight: Pointer to returned weight
|
|
|
|
*
|
2013-07-08 10:08:46 +00:00
|
|
|
* Returns: 0 on success, -1 on error
|
2011-02-08 06:56:39 +00:00
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight)
|
2011-02-08 06:56:39 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
getBlkioWeight, -1, weight);
|
2011-02-08 06:56:39 +00:00
|
|
|
}
|
|
|
|
|
2013-12-11 08:29:50 +00:00
|
|
|
/**
|
|
|
|
* virCgroupSetBlkioDeviceReadIops:
|
|
|
|
* @group: The cgroup to change block io setting for
|
|
|
|
* @path: The path of device
|
|
|
|
* @riops: The new device read iops throttle, or 0 to clear
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2013-12-11 08:29:50 +00:00
|
|
|
virCgroupSetBlkioDeviceReadIops(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
unsigned int riops)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
setBlkioDeviceReadIops, -1, path, riops);
|
2013-12-11 08:29:50 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2011-11-08 11:00:34 +00:00
|
|
|
/**
|
2013-12-11 08:29:50 +00:00
|
|
|
* virCgroupSetBlkioDeviceWriteIops:
|
|
|
|
* @group: The cgroup to change block io setting for
|
|
|
|
* @path: The path of device
|
|
|
|
* @wiops: The new device write iops throttle, or 0 to clear
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2013-12-11 08:29:50 +00:00
|
|
|
virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
unsigned int wiops)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
setBlkioDeviceWriteIops, -1, path, wiops);
|
2013-12-11 08:29:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupSetBlkioDeviceReadBps:
|
|
|
|
* @group: The cgroup to change block io setting for
|
|
|
|
* @path: The path of device
|
|
|
|
* @rbps: The new device read bps throttle, or 0 to clear
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2013-12-11 08:29:50 +00:00
|
|
|
virCgroupSetBlkioDeviceReadBps(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
unsigned long long rbps)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
setBlkioDeviceReadBps, -1, path, rbps);
|
2013-12-11 08:29:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupSetBlkioDeviceWriteBps:
|
|
|
|
* @group: The cgroup to change block io setting for
|
|
|
|
* @path: The path of device
|
|
|
|
* @wbps: The new device write bps throttle, or 0 to clear
|
2011-11-08 11:00:34 +00:00
|
|
|
*
|
2013-12-11 08:29:50 +00:00
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2013-12-11 08:29:50 +00:00
|
|
|
virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
unsigned long long wbps)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
setBlkioDeviceWriteBps, -1, path, wbps);
|
2013-12-11 08:29:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupSetBlkioDeviceWeight:
|
|
|
|
* @group: The cgroup to change block io setting for
|
|
|
|
* @path: The path of device
|
2013-10-11 13:41:23 +00:00
|
|
|
* @weight: The new device weight (100-1000),
|
|
|
|
* (10-1000) after kernel 2.6.39, or 0 to clear
|
2011-11-08 11:00:34 +00:00
|
|
|
*
|
2013-07-08 10:08:46 +00:00
|
|
|
* Returns: 0 on success, -1 on error
|
2011-11-08 11:00:34 +00:00
|
|
|
*/
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2013-08-12 19:52:06 +00:00
|
|
|
virCgroupSetBlkioDeviceWeight(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
unsigned int weight)
|
2011-11-08 11:00:34 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
setBlkioDeviceWeight, -1, path, weight);
|
2011-11-08 11:00:34 +00:00
|
|
|
}
|
2013-08-11 12:04:28 +00:00
|
|
|
|
2015-08-03 13:10:20 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetBlkioDeviceReadIops:
|
|
|
|
* @group: The cgroup to gather block io setting for
|
|
|
|
* @path: The path of device
|
|
|
|
* @riops: Returned device read iops throttle, 0 if there is none
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2015-08-03 13:10:20 +00:00
|
|
|
virCgroupGetBlkioDeviceReadIops(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
unsigned int *riops)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
getBlkioDeviceReadIops, -1, path, riops);
|
2015-08-03 13:10:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupGetBlkioDeviceWriteIops:
|
|
|
|
* @group: The cgroup to gather block io setting for
|
|
|
|
* @path: The path of device
|
|
|
|
* @wiops: Returned device write iops throttle, 0 if there is none
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2015-08-03 13:10:20 +00:00
|
|
|
virCgroupGetBlkioDeviceWriteIops(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
unsigned int *wiops)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
getBlkioDeviceWriteIops, -1, path, wiops);
|
2015-08-03 13:10:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupGetBlkioDeviceReadBps:
|
|
|
|
* @group: The cgroup to gather block io setting for
|
|
|
|
* @path: The path of device
|
|
|
|
* @rbps: Returned device read bps throttle, 0 if there is none
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2015-08-03 13:10:20 +00:00
|
|
|
virCgroupGetBlkioDeviceReadBps(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
unsigned long long *rbps)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
getBlkioDeviceReadBps, -1, path, rbps);
|
2015-08-03 13:10:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupGetBlkioDeviceWriteBps:
|
|
|
|
* @group: The cgroup to gather block io setting for
|
|
|
|
* @path: The path of device
|
|
|
|
* @wbps: Returned device write bps throttle, 0 if there is none
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2015-08-03 13:10:20 +00:00
|
|
|
virCgroupGetBlkioDeviceWriteBps(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
unsigned long long *wbps)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
getBlkioDeviceWriteBps, -1, path, wbps);
|
2015-08-03 13:10:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupGetBlkioDeviceWeight:
|
|
|
|
* @group: The cgroup to gather block io setting for
|
|
|
|
* @path: The path of device
|
|
|
|
* @weight: Returned device weight, 0 if there is none
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2015-08-03 13:10:20 +00:00
|
|
|
virCgroupGetBlkioDeviceWeight(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
unsigned int *weight)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
|
|
|
|
getBlkioDeviceWeight, -1, path, weight);
|
2015-08-03 13:10:20 +00:00
|
|
|
}
|
|
|
|
|
2011-11-08 11:00:34 +00:00
|
|
|
|
2008-10-03 17:58:02 +00:00
|
|
|
/**
|
|
|
|
* virCgroupSetMemory:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to change memory for
|
|
|
|
* @kb: The memory amount in kilobytes
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupSetMemory(virCgroupPtr group, unsigned long long kb)
|
2008-10-03 17:58:02 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
|
|
|
|
setMemory, -1, kb);
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2018-07-20 12:47:11 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetMemoryStat:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to change memory for
|
|
|
|
* @cache: page cache memory in KiB
|
|
|
|
* @activeAnon: anonymous and swap cache memory in KiB
|
|
|
|
* @inactiveAnon: anonymous and swap cache memory in KiB
|
|
|
|
* @activeFile: file-backed memory in KiB
|
|
|
|
* @inactiveFile: file-backed memory in KiB
|
|
|
|
* @unevictable: memory that cannot be reclaimed KiB
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on error
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupGetMemoryStat(virCgroupPtr group,
|
|
|
|
unsigned long long *cache,
|
|
|
|
unsigned long long *activeAnon,
|
|
|
|
unsigned long long *inactiveAnon,
|
|
|
|
unsigned long long *activeFile,
|
|
|
|
unsigned long long *inactiveFile,
|
|
|
|
unsigned long long *unevictable)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
|
|
|
|
getMemoryStat, -1, cache,
|
2018-08-17 13:55:47 +00:00
|
|
|
activeAnon, inactiveAnon,
|
|
|
|
activeFile, inactiveFile,
|
|
|
|
unevictable);
|
2018-07-20 12:47:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-07 13:26:23 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetMemoryUsage:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to change memory for
|
|
|
|
* @kb: Pointer to returned used memory in kilobytes
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb)
|
2009-10-07 13:26:23 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
|
|
|
|
getMemoryUsage, -1, kb);
|
2009-10-07 13:26:23 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2010-10-12 14:50:53 +00:00
|
|
|
/**
|
|
|
|
* virCgroupSetMemoryHardLimit:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to change memory hard limit for
|
|
|
|
* @kb: The memory amount in kilobytes
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long long kb)
|
2010-10-12 14:50:53 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
|
|
|
|
setMemoryHardLimit, -1, kb);
|
2010-10-12 14:50:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2010-10-12 14:50:53 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetMemoryHardLimit:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to get the memory hard limit for
|
|
|
|
* @kb: The memory amount in kilobytes
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long long *kb)
|
2010-10-12 14:50:53 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
|
|
|
|
getMemoryHardLimit, -1, kb);
|
2010-10-12 14:50:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2010-10-12 14:50:53 +00:00
|
|
|
/**
|
|
|
|
* virCgroupSetMemorySoftLimit:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to change memory soft limit for
|
|
|
|
* @kb: The memory amount in kilobytes
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long long kb)
|
2010-10-12 14:50:53 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
|
|
|
|
setMemorySoftLimit, -1, kb);
|
2010-10-12 14:50:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupGetMemorySoftLimit:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to get the memory soft limit for
|
|
|
|
* @kb: The memory amount in kilobytes
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long long *kb)
|
2010-10-12 14:50:53 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
|
|
|
|
getMemorySoftLimit, -1, kb);
|
2010-10-12 14:50:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2010-10-12 14:50:53 +00:00
|
|
|
/**
|
2011-03-16 05:07:12 +00:00
|
|
|
* virCgroupSetMemSwapHardLimit:
|
2010-10-12 14:50:53 +00:00
|
|
|
*
|
2011-03-16 05:07:12 +00:00
|
|
|
* @group: The cgroup to change mem+swap hard limit for
|
|
|
|
* @kb: The mem+swap amount in kilobytes
|
2010-10-12 14:50:53 +00:00
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupSetMemSwapHardLimit(virCgroupPtr group, unsigned long long kb)
|
2010-10-12 14:50:53 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
|
|
|
|
setMemSwapHardLimit, -1, kb);
|
2010-10-12 14:50:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2010-10-12 14:50:53 +00:00
|
|
|
/**
|
2011-03-16 05:07:12 +00:00
|
|
|
* virCgroupGetMemSwapHardLimit:
|
2010-10-12 14:50:53 +00:00
|
|
|
*
|
2011-03-16 05:07:12 +00:00
|
|
|
* @group: The cgroup to get mem+swap hard limit for
|
|
|
|
* @kb: The mem+swap amount in kilobytes
|
2010-10-12 14:50:53 +00:00
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb)
|
2010-10-12 14:50:53 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
|
|
|
|
getMemSwapHardLimit, -1, kb);
|
2010-10-12 14:50:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2012-11-12 07:02:25 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetMemSwapUsage:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to get mem+swap usage for
|
|
|
|
* @kb: The mem+swap amount in kilobytes
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb)
|
2012-11-12 07:02:25 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
|
|
|
|
getMemSwapUsage, -1, kb);
|
2012-11-12 07:02:25 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2011-12-20 08:34:58 +00:00
|
|
|
/**
|
|
|
|
* virCgroupSetCpusetMems:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to set cpuset.mems for
|
|
|
|
* @mems: the numa nodes to set
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupSetCpusetMems(virCgroupPtr group, const char *mems)
|
2011-12-20 08:34:58 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
|
|
|
|
setCpusetMems, -1, mems);
|
2011-12-20 08:34:58 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2011-12-20 08:34:58 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetCpusetMems:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to get cpuset.mems for
|
|
|
|
* @mems: the numa nodes to get
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupGetCpusetMems(virCgroupPtr group, char **mems)
|
2011-12-20 08:34:58 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
|
|
|
|
getCpusetMems, -1, mems);
|
2011-12-20 08:34:58 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2015-03-11 10:15:29 +00:00
|
|
|
/**
|
|
|
|
* virCgroupSetCpusetMemoryMigrate:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to set cpuset.memory_migrate for
|
|
|
|
* @migrate: Whether to migrate the memory on change or not
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupSetCpusetMemoryMigrate(virCgroupPtr group, bool migrate)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
|
|
|
|
setCpusetMemoryMigrate, -1, migrate);
|
2015-03-11 10:15:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupGetCpusetMemoryMigrate:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to get cpuset.memory_migrate for
|
|
|
|
* @migrate: Migration setting
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupGetCpusetMemoryMigrate(virCgroupPtr group, bool *migrate)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
|
|
|
|
getCpusetMemoryMigrate, -1, migrate);
|
2015-03-11 10:15:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-21 09:18:30 +00:00
|
|
|
/**
|
|
|
|
* virCgroupSetCpusetCpus:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to set cpuset.cpus for
|
|
|
|
* @cpus: the cpus to set
|
|
|
|
*
|
2016-11-15 14:00:08 +00:00
|
|
|
* Returns: 0 on success
|
2012-08-21 09:18:30 +00:00
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupSetCpusetCpus(virCgroupPtr group, const char *cpus)
|
2012-08-21 09:18:30 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
|
|
|
|
setCpusetCpus, -1, cpus);
|
2012-08-21 09:18:30 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2012-08-21 09:18:30 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetCpusetCpus:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to get cpuset.cpus for
|
|
|
|
* @cpus: the cpus to get
|
|
|
|
*
|
2016-11-15 14:00:08 +00:00
|
|
|
* Returns: 0 on success
|
2012-08-21 09:18:30 +00:00
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupGetCpusetCpus(virCgroupPtr group, char **cpus)
|
2012-08-21 09:18:30 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
|
|
|
|
getCpusetCpus, -1, cpus);
|
2012-08-21 09:18:30 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2008-10-03 17:58:02 +00:00
|
|
|
/**
|
|
|
|
* virCgroupDenyAllDevices:
|
|
|
|
*
|
2011-03-09 03:13:18 +00:00
|
|
|
* @group: The cgroup to deny all permissions, for all devices
|
2008-10-03 17:58:02 +00:00
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupDenyAllDevices(virCgroupPtr group)
|
2008-10-03 17:58:02 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
|
|
|
|
denyAllDevices, -1);
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
|
|
|
|
2014-07-18 08:02:29 +00:00
|
|
|
/**
|
|
|
|
* virCgroupAllowAllDevices:
|
|
|
|
*
|
2018-12-04 17:08:14 +00:00
|
|
|
* Allows the permission for all devices by setting lines similar
|
2014-07-18 08:02:29 +00:00
|
|
|
* to these ones (obviously the 'm' permission is an example):
|
|
|
|
*
|
|
|
|
* 'b *:* m'
|
|
|
|
* 'c *:* m'
|
|
|
|
*
|
|
|
|
* @group: The cgroup to allow devices for
|
|
|
|
* @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupAllowAllDevices(virCgroupPtr group, int perms)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
|
|
|
|
allowAllDevices, -1, perms);
|
2014-07-18 08:02:29 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2008-10-03 17:58:02 +00:00
|
|
|
/**
|
|
|
|
* virCgroupAllowDevice:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to allow a device for
|
|
|
|
* @type: The device type (i.e., 'c' or 'b')
|
2014-07-18 08:02:29 +00:00
|
|
|
* @major: The major number of the device, a negative value means '*'
|
|
|
|
* @minor: The minor number of the device, a negative value means '*'
|
2011-03-09 03:13:18 +00:00
|
|
|
* @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow
|
2008-10-03 17:58:02 +00:00
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupAllowDevice(virCgroupPtr group, char type, int major, int minor,
|
|
|
|
int perms)
|
2008-10-03 17:58:02 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
|
|
|
|
allowDevice, -1, type, major, minor, perms);
|
2008-10-03 17:58:02 +00:00
|
|
|
}
|
2008-10-08 16:28:48 +00:00
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2009-07-09 13:11:49 +00:00
|
|
|
/**
|
|
|
|
* virCgroupAllowDevicePath:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to allow the device for
|
|
|
|
* @path: the device to allow
|
2011-03-09 03:13:18 +00:00
|
|
|
* @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow
|
2016-02-16 13:43:41 +00:00
|
|
|
* @ignoreEacces: Ignore lack of permission (mostly for NFS mounts)
|
2009-07-09 13:11:49 +00:00
|
|
|
*
|
|
|
|
* Queries the type of device and its major/minor number, and
|
|
|
|
* adds that to the cgroup ACL
|
|
|
|
*
|
2016-02-16 13:43:41 +00:00
|
|
|
* Returns: 0 on success, 1 if path exists but is not a device or is not
|
2018-12-04 17:08:14 +00:00
|
|
|
* accessible, or * -1 on error
|
2009-07-09 13:11:49 +00:00
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
2016-02-16 13:43:41 +00:00
|
|
|
virCgroupAllowDevicePath(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
int perms,
|
|
|
|
bool ignoreEacces)
|
2009-07-09 13:11:49 +00:00
|
|
|
{
|
|
|
|
struct stat sb;
|
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
if (stat(path, &sb) < 0) {
|
2016-02-16 13:43:41 +00:00
|
|
|
if (errno == EACCES && ignoreEacces)
|
|
|
|
return 1;
|
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Path '%s' is not accessible"),
|
|
|
|
path);
|
|
|
|
return -1;
|
|
|
|
}
|
2009-07-09 13:11:49 +00:00
|
|
|
|
|
|
|
if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode))
|
2011-02-17 00:05:54 +00:00
|
|
|
return 1;
|
2009-07-09 13:11:49 +00:00
|
|
|
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
|
|
|
|
allowDevice, -1,
|
2018-09-05 18:08:48 +00:00
|
|
|
S_ISCHR(sb.st_mode) ? 'c' : 'b',
|
|
|
|
major(sb.st_rdev),
|
|
|
|
minor(sb.st_rdev),
|
|
|
|
perms);
|
2009-07-09 13:11:49 +00:00
|
|
|
}
|
2009-10-07 10:18:31 +00:00
|
|
|
|
2009-07-09 13:11:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupDenyDevice:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to deny a device for
|
|
|
|
* @type: The device type (i.e., 'c' or 'b')
|
2016-02-16 13:01:25 +00:00
|
|
|
* @major: The major number of the device, a negative value means '*'
|
|
|
|
* @minor: The minor number of the device, a negative value means '*'
|
2011-03-09 03:13:18 +00:00
|
|
|
* @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to deny
|
2009-07-09 13:11:49 +00:00
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupDenyDevice(virCgroupPtr group, char type, int major, int minor,
|
|
|
|
int perms)
|
2009-07-09 13:11:49 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
|
|
|
|
denyDevice, -1, type, major, minor, perms);
|
2009-07-09 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2016-02-16 13:43:41 +00:00
|
|
|
/**
|
|
|
|
* virCgroupDenyDevicePath:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to deny the device for
|
|
|
|
* @path: the device to deny
|
|
|
|
* @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow
|
|
|
|
* @ignoreEacces: Ignore lack of permission (mostly for NFS mounts)
|
|
|
|
*
|
|
|
|
* Queries the type of device and its major/minor number, and
|
|
|
|
* removes it from the cgroup ACL
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, 1 if path exists but is not a device or is not
|
|
|
|
* accessible, or -1 on error.
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
2016-02-16 13:43:41 +00:00
|
|
|
virCgroupDenyDevicePath(virCgroupPtr group,
|
|
|
|
const char *path,
|
|
|
|
int perms,
|
|
|
|
bool ignoreEacces)
|
2009-07-09 13:11:49 +00:00
|
|
|
{
|
|
|
|
struct stat sb;
|
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
if (stat(path, &sb) < 0) {
|
2016-02-16 13:43:41 +00:00
|
|
|
if (errno == EACCES && ignoreEacces)
|
|
|
|
return 1;
|
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Path '%s' is not accessible"),
|
|
|
|
path);
|
|
|
|
return -1;
|
|
|
|
}
|
2009-07-09 13:11:49 +00:00
|
|
|
|
|
|
|
if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode))
|
2011-02-17 00:05:54 +00:00
|
|
|
return 1;
|
2009-07-09 13:11:49 +00:00
|
|
|
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
|
|
|
|
denyDevice, -1,
|
2018-09-05 18:08:48 +00:00
|
|
|
S_ISCHR(sb.st_mode) ? 'c' : 'b',
|
|
|
|
major(sb.st_rdev),
|
|
|
|
minor(sb.st_rdev),
|
|
|
|
perms);
|
2009-07-09 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2014-04-03 15:53:43 +00:00
|
|
|
/* This function gets the sums of cpu time consumed by all vcpus.
|
|
|
|
* For example, if there are 4 physical cpus, and 2 vcpus in a domain,
|
|
|
|
* then for each vcpu, the cpuacct.usage_percpu looks like this:
|
|
|
|
* t0 t1 t2 t3
|
|
|
|
* and we have 2 groups of such data:
|
|
|
|
* v\p 0 1 2 3
|
|
|
|
* 0 t00 t01 t02 t03
|
|
|
|
* 1 t10 t11 t12 t13
|
|
|
|
* for each pcpu, the sum is cpu time consumed by all vcpus.
|
|
|
|
* s0 = t00 + t10
|
|
|
|
* s1 = t01 + t11
|
|
|
|
* s2 = t02 + t12
|
|
|
|
* s3 = t03 + t13
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virCgroupGetPercpuVcpuSum(virCgroupPtr group,
|
2015-12-14 14:10:22 +00:00
|
|
|
virBitmapPtr guestvcpus,
|
2014-04-03 15:53:43 +00:00
|
|
|
unsigned long long *sum_cpu_time,
|
2015-01-22 10:54:50 +00:00
|
|
|
size_t nsum,
|
|
|
|
virBitmapPtr cpumap)
|
2014-04-03 15:53:43 +00:00
|
|
|
{
|
2015-12-14 14:10:22 +00:00
|
|
|
ssize_t i = -1;
|
2014-04-03 15:53:43 +00:00
|
|
|
|
2015-12-14 14:10:22 +00:00
|
|
|
while ((i = virBitmapNextSetBit(guestvcpus, i)) >= 0) {
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *buf = NULL;
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) group_vcpu = NULL;
|
2014-04-03 15:53:43 +00:00
|
|
|
char *pos;
|
|
|
|
unsigned long long tmp;
|
2015-01-22 10:54:50 +00:00
|
|
|
ssize_t j;
|
2014-04-03 15:53:43 +00:00
|
|
|
|
2015-04-07 12:53:35 +00:00
|
|
|
if (virCgroupNewThread(group, VIR_CGROUP_THREAD_VCPU, i,
|
|
|
|
false, &group_vcpu) < 0)
|
2020-10-09 14:09:46 +00:00
|
|
|
return -1;
|
2014-04-03 15:53:43 +00:00
|
|
|
|
|
|
|
if (virCgroupGetCpuacctPercpuUsage(group_vcpu, &buf) < 0)
|
2020-10-09 14:09:46 +00:00
|
|
|
return -1;
|
2014-04-03 15:53:43 +00:00
|
|
|
|
|
|
|
pos = buf;
|
2015-01-22 10:54:50 +00:00
|
|
|
for (j = virBitmapNextSetBit(cpumap, -1);
|
|
|
|
j >= 0 && j < nsum;
|
|
|
|
j = virBitmapNextSetBit(cpumap, j)) {
|
2014-04-03 15:53:43 +00:00
|
|
|
if (virStrToLong_ull(pos, &pos, 10, &tmp) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cpuacct parse error"));
|
2020-10-09 14:09:46 +00:00
|
|
|
return -1;
|
2014-04-03 15:53:43 +00:00
|
|
|
}
|
|
|
|
sum_cpu_time[j] += tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
return 0;
|
2014-04-03 15:53:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-07 06:39:34 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetPercpuStats:
|
|
|
|
* @cgroup: cgroup data structure
|
|
|
|
* @params: typed parameter array where data is returned
|
|
|
|
* @nparams: cardinality of @params
|
|
|
|
* @start_cpu: offset of physical CPU to get data for
|
|
|
|
* @ncpus: number of physical CPUs to get data for
|
|
|
|
* @nvcpupids: number of vCPU threads for a domain (actual number of vcpus)
|
|
|
|
*
|
|
|
|
* This function is the worker that retrieves data in the appropriate format
|
|
|
|
* for the terribly designed 'virDomainGetCPUStats' API. Sharing semantics with
|
|
|
|
* the API, this function has two modes of operation depending on magic settings
|
|
|
|
* of the input arguments. Please refer to docs of 'virDomainGetCPUStats' for
|
|
|
|
* the usage patterns of the similarly named arguments.
|
|
|
|
*
|
|
|
|
* @nvcpupids determines the count of active vcpu threads for the vm. If the
|
|
|
|
* threads could not be detected the percpu data is skipped.
|
|
|
|
*
|
|
|
|
* Please DON'T use this function anywhere else.
|
|
|
|
*/
|
2014-02-14 17:49:02 +00:00
|
|
|
int
|
|
|
|
virCgroupGetPercpuStats(virCgroupPtr group,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
unsigned int nparams,
|
|
|
|
int start_cpu,
|
2014-04-03 15:53:43 +00:00
|
|
|
unsigned int ncpus,
|
2015-12-14 14:10:22 +00:00
|
|
|
virBitmapPtr guestvcpus)
|
2014-02-14 17:49:02 +00:00
|
|
|
{
|
2018-07-30 09:03:16 +00:00
|
|
|
int ret = -1;
|
2014-02-14 17:49:02 +00:00
|
|
|
size_t i;
|
2014-04-03 17:53:13 +00:00
|
|
|
int need_cpus, total_cpus;
|
2014-02-14 17:49:02 +00:00
|
|
|
char *pos;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *buf = NULL;
|
|
|
|
g_autofree unsigned long long *sum_cpu_time = NULL;
|
2014-02-14 17:49:02 +00:00
|
|
|
virTypedParameterPtr ent;
|
|
|
|
int param_idx;
|
|
|
|
unsigned long long cpu_time;
|
2018-07-30 09:03:16 +00:00
|
|
|
virBitmapPtr cpumap = NULL;
|
2014-02-14 17:49:02 +00:00
|
|
|
|
|
|
|
/* return the number of supported params */
|
2014-04-03 15:53:43 +00:00
|
|
|
if (nparams == 0 && ncpus != 0) {
|
2015-12-14 14:10:22 +00:00
|
|
|
if (!guestvcpus)
|
2014-04-03 15:53:43 +00:00
|
|
|
return CGROUP_NB_PER_CPU_STAT_PARAM;
|
|
|
|
else
|
|
|
|
return CGROUP_NB_PER_CPU_STAT_PARAM + 1;
|
|
|
|
}
|
2014-02-14 17:49:02 +00:00
|
|
|
|
|
|
|
/* To parse account file, we need to know how many cpus are present. */
|
2016-04-13 17:16:16 +00:00
|
|
|
if (!(cpumap = virHostCPUGetPresentBitmap()))
|
2015-12-07 06:39:34 +00:00
|
|
|
return -1;
|
2014-02-14 17:49:02 +00:00
|
|
|
|
2015-01-22 10:54:50 +00:00
|
|
|
total_cpus = virBitmapSize(cpumap);
|
|
|
|
|
2015-12-07 06:39:34 +00:00
|
|
|
/* return total number of cpus */
|
2018-07-30 09:03:16 +00:00
|
|
|
if (ncpus == 0) {
|
|
|
|
ret = total_cpus;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-02-14 17:49:02 +00:00
|
|
|
|
2014-04-03 17:38:54 +00:00
|
|
|
if (start_cpu >= total_cpus) {
|
2014-02-14 17:49:02 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("start_cpu %d larger than maximum of %d"),
|
2014-04-03 17:38:54 +00:00
|
|
|
start_cpu, total_cpus - 1);
|
2018-07-30 09:03:16 +00:00
|
|
|
goto cleanup;
|
2014-02-14 17:49:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* we get percpu cputime accounting info. */
|
|
|
|
if (virCgroupGetCpuacctPercpuUsage(group, &buf))
|
2018-07-30 09:03:16 +00:00
|
|
|
goto cleanup;
|
2014-02-14 17:49:02 +00:00
|
|
|
pos = buf;
|
|
|
|
|
|
|
|
/* return percpu cputime in index 0 */
|
|
|
|
param_idx = 0;
|
|
|
|
|
|
|
|
/* number of cpus to compute */
|
2014-04-03 17:23:25 +00:00
|
|
|
need_cpus = MIN(total_cpus, start_cpu + ncpus);
|
2014-02-14 17:49:02 +00:00
|
|
|
|
2014-04-03 17:23:25 +00:00
|
|
|
for (i = 0; i < need_cpus; i++) {
|
2015-03-11 15:41:57 +00:00
|
|
|
if (!virBitmapIsBitSet(cpumap, i)) {
|
2015-01-22 10:54:50 +00:00
|
|
|
cpu_time = 0;
|
|
|
|
} else if (virStrToLong_ull(pos, &pos, 10, &cpu_time) < 0) {
|
2014-02-14 17:49:02 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cpuacct parse error"));
|
2018-07-30 09:03:16 +00:00
|
|
|
goto cleanup;
|
2014-02-14 17:49:02 +00:00
|
|
|
}
|
|
|
|
if (i < start_cpu)
|
|
|
|
continue;
|
|
|
|
ent = ¶ms[(i - start_cpu) * nparams + param_idx];
|
|
|
|
if (virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
|
2018-07-30 09:03:16 +00:00
|
|
|
goto cleanup;
|
2014-02-14 17:49:02 +00:00
|
|
|
}
|
|
|
|
|
2014-04-03 15:53:43 +00:00
|
|
|
/* return percpu vcputime in index 1 */
|
2015-12-07 06:39:34 +00:00
|
|
|
param_idx = 1;
|
2014-04-03 15:53:43 +00:00
|
|
|
|
2015-12-14 14:10:22 +00:00
|
|
|
if (guestvcpus && param_idx < nparams) {
|
2020-10-05 17:12:37 +00:00
|
|
|
sum_cpu_time = g_new0(unsigned long long, need_cpus);
|
2015-12-14 14:10:22 +00:00
|
|
|
if (virCgroupGetPercpuVcpuSum(group, guestvcpus, sum_cpu_time,
|
|
|
|
need_cpus, cpumap) < 0)
|
2018-07-30 09:03:16 +00:00
|
|
|
goto cleanup;
|
2015-12-07 06:39:34 +00:00
|
|
|
|
|
|
|
for (i = start_cpu; i < need_cpus; i++) {
|
2018-09-19 08:38:14 +00:00
|
|
|
int idx = (i - start_cpu) * nparams + param_idx;
|
|
|
|
if (virTypedParameterAssign(¶ms[idx],
|
2015-12-07 06:39:34 +00:00
|
|
|
VIR_DOMAIN_CPU_STATS_VCPUTIME,
|
|
|
|
VIR_TYPED_PARAM_ULLONG,
|
|
|
|
sum_cpu_time[i]) < 0)
|
2018-07-30 09:03:16 +00:00
|
|
|
goto cleanup;
|
2015-12-07 06:39:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
param_idx++;
|
2014-04-03 15:53:43 +00:00
|
|
|
}
|
|
|
|
|
2018-07-30 09:03:16 +00:00
|
|
|
ret = param_idx;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virBitmapFree(cpumap);
|
|
|
|
return ret;
|
2014-02-14 17:49:02 +00:00
|
|
|
}
|
|
|
|
|
2014-02-14 17:49:01 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupGetDomainTotalCpuStats(virCgroupPtr group,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int nparams)
|
|
|
|
{
|
|
|
|
unsigned long long cpu_time;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (nparams == 0) /* return supported number of params */
|
|
|
|
return CGROUP_NB_TOTAL_CPU_STAT_PARAM;
|
|
|
|
/* entry 0 is cputime */
|
|
|
|
ret = virCgroupGetCpuacctUsage(group, &cpu_time);
|
|
|
|
if (ret < 0) {
|
|
|
|
virReportSystemError(-ret, "%s", _("unable to get cpu account"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virTypedParameterAssign(¶ms[0], VIR_DOMAIN_CPU_STATS_CPUTIME,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (nparams > 1) {
|
|
|
|
unsigned long long user;
|
|
|
|
unsigned long long sys;
|
|
|
|
|
|
|
|
ret = virCgroupGetCpuacctStat(group, &user, &sys);
|
|
|
|
if (ret < 0) {
|
|
|
|
virReportSystemError(-ret, "%s", _("unable to get cpu account"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virTypedParameterAssign(¶ms[1],
|
|
|
|
VIR_DOMAIN_CPU_STATS_USERTIME,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, user) < 0)
|
|
|
|
return -1;
|
|
|
|
if (nparams > 2 &&
|
|
|
|
virTypedParameterAssign(¶ms[2],
|
|
|
|
VIR_DOMAIN_CPU_STATS_SYSTEMTIME,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, sys) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (nparams > CGROUP_NB_TOTAL_CPU_STAT_PARAM)
|
|
|
|
nparams = CGROUP_NB_TOTAL_CPU_STAT_PARAM;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nparams;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares)
|
2008-10-08 16:28:48 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
|
|
|
|
setCpuShares, -1, shares);
|
2008-10-08 16:28:48 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares)
|
2008-10-08 16:28:48 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
|
|
|
|
getCpuShares, -1, shares);
|
2008-10-08 16:28:48 +00:00
|
|
|
}
|
2009-03-06 14:44:04 +00:00
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2011-07-21 07:21:05 +00:00
|
|
|
/**
|
|
|
|
* virCgroupSetCpuCfsPeriod:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to change cpu.cfs_period_us for
|
|
|
|
* @cfs_period: The bandwidth period in usecs
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupSetCpuCfsPeriod(virCgroupPtr group, unsigned long long cfs_period)
|
2011-07-21 07:21:05 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
|
|
|
|
setCpuCfsPeriod, -1, cfs_period);
|
2011-07-21 07:21:05 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2011-07-21 07:21:05 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetCpuCfsPeriod:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to get cpu.cfs_period_us for
|
|
|
|
* @cfs_period: Pointer to the returned bandwidth period in usecs
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupGetCpuCfsPeriod(virCgroupPtr group, unsigned long long *cfs_period)
|
2011-07-21 07:21:05 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
|
|
|
|
getCpuCfsPeriod, -1, cfs_period);
|
2011-07-21 07:21:05 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2011-07-21 07:21:05 +00:00
|
|
|
/**
|
|
|
|
* virCgroupSetCpuCfsQuota:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to change cpu.cfs_quota_us for
|
|
|
|
* @cfs_quota: the cpu bandwidth (in usecs) that this tg will be allowed to
|
|
|
|
* consume over period
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupSetCpuCfsQuota(virCgroupPtr group, long long cfs_quota)
|
2011-07-21 07:21:05 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
|
|
|
|
setCpuCfsQuota, -1, cfs_quota);
|
2011-07-21 07:21:05 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupGetCpuacctPercpuUsage(virCgroupPtr group, char **usage)
|
2012-03-02 02:54:23 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT,
|
|
|
|
getCpuacctPercpuUsage, -1, usage);
|
2012-03-02 02:54:23 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2018-08-17 08:02:05 +00:00
|
|
|
int
|
2013-08-12 21:20:59 +00:00
|
|
|
virCgroupRemoveRecursively(char *grppath)
|
|
|
|
{
|
2020-10-25 21:50:51 +00:00
|
|
|
g_autoptr(DIR) grpdir = NULL;
|
2013-08-12 21:20:59 +00:00
|
|
|
struct dirent *ent;
|
|
|
|
int rc = 0;
|
2014-04-25 20:45:49 +00:00
|
|
|
int direrr;
|
2013-08-12 21:20:59 +00:00
|
|
|
|
2016-06-21 14:52:37 +00:00
|
|
|
if (virDirOpenQuiet(&grpdir, grppath) < 0) {
|
2013-08-12 21:20:59 +00:00
|
|
|
if (errno == ENOENT)
|
|
|
|
return 0;
|
|
|
|
rc = -errno;
|
|
|
|
VIR_ERROR(_("Unable to open %s (%d)"), grppath, errno);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2014-04-25 20:45:49 +00:00
|
|
|
/* This is best-effort cleanup: we want to log failures with just
|
|
|
|
* VIR_ERROR instead of normal virReportError */
|
|
|
|
while ((direrr = virDirRead(grpdir, &ent, NULL)) > 0) {
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *path = NULL;
|
2013-08-12 21:20:59 +00:00
|
|
|
|
|
|
|
if (ent->d_type != DT_DIR) continue;
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
path = g_strdup_printf("%s/%s", grppath, ent->d_name);
|
|
|
|
|
2013-08-12 21:20:59 +00:00
|
|
|
rc = virCgroupRemoveRecursively(path);
|
|
|
|
if (rc != 0)
|
|
|
|
break;
|
|
|
|
}
|
2014-04-25 20:45:49 +00:00
|
|
|
if (direrr < 0) {
|
|
|
|
rc = -errno;
|
|
|
|
VIR_ERROR(_("Failed to readdir for %s (%d)"), grppath, errno);
|
|
|
|
}
|
|
|
|
|
2013-08-12 21:20:59 +00:00
|
|
|
VIR_DEBUG("Removing cgroup %s", grppath);
|
|
|
|
if (rmdir(grppath) != 0 && errno != ENOENT) {
|
|
|
|
rc = -errno;
|
|
|
|
VIR_ERROR(_("Unable to remove %s (%d)"), grppath, errno);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCgroupRemove:
|
|
|
|
*
|
|
|
|
* @group: The group to be removed
|
|
|
|
*
|
|
|
|
* It first removes all child groups recursively
|
|
|
|
* in depth first order and then removes @group
|
|
|
|
* because the presence of the child groups
|
|
|
|
* prevents removing @group.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupRemove(virCgroupPtr group)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
2019-07-19 03:19:38 +00:00
|
|
|
if (group->backends[i]) {
|
|
|
|
int rc = group->backends[i]->remove(group);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
2018-09-28 17:53:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2013-08-12 21:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-19 14:43:04 +00:00
|
|
|
/*
|
|
|
|
* Returns 1 if some PIDs are killed, 0 if none are killed, or -1 on error
|
|
|
|
*/
|
2013-08-12 19:52:06 +00:00
|
|
|
static int
|
2018-12-10 08:51:14 +00:00
|
|
|
virCgroupKillInternal(virCgroupPtr group,
|
|
|
|
int signum,
|
2020-10-20 15:01:51 +00:00
|
|
|
GHashTable *pids,
|
2018-12-10 08:51:14 +00:00
|
|
|
int controller,
|
|
|
|
const char *taskFile)
|
2011-02-22 17:33:59 +00:00
|
|
|
{
|
2013-07-19 14:43:04 +00:00
|
|
|
int ret = -1;
|
2013-05-24 10:14:02 +00:00
|
|
|
bool killedAny = false;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *keypath = NULL;
|
2011-02-22 17:33:59 +00:00
|
|
|
bool done = false;
|
cgroup: avoid leaking a file
Clang detected a dead store to rc. It turns out that in fixing this,
I also found a FILE* leak.
This is a subtle change in behavior, although unlikely to hit. The
pidfile is a kernel file, so we've probably got more serious problems
under foot if we fail to parse one. However, the previous behavior
was that even if one pid file failed to parse, we tried others,
whereas now we give up on the first failure. Either way, though,
the function returns -1, so the caller will know that something is
going wrong, and that not all pids were necessarily reaped. Besides,
there were other instances already in the code where failure in the
inner loop aborted the outer loop.
* src/util/cgroup.c (virCgroupKillInternal): Abort rather than
resuming loop on fscanf failure, and cleanup file on error.
2011-05-03 21:46:06 +00:00
|
|
|
FILE *fp = NULL;
|
2020-10-14 08:29:45 +00:00
|
|
|
VIR_DEBUG("group=%p signum=%d pids=%p",
|
|
|
|
group, signum, pids);
|
2011-02-22 17:33:59 +00:00
|
|
|
|
2018-12-10 08:51:14 +00:00
|
|
|
if (virCgroupPathOfController(group, controller, taskFile, &keypath) < 0)
|
2013-07-19 14:43:04 +00:00
|
|
|
return -1;
|
2011-02-22 17:33:59 +00:00
|
|
|
|
|
|
|
/* PIDs may be forking as we kill them, so loop
|
|
|
|
* until there are no new PIDs found
|
|
|
|
*/
|
|
|
|
while (!done) {
|
|
|
|
done = true;
|
|
|
|
if (!(fp = fopen(keypath, "r"))) {
|
2013-07-26 15:02:22 +00:00
|
|
|
if (errno == ENOENT) {
|
|
|
|
VIR_DEBUG("No file %s, assuming done", keypath);
|
|
|
|
killedAny = false;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2013-07-19 14:43:04 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to read %s"),
|
|
|
|
keypath);
|
2011-02-22 17:33:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
while (!feof(fp)) {
|
2020-10-20 15:01:51 +00:00
|
|
|
g_autofree long long *pid_value = g_new0(long long, 1);
|
|
|
|
|
|
|
|
if (fscanf(fp, "%lld", pid_value) != 1) {
|
2011-02-22 17:33:59 +00:00
|
|
|
if (feof(fp))
|
|
|
|
break;
|
2013-07-19 14:43:04 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to read %s"),
|
|
|
|
keypath);
|
cgroup: avoid leaking a file
Clang detected a dead store to rc. It turns out that in fixing this,
I also found a FILE* leak.
This is a subtle change in behavior, although unlikely to hit. The
pidfile is a kernel file, so we've probably got more serious problems
under foot if we fail to parse one. However, the previous behavior
was that even if one pid file failed to parse, we tried others,
whereas now we give up on the first failure. Either way, though,
the function returns -1, so the caller will know that something is
going wrong, and that not all pids were necessarily reaped. Besides,
there were other instances already in the code where failure in the
inner loop aborted the outer loop.
* src/util/cgroup.c (virCgroupKillInternal): Abort rather than
resuming loop on fscanf failure, and cleanup file on error.
2011-05-03 21:46:06 +00:00
|
|
|
goto cleanup;
|
2011-02-22 17:33:59 +00:00
|
|
|
}
|
2020-10-20 15:01:51 +00:00
|
|
|
|
|
|
|
if (g_hash_table_lookup(pids, pid_value))
|
2011-02-22 17:33:59 +00:00
|
|
|
continue;
|
|
|
|
|
2020-10-20 15:01:51 +00:00
|
|
|
VIR_DEBUG("pid=%lld", *pid_value);
|
build: use correct type for pid and similar types
No thanks to 64-bit windows, with 64-bit pid_t, we have to avoid
constructs like 'int pid'. Our API in libvirt-qemu cannot be
changed without breaking ABI; but then again, libvirt-qemu can
only be used on systems that support UNIX sockets, which rules
out Windows (even if qemu could be compiled there) - so for all
points on the call chain that interact with this API decision,
we require a different variable name to make it clear that we
audited the use for safety.
Adding a syntax-check rule only solves half the battle; anywhere
that uses printf on a pid_t still needs to be converted, but that
will be a separate patch.
* cfg.mk (sc_correct_id_types): New syntax check.
* src/libvirt-qemu.c (virDomainQemuAttach): Document why we didn't
use pid_t for pid, and validate for overflow.
* include/libvirt/libvirt-qemu.h (virDomainQemuAttach): Tweak name
for syntax check.
* src/vmware/vmware_conf.c (vmwareExtractPid): Likewise.
* src/driver.h (virDrvDomainQemuAttach): Likewise.
* tools/virsh.c (cmdQemuAttach): Likewise.
* src/remote/qemu_protocol.x (qemu_domain_attach_args): Likewise.
* src/qemu_protocol-structs (qemu_domain_attach_args): Likewise.
* src/util/cgroup.c (virCgroupPidCode, virCgroupKillInternal):
Likewise.
* src/qemu/qemu_command.c(qemuParseProcFileStrings): Likewise.
(qemuParseCommandLinePid): Use pid_t for pid.
* daemon/libvirtd.c (daemonForkIntoBackground): Likewise.
* src/conf/domain_conf.h (_virDomainObj): Likewise.
* src/probes.d (rpc_socket_new): Likewise.
* src/qemu/qemu_command.h (qemuParseCommandLinePid): Likewise.
* src/qemu/qemu_driver.c (qemudGetProcessInfo, qemuDomainAttach):
Likewise.
* src/qemu/qemu_process.c (qemuProcessAttach): Likewise.
* src/qemu/qemu_process.h (qemuProcessAttach): Likewise.
* src/uml/uml_driver.c (umlGetProcessInfo): Likewise.
* src/util/virnetdev.h (virNetDevSetNamespace): Likewise.
* src/util/virnetdev.c (virNetDevSetNamespace): Likewise.
* tests/testutils.c (virtTestCaptureProgramOutput): Likewise.
* src/conf/storage_conf.h (_virStoragePerms): Use mode_t, uid_t,
and gid_t rather than int.
* src/security/security_dac.c (virSecurityDACSetOwnership): Likewise.
* src/conf/storage_conf.c (virStorageDefParsePerms): Avoid
compiler warning.
2012-02-10 23:08:11 +00:00
|
|
|
/* Cgroups is a Linux concept, so this cast is safe. */
|
2020-10-20 15:01:51 +00:00
|
|
|
if (kill((pid_t)*pid_value, signum) < 0) {
|
2011-02-22 17:33:59 +00:00
|
|
|
if (errno != ESRCH) {
|
2013-07-19 14:43:04 +00:00
|
|
|
virReportSystemError(errno,
|
2020-10-20 15:01:51 +00:00
|
|
|
_("Failed to kill process %lld"),
|
|
|
|
*pid_value);
|
2011-02-22 17:33:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* Leave RC == 0 since we didn't kill one */
|
|
|
|
} else {
|
2013-05-24 10:14:02 +00:00
|
|
|
killedAny = true;
|
2011-02-22 17:33:59 +00:00
|
|
|
done = false;
|
|
|
|
}
|
|
|
|
|
2020-10-20 15:01:51 +00:00
|
|
|
g_hash_table_add(pids, g_steal_pointer(&pid_value));
|
2011-02-22 17:33:59 +00:00
|
|
|
}
|
|
|
|
VIR_FORCE_FCLOSE(fp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-26 15:02:22 +00:00
|
|
|
done:
|
2013-07-19 14:43:04 +00:00
|
|
|
ret = killedAny ? 1 : 0;
|
2011-02-22 17:33:59 +00:00
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
cgroup: avoid leaking a file
Clang detected a dead store to rc. It turns out that in fixing this,
I also found a FILE* leak.
This is a subtle change in behavior, although unlikely to hit. The
pidfile is a kernel file, so we've probably got more serious problems
under foot if we fail to parse one. However, the previous behavior
was that even if one pid file failed to parse, we tried others,
whereas now we give up on the first failure. Either way, though,
the function returns -1, so the caller will know that something is
going wrong, and that not all pids were necessarily reaped. Besides,
there were other instances already in the code where failure in the
inner loop aborted the outer loop.
* src/util/cgroup.c (virCgroupKillInternal): Abort rather than
resuming loop on fscanf failure, and cleanup file on error.
2011-05-03 21:46:06 +00:00
|
|
|
VIR_FORCE_FCLOSE(fp);
|
2011-02-22 17:33:59 +00:00
|
|
|
|
2013-07-19 14:43:04 +00:00
|
|
|
return ret;
|
2011-02-22 17:33:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-12-10 08:51:14 +00:00
|
|
|
int
|
2013-08-12 19:52:06 +00:00
|
|
|
virCgroupKillRecursiveInternal(virCgroupPtr group,
|
|
|
|
int signum,
|
2020-10-20 15:01:51 +00:00
|
|
|
GHashTable *pids,
|
2018-12-10 08:51:14 +00:00
|
|
|
int controller,
|
|
|
|
const char *taskFile,
|
2013-08-12 19:52:06 +00:00
|
|
|
bool dormdir)
|
2011-02-22 17:33:59 +00:00
|
|
|
{
|
|
|
|
int rc;
|
2013-07-19 14:43:04 +00:00
|
|
|
bool killedAny = false;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *keypath = NULL;
|
2020-10-25 21:50:51 +00:00
|
|
|
g_autoptr(DIR) dp = NULL;
|
2011-02-22 17:33:59 +00:00
|
|
|
struct dirent *ent;
|
2014-04-25 20:45:49 +00:00
|
|
|
int direrr;
|
2020-10-14 08:29:45 +00:00
|
|
|
VIR_DEBUG("group=%p signum=%d pids=%p",
|
|
|
|
group, signum, pids);
|
2011-02-22 17:33:59 +00:00
|
|
|
|
2018-12-10 08:51:14 +00:00
|
|
|
if (virCgroupPathOfController(group, controller, "", &keypath) < 0)
|
2013-07-19 14:43:04 +00:00
|
|
|
return -1;
|
2011-02-22 17:33:59 +00:00
|
|
|
|
2018-12-10 08:51:14 +00:00
|
|
|
if ((rc = virCgroupKillInternal(group, signum, pids,
|
|
|
|
controller, taskFile)) < 0) {
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2018-12-10 08:51:14 +00:00
|
|
|
}
|
2013-07-19 14:43:04 +00:00
|
|
|
if (rc == 1)
|
|
|
|
killedAny = true;
|
2011-02-22 17:33:59 +00:00
|
|
|
|
2013-07-26 15:02:22 +00:00
|
|
|
VIR_DEBUG("Iterate over children of %s (killedAny=%d)", keypath, killedAny);
|
2016-06-21 14:47:24 +00:00
|
|
|
if ((rc = virDirOpenIfExists(&dp, keypath)) < 0)
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2016-06-21 14:47:24 +00:00
|
|
|
|
|
|
|
if (rc == 0) {
|
|
|
|
VIR_DEBUG("Path %s does not exist, assuming done", keypath);
|
|
|
|
killedAny = false;
|
|
|
|
goto done;
|
2011-02-22 17:33:59 +00:00
|
|
|
}
|
|
|
|
|
2014-04-25 20:45:49 +00:00
|
|
|
while ((direrr = virDirRead(dp, &ent, keypath)) > 0) {
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) subgroup = NULL;
|
|
|
|
|
2011-02-22 17:33:59 +00:00
|
|
|
if (ent->d_type != DT_DIR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
VIR_DEBUG("Process subdir %s", ent->d_name);
|
|
|
|
|
2020-11-03 12:27:08 +00:00
|
|
|
if (virCgroupNewFromParent(group, ent->d_name, -1, &subgroup) < 0)
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2011-02-22 17:33:59 +00:00
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
if ((rc = virCgroupKillRecursiveInternal(subgroup, signum, pids,
|
2018-12-10 08:51:14 +00:00
|
|
|
controller, taskFile, true)) < 0)
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2011-02-22 17:33:59 +00:00
|
|
|
if (rc == 1)
|
2013-07-19 14:43:04 +00:00
|
|
|
killedAny = true;
|
2011-02-22 17:33:59 +00:00
|
|
|
|
|
|
|
if (dormdir)
|
|
|
|
virCgroupRemove(subgroup);
|
|
|
|
}
|
2014-04-25 20:45:49 +00:00
|
|
|
if (direrr < 0)
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2011-02-22 17:33:59 +00:00
|
|
|
|
2013-07-26 15:02:22 +00:00
|
|
|
done:
|
2020-10-27 21:49:11 +00:00
|
|
|
return killedAny ? 1 : 0;
|
2011-02-22 17:33:59 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupKillRecursive(virCgroupPtr group, int signum)
|
2011-02-22 17:33:59 +00:00
|
|
|
{
|
2018-12-10 08:51:14 +00:00
|
|
|
int rc;
|
2020-10-22 07:59:52 +00:00
|
|
|
bool success = false;
|
2018-12-10 08:51:14 +00:00
|
|
|
size_t i;
|
2019-01-24 16:20:58 +00:00
|
|
|
bool backendAvailable = false;
|
2018-12-10 08:51:14 +00:00
|
|
|
virCgroupBackendPtr *backends = virCgroupBackendGetAll();
|
2020-10-20 15:01:51 +00:00
|
|
|
g_autoptr(GHashTable) pids = g_hash_table_new_full(g_int64_hash, g_int64_equal, g_free, NULL);
|
2011-02-22 17:33:59 +00:00
|
|
|
|
2020-10-14 08:29:45 +00:00
|
|
|
VIR_DEBUG("group=%p signum=%d", group, signum);
|
2018-07-30 09:03:16 +00:00
|
|
|
|
2018-12-10 08:51:14 +00:00
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
2019-01-24 16:20:58 +00:00
|
|
|
if (backends && backends[i] && backends[i]->available()) {
|
|
|
|
backendAvailable = true;
|
2020-10-22 07:59:52 +00:00
|
|
|
if ((rc = backends[i]->killRecursive(group, signum, pids)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2018-12-10 08:51:14 +00:00
|
|
|
if (rc > 0)
|
2020-10-22 07:59:52 +00:00
|
|
|
success = true;
|
2018-12-10 08:51:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-22 07:59:52 +00:00
|
|
|
if (success)
|
|
|
|
return 1;
|
|
|
|
|
2019-01-24 16:20:58 +00:00
|
|
|
if (!backends || !backendAvailable) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("no cgroup backend available"));
|
2020-10-22 07:59:52 +00:00
|
|
|
return -1;
|
2019-01-24 16:20:58 +00:00
|
|
|
}
|
|
|
|
|
2020-10-22 07:59:52 +00:00
|
|
|
return 0;
|
2011-02-22 17:33:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
|
|
|
virCgroupKillPainfully(virCgroupPtr group)
|
2011-02-22 17:33:59 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-07-19 14:43:04 +00:00
|
|
|
int ret;
|
2020-10-14 08:29:45 +00:00
|
|
|
VIR_DEBUG("cgroup=%p", group);
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < 15; i++) {
|
2011-02-22 17:33:59 +00:00
|
|
|
int signum;
|
|
|
|
if (i == 0)
|
|
|
|
signum = SIGTERM;
|
|
|
|
else if (i == 8)
|
|
|
|
signum = SIGKILL;
|
|
|
|
else
|
2012-10-11 16:31:20 +00:00
|
|
|
signum = 0; /* Just check for existence */
|
2011-02-22 17:33:59 +00:00
|
|
|
|
2013-07-19 14:43:04 +00:00
|
|
|
ret = virCgroupKillRecursive(group, signum);
|
|
|
|
VIR_DEBUG("Iteration %zu rc=%d", i, ret);
|
|
|
|
/* If ret == -1 we hit error, if 0 we ran out of PIDs */
|
|
|
|
if (ret <= 0)
|
2011-02-22 17:33:59 +00:00
|
|
|
break;
|
|
|
|
|
2019-10-02 17:01:11 +00:00
|
|
|
g_usleep(200 * 1000);
|
2011-02-22 17:33:59 +00:00
|
|
|
}
|
2013-07-19 14:43:04 +00:00
|
|
|
VIR_DEBUG("Complete %d", ret);
|
|
|
|
return ret;
|
2011-02-22 17:33:59 +00:00
|
|
|
}
|
2011-02-28 14:13:58 +00:00
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
|
2013-08-12 17:47:13 +00:00
|
|
|
/**
|
|
|
|
* virCgroupGetCpuCfsQuota:
|
|
|
|
*
|
|
|
|
* @group: The cgroup to get cpu.cfs_quota_us for
|
|
|
|
* @cfs_quota: Pointer to the returned cpu bandwidth (in usecs) that this tg
|
|
|
|
* will be allowed to consume over period
|
|
|
|
*
|
|
|
|
* Returns: 0 on success
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupGetCpuCfsQuota(virCgroupPtr group, long long *cfs_quota)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
|
|
|
|
getCpuCfsQuota, -1, cfs_quota);
|
2013-08-12 17:47:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT,
|
|
|
|
getCpuacctUsage, -1, usage);
|
2013-08-12 17:47:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user,
|
|
|
|
unsigned long long *sys)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT,
|
|
|
|
getCpuacctStat, -1, user, sys);
|
2013-08-12 17:47:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupSetFreezerState(virCgroupPtr group, const char *state)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_FREEZER,
|
|
|
|
setFreezerState, -1, state);
|
2013-08-12 17:47:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupGetFreezerState(virCgroupPtr group, char **state)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_FREEZER,
|
|
|
|
getFreezerState, -1, state);
|
2013-08-12 17:47:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
2016-01-22 16:07:18 +00:00
|
|
|
virCgroupBindMount(virCgroupPtr group, const char *oldroot,
|
|
|
|
const char *mountopts)
|
2013-04-05 11:48:47 +00:00
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (group->backends[i] &&
|
|
|
|
group->backends[i]->bindMount(group, oldroot, mountopts) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2013-04-05 11:48:47 +00:00
|
|
|
}
|
2013-08-12 20:02:26 +00:00
|
|
|
|
|
|
|
|
2014-02-24 12:23:33 +00:00
|
|
|
int virCgroupSetOwner(virCgroupPtr cgroup,
|
|
|
|
uid_t uid,
|
|
|
|
gid_t gid,
|
|
|
|
int controllers)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (cgroup->backends[i] &&
|
|
|
|
cgroup->backends[i]->setOwner(cgroup, uid, gid, controllers) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2014-02-24 12:23:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-13 14:03:14 +00:00
|
|
|
/**
|
|
|
|
* virCgroupSupportsCpuBW():
|
|
|
|
* Check whether the host supports CFS bandwidth.
|
|
|
|
*
|
|
|
|
* Return true when CFS bandwidth is supported,
|
|
|
|
* false when CFS bandwidth is not supported.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
virCgroupSupportsCpuBW(virCgroupPtr cgroup)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
VIR_CGROUP_BACKEND_CALL(cgroup, VIR_CGROUP_CONTROLLER_CPU,
|
|
|
|
supportsCpuBW, false);
|
2013-09-13 14:03:14 +00:00
|
|
|
}
|
|
|
|
|
2014-12-13 08:56:00 +00:00
|
|
|
int
|
|
|
|
virCgroupHasEmptyTasks(virCgroupPtr cgroup, int controller)
|
|
|
|
{
|
2018-09-28 17:53:05 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
|
|
|
|
if (cgroup->backends[i]) {
|
|
|
|
int rc = cgroup->backends[i]->hasEmptyTasks(cgroup, controller);
|
|
|
|
if (rc <= 0)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
2014-12-13 08:56:00 +00:00
|
|
|
}
|
2013-09-13 14:03:14 +00:00
|
|
|
|
2015-03-31 09:39:13 +00:00
|
|
|
bool
|
|
|
|
virCgroupControllerAvailable(int controller)
|
|
|
|
{
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) cgroup = NULL;
|
2015-03-31 09:39:13 +00:00
|
|
|
|
|
|
|
if (virCgroupNewSelf(&cgroup) < 0)
|
2020-10-09 14:09:46 +00:00
|
|
|
return false;
|
2015-03-31 09:39:13 +00:00
|
|
|
|
2020-10-09 14:09:46 +00:00
|
|
|
return virCgroupHasController(cgroup, controller);
|
2015-03-31 09:39:13 +00:00
|
|
|
}
|
|
|
|
|
2018-09-27 10:16:57 +00:00
|
|
|
#else /* !__linux__ */
|
2013-08-12 20:02:26 +00:00
|
|
|
|
2013-08-11 12:04:27 +00:00
|
|
|
bool
|
|
|
|
virCgroupAvailable(void)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:28 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupNewPartition(const char *path G_GNUC_UNUSED,
|
|
|
|
bool create G_GNUC_UNUSED,
|
|
|
|
int controllers G_GNUC_UNUSED,
|
|
|
|
virCgroupPtr *group G_GNUC_UNUSED)
|
2013-08-11 12:04:28 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupNewSelf(virCgroupPtr *group G_GNUC_UNUSED)
|
2013-08-11 12:04:28 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupNewDomainPartition(virCgroupPtr partition G_GNUC_UNUSED,
|
|
|
|
const char *driver G_GNUC_UNUSED,
|
|
|
|
const char *name G_GNUC_UNUSED,
|
|
|
|
virCgroupPtr *group G_GNUC_UNUSED)
|
2013-08-11 12:04:28 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-07 12:28:05 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupNewThread(virCgroupPtr domain G_GNUC_UNUSED,
|
|
|
|
virCgroupThreadName nameval G_GNUC_UNUSED,
|
|
|
|
int id G_GNUC_UNUSED,
|
|
|
|
bool create G_GNUC_UNUSED,
|
|
|
|
virCgroupPtr *group G_GNUC_UNUSED)
|
2015-04-07 12:28:05 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:28 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupNewDetect(pid_t pid G_GNUC_UNUSED,
|
|
|
|
int controllers G_GNUC_UNUSED,
|
|
|
|
virCgroupPtr *group G_GNUC_UNUSED)
|
2013-08-11 12:04:28 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:27 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupNewDetectMachine(const char *name G_GNUC_UNUSED,
|
|
|
|
const char *drivername G_GNUC_UNUSED,
|
|
|
|
pid_t pid G_GNUC_UNUSED,
|
|
|
|
int controllers G_GNUC_UNUSED,
|
|
|
|
char *machinename G_GNUC_UNUSED,
|
|
|
|
virCgroupPtr *group G_GNUC_UNUSED)
|
2013-08-11 12:04:27 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-10-02 09:05:50 +00:00
|
|
|
|
2019-10-14 12:45:33 +00:00
|
|
|
int virCgroupTerminateMachine(const char *name G_GNUC_UNUSED)
|
2014-10-02 09:05:50 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:29 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupNewMachine(const char *name G_GNUC_UNUSED,
|
|
|
|
const char *drivername G_GNUC_UNUSED,
|
|
|
|
const unsigned char *uuid G_GNUC_UNUSED,
|
|
|
|
const char *rootdir G_GNUC_UNUSED,
|
|
|
|
pid_t pidleader G_GNUC_UNUSED,
|
|
|
|
bool isContainer G_GNUC_UNUSED,
|
|
|
|
size_t nnicindexes G_GNUC_UNUSED,
|
|
|
|
int *nicindexes G_GNUC_UNUSED,
|
|
|
|
const char *partition G_GNUC_UNUSED,
|
|
|
|
int controllers G_GNUC_UNUSED,
|
|
|
|
unsigned int maxthreads G_GNUC_UNUSED,
|
|
|
|
virCgroupPtr *group G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
virCgroupNewIgnoreError(void)
|
|
|
|
{
|
|
|
|
VIR_DEBUG("No cgroups present/configured/accessible, ignoring error");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-08-11 12:04:27 +00:00
|
|
|
|
|
|
|
bool
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupHasController(virCgroupPtr cgroup G_GNUC_UNUSED,
|
|
|
|
int controller G_GNUC_UNUSED)
|
2013-08-11 12:04:27 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:28 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupPathOfController(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned int controller G_GNUC_UNUSED,
|
|
|
|
const char *key G_GNUC_UNUSED,
|
|
|
|
char **path G_GNUC_UNUSED)
|
2013-08-11 12:04:28 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:29 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupAddProcess(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
pid_t pid G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-09 14:27:34 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupAddMachineProcess(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
pid_t pid G_GNUC_UNUSED)
|
2017-01-09 14:27:34 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-24 22:54:04 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupAddThread(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
pid_t pid G_GNUC_UNUSED)
|
2018-09-24 22:54:04 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-14 17:48:59 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetBlkioIoServiced(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
long long *bytes_read G_GNUC_UNUSED,
|
|
|
|
long long *bytes_write G_GNUC_UNUSED,
|
|
|
|
long long *requests_read G_GNUC_UNUSED,
|
|
|
|
long long *requests_write G_GNUC_UNUSED)
|
2014-02-14 17:48:59 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetBlkioIoDeviceServiced(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
long long *bytes_read G_GNUC_UNUSED,
|
|
|
|
long long *bytes_write G_GNUC_UNUSED,
|
|
|
|
long long *requests_read G_GNUC_UNUSED,
|
|
|
|
long long *requests_write G_GNUC_UNUSED)
|
2014-02-14 17:48:59 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:29 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetBlkioWeight(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned int weight G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetBlkioWeight(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned int *weight G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetBlkioDeviceWeight(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
unsigned int weight G_GNUC_UNUSED)
|
2013-08-11 12:04:28 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetBlkioDeviceReadIops(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
unsigned int riops G_GNUC_UNUSED)
|
2013-12-11 08:29:50 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
unsigned int wiops G_GNUC_UNUSED)
|
2013-12-11 08:29:50 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetBlkioDeviceReadBps(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
unsigned long long rbps G_GNUC_UNUSED)
|
2013-12-11 08:29:50 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
unsigned long long wbps G_GNUC_UNUSED)
|
2013-12-11 08:29:50 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetBlkioDeviceWeight(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
unsigned int *weight G_GNUC_UNUSED)
|
2015-08-03 13:10:20 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetBlkioDeviceReadIops(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
unsigned int *riops G_GNUC_UNUSED)
|
2015-08-03 13:10:20 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetBlkioDeviceWriteIops(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
unsigned int *wiops G_GNUC_UNUSED)
|
2015-08-03 13:10:20 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetBlkioDeviceReadBps(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
unsigned long long *rbps G_GNUC_UNUSED)
|
2015-08-03 13:10:20 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-02-17 21:29:10 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetBlkioDeviceWriteBps(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
unsigned long long *wbps G_GNUC_UNUSED)
|
2015-08-03 13:10:20 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
2013-08-11 12:04:28 +00:00
|
|
|
|
2013-08-11 12:04:29 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetMemory(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long kb G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-13 14:03:03 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetMemoryStat(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long *cache G_GNUC_UNUSED,
|
|
|
|
unsigned long long *activeAnon G_GNUC_UNUSED,
|
|
|
|
unsigned long long *inactiveAnon G_GNUC_UNUSED,
|
|
|
|
unsigned long long *activeFile G_GNUC_UNUSED,
|
|
|
|
unsigned long long *inactiveFile G_GNUC_UNUSED,
|
|
|
|
unsigned long long *unevictable G_GNUC_UNUSED)
|
2018-08-13 14:03:03 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:29 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetMemoryUsage(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long *kb G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetMemoryHardLimit(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long kb G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetMemoryHardLimit(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long *kb G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetMemorySoftLimit(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long kb G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetMemorySoftLimit(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long *kb G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetMemSwapHardLimit(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long kb G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetMemSwapHardLimit(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long *kb G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetMemSwapUsage(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long *kb G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetCpusetMems(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *mems G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetCpusetMems(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
char **mems G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-03-27 16:13:56 +00:00
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetCpusetMemoryMigrate(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
bool migrate G_GNUC_UNUSED)
|
2015-03-27 16:13:56 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetCpusetMemoryMigrate(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
bool *migrate G_GNUC_UNUSED)
|
2015-03-27 16:13:56 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-08-11 12:04:29 +00:00
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetCpusetCpus(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *cpus G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetCpusetCpus(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
char **cpus G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-07-18 08:02:29 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupAllowAllDevices(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
int perms G_GNUC_UNUSED)
|
2014-07-18 08:02:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
2013-08-11 12:04:29 +00:00
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupDenyAllDevices(virCgroupPtr group G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupAllowDevice(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
char type G_GNUC_UNUSED,
|
|
|
|
int major G_GNUC_UNUSED,
|
|
|
|
int minor G_GNUC_UNUSED,
|
|
|
|
int perms G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:28 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupAllowDevicePath(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
int perms G_GNUC_UNUSED,
|
|
|
|
bool ignoreEaccess G_GNUC_UNUSED)
|
2013-08-11 12:04:28 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:29 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupDenyDevice(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
char type G_GNUC_UNUSED,
|
|
|
|
int major G_GNUC_UNUSED,
|
|
|
|
int minor G_GNUC_UNUSED,
|
|
|
|
int perms G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:28 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupDenyDevicePath(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *path G_GNUC_UNUSED,
|
|
|
|
int perms G_GNUC_UNUSED,
|
|
|
|
bool ignoreEacces G_GNUC_UNUSED)
|
2013-08-11 12:04:28 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-11 12:04:29 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetCpuShares(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long shares G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetCpuShares(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long *shares G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetCpuCfsPeriod(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long cfs_period G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetCpuCfsPeriod(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long *cfs_period G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetCpuCfsQuota(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
long long cfs_quota G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupRemove(virCgroupPtr group G_GNUC_UNUSED)
|
2013-08-11 12:04:29 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENXIO, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-12 20:02:26 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupKillRecursive(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
int signum G_GNUC_UNUSED)
|
2013-08-12 20:02:26 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupKillPainfully(virCgroupPtr group G_GNUC_UNUSED)
|
2013-08-12 20:02:26 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-12 17:47:13 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetCpuCfsQuota(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
long long *cfs_quota G_GNUC_UNUSED)
|
2013-08-12 17:47:13 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetCpuacctUsage(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long *usage G_GNUC_UNUSED)
|
2013-08-12 17:47:13 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetCpuacctPercpuUsage(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
char **usage G_GNUC_UNUSED)
|
2013-08-12 17:47:13 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetCpuacctStat(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
unsigned long long *user G_GNUC_UNUSED,
|
|
|
|
unsigned long long *sys G_GNUC_UNUSED)
|
2013-08-12 17:47:13 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-21 08:10:48 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetDomainTotalCpuStats(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
virTypedParameterPtr params G_GNUC_UNUSED,
|
|
|
|
int nparams G_GNUC_UNUSED)
|
2014-02-21 08:10:48 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-12 17:47:13 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetFreezerState(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *state G_GNUC_UNUSED)
|
2013-08-12 17:47:13 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetFreezerState(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
char **state G_GNUC_UNUSED)
|
2013-08-12 17:47:13 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-12 19:52:06 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupBindMount(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
const char *oldroot G_GNUC_UNUSED,
|
|
|
|
const char *mountopts G_GNUC_UNUSED)
|
2013-04-05 11:48:47 +00:00
|
|
|
{
|
2013-07-08 10:08:46 +00:00
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
2013-04-05 11:48:47 +00:00
|
|
|
}
|
2013-08-12 20:02:26 +00:00
|
|
|
|
2013-09-13 14:03:14 +00:00
|
|
|
|
|
|
|
bool
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSupportsCpuBW(virCgroupPtr cgroup G_GNUC_UNUSED)
|
2013-09-13 14:03:14 +00:00
|
|
|
{
|
|
|
|
VIR_DEBUG("Control groups not supported on this platform");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-02-26 00:18:54 +00:00
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupGetPercpuStats(virCgroupPtr group G_GNUC_UNUSED,
|
|
|
|
virTypedParameterPtr params G_GNUC_UNUSED,
|
|
|
|
unsigned int nparams G_GNUC_UNUSED,
|
|
|
|
int start_cpu G_GNUC_UNUSED,
|
|
|
|
unsigned int ncpus G_GNUC_UNUSED,
|
|
|
|
virBitmapPtr guestvcpus G_GNUC_UNUSED)
|
2014-02-26 00:18:54 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupSetOwner(virCgroupPtr cgroup G_GNUC_UNUSED,
|
|
|
|
uid_t uid G_GNUC_UNUSED,
|
|
|
|
gid_t gid G_GNUC_UNUSED,
|
|
|
|
int controllers G_GNUC_UNUSED)
|
2014-02-26 00:18:54 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-12-13 08:56:00 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupHasEmptyTasks(virCgroupPtr cgroup G_GNUC_UNUSED,
|
|
|
|
int controller G_GNUC_UNUSED)
|
2014-12-13 08:56:00 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Control groups not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-03-31 09:39:13 +00:00
|
|
|
bool
|
2019-10-14 12:45:33 +00:00
|
|
|
virCgroupControllerAvailable(int controller G_GNUC_UNUSED)
|
2015-03-31 09:39:13 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2018-09-27 10:16:57 +00:00
|
|
|
#endif /* !__linux__ */
|
2016-08-04 21:36:38 +00:00
|
|
|
|
|
|
|
|
2019-04-24 13:26:12 +00:00
|
|
|
/**
|
|
|
|
* virCgroupFree:
|
|
|
|
*
|
|
|
|
* @group: The group structure to free
|
|
|
|
*/
|
|
|
|
void
|
2020-09-22 12:07:27 +00:00
|
|
|
virCgroupFree(virCgroupPtr group)
|
2019-04-24 13:26:12 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
2020-09-22 12:07:27 +00:00
|
|
|
if (group == NULL)
|
2019-04-24 13:26:12 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
|
2020-09-22 12:07:27 +00:00
|
|
|
VIR_FREE(group->legacy[i].mountPoint);
|
|
|
|
VIR_FREE(group->legacy[i].linkPoint);
|
|
|
|
VIR_FREE(group->legacy[i].placement);
|
2019-04-24 13:26:12 +00:00
|
|
|
}
|
|
|
|
|
2020-09-22 12:07:27 +00:00
|
|
|
VIR_FREE(group->unified.mountPoint);
|
|
|
|
VIR_FREE(group->unified.placement);
|
2019-04-24 13:26:12 +00:00
|
|
|
|
2020-09-22 12:07:27 +00:00
|
|
|
VIR_FREE(group);
|
2019-04-24 13:26:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-04 21:36:38 +00:00
|
|
|
int
|
|
|
|
virCgroupDelThread(virCgroupPtr cgroup,
|
|
|
|
virCgroupThreadName nameval,
|
|
|
|
int idx)
|
|
|
|
{
|
2020-10-09 14:09:46 +00:00
|
|
|
g_autoptr(virCgroup) new_cgroup = NULL;
|
2016-08-04 21:36:38 +00:00
|
|
|
|
|
|
|
if (cgroup) {
|
|
|
|
if (virCgroupNewThread(cgroup, nameval, idx, false, &new_cgroup) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Remove the offlined cgroup */
|
|
|
|
virCgroupRemove(new_cgroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2020-02-17 21:29:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calls virCgroupSetBlkioDeviceWeight() to set up blkio device weight,
|
|
|
|
* then retrieves the actual value set by the kernel with
|
|
|
|
* virCgroupGetBlkioDeviceWeight() in the same @weight pointer.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupSetupBlkioDeviceWeight(virCgroupPtr cgroup, const char *path,
|
|
|
|
unsigned int *weight)
|
|
|
|
{
|
|
|
|
if (virCgroupSetBlkioDeviceWeight(cgroup, path, *weight) < 0 ||
|
|
|
|
virCgroupGetBlkioDeviceWeight(cgroup, path, weight) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calls virCgroupSetBlkioDeviceReadIops() to set up blkio device riops,
|
|
|
|
* then retrieves the actual value set by the kernel with
|
|
|
|
* virCgroupGetBlkioDeviceReadIops() in the same @riops pointer.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupSetupBlkioDeviceReadIops(virCgroupPtr cgroup, const char *path,
|
|
|
|
unsigned int *riops)
|
|
|
|
{
|
|
|
|
if (virCgroupSetBlkioDeviceReadIops(cgroup, path, *riops) < 0 ||
|
|
|
|
virCgroupGetBlkioDeviceReadIops(cgroup, path, riops) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calls virCgroupSetBlkioDeviceWriteIops() to set up blkio device wiops,
|
|
|
|
* then retrieves the actual value set by the kernel with
|
|
|
|
* virCgroupGetBlkioDeviceWriteIops() in the same @wiops pointer.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupSetupBlkioDeviceWriteIops(virCgroupPtr cgroup, const char *path,
|
|
|
|
unsigned int *wiops)
|
|
|
|
{
|
|
|
|
if (virCgroupSetBlkioDeviceWriteIops(cgroup, path, *wiops) < 0 ||
|
|
|
|
virCgroupGetBlkioDeviceWriteIops(cgroup, path, wiops) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calls virCgroupSetBlkioDeviceReadBps() to set up blkio device rbps,
|
|
|
|
* then retrieves the actual value set by the kernel with
|
|
|
|
* virCgroupGetBlkioDeviceReadBps() in the same @rbps pointer.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupSetupBlkioDeviceReadBps(virCgroupPtr cgroup, const char *path,
|
|
|
|
unsigned long long *rbps)
|
|
|
|
{
|
|
|
|
if (virCgroupSetBlkioDeviceReadBps(cgroup, path, *rbps) < 0 ||
|
|
|
|
virCgroupGetBlkioDeviceReadBps(cgroup, path, rbps) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calls virCgroupSetBlkioDeviceWriteBps() to set up blkio device wbps,
|
|
|
|
* then retrieves the actual value set by the kernel with
|
|
|
|
* virCgroupGetBlkioDeviceWriteBps() in the same @wbps pointer.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCgroupSetupBlkioDeviceWriteBps(virCgroupPtr cgroup, const char *path,
|
|
|
|
unsigned long long *wbps)
|
|
|
|
{
|
|
|
|
if (virCgroupSetBlkioDeviceWriteBps(cgroup, path, *wbps) < 0 ||
|
|
|
|
virCgroupGetBlkioDeviceWriteBps(cgroup, path, wbps) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2020-02-17 21:29:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupSetupCpusetCpus(virCgroupPtr cgroup, virBitmapPtr cpumask)
|
|
|
|
{
|
|
|
|
g_autofree char *new_cpus = NULL;
|
|
|
|
|
|
|
|
if (!(new_cpus = virBitmapFormat(cpumask)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupSetCpusetCpus(cgroup, new_cpus) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2020-02-17 21:29:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Per commit 97814d8ab3, the Linux kernel can consider a 'shares'
|
|
|
|
* value of '0' and '1' as 2, and any value larger than a maximum
|
|
|
|
* is reduced to maximum.
|
|
|
|
*
|
|
|
|
* The 'realValue' pointer holds the actual 'shares' value set by
|
|
|
|
* the kernel if the function returned success. */
|
|
|
|
int
|
|
|
|
virCgroupSetupCpuShares(virCgroupPtr cgroup, unsigned long long shares,
|
|
|
|
unsigned long long *realValue)
|
|
|
|
{
|
|
|
|
if (virCgroupSetCpuShares(cgroup, shares) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupGetCpuShares(cgroup, realValue) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2020-02-17 21:29:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupSetupCpuPeriodQuota(virCgroupPtr cgroup,
|
|
|
|
unsigned long long period,
|
|
|
|
long long quota)
|
|
|
|
{
|
|
|
|
unsigned long long old_period;
|
|
|
|
|
|
|
|
if (period == 0 && quota == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (period) {
|
|
|
|
/* get old period, and we can rollback if set quota failed */
|
|
|
|
if (virCgroupGetCpuCfsPeriod(cgroup, &old_period) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupSetCpuCfsPeriod(cgroup, period) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (quota &&
|
|
|
|
virCgroupSetCpuCfsQuota(cgroup, quota) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (period) {
|
|
|
|
virErrorPtr saved;
|
|
|
|
|
|
|
|
virErrorPreserveLast(&saved);
|
|
|
|
ignore_value(virCgroupSetCpuCfsPeriod(cgroup, old_period));
|
|
|
|
virErrorRestore(&saved);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2020-02-17 21:29:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virCgroupGetCpuPeriodQuota(virCgroupPtr cgroup, unsigned long long *period,
|
|
|
|
long long *quota)
|
|
|
|
{
|
|
|
|
if (virCgroupGetCpuCfsPeriod(cgroup, period) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virCgroupGetCpuCfsQuota(cgroup, quota) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|