vircgroup.c 93.9 KB
Newer Older
1
/*
2
 * vircgroup.c: methods for managing control cgroups
3
 *
4
 * Copyright (C) 2010-2015 Red Hat, Inc.
5 6
 * Copyright IBM Corp. 2008
 *
O
Osier Yang 已提交
7 8 9 10 11 12 13 14 15 16 17
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22
 */
#include <config.h>

23
#ifdef __linux__
24
# include <mntent.h>
25
# include <sys/mount.h>
26 27
# include <fcntl.h>
# include <sys/stat.h>
28

29 30 31 32 33
# ifdef MAJOR_IN_MKDEV
#  include <sys/mkdev.h>
# elif MAJOR_IN_SYSMACROS
#  include <sys/sysmacros.h>
# endif
34

35 36 37 38 39
# include <sys/types.h>
# include <signal.h>
# include <dirent.h>
# include <unistd.h>
#endif /* __linux__ */
40

41
#define LIBVIRT_VIRCGROUPPRIV_H_ALLOW
42 43
#include "vircgrouppriv.h"

44
#include "virutil.h"
45
#include "viralloc.h"
46
#include "vircgroupbackend.h"
47
#include "virerror.h"
48
#include "virlog.h"
E
Eric Blake 已提交
49
#include "virfile.h"
50
#include "virhash.h"
51
#include "virhashcode.h"
52
#include "virstring.h"
53
#include "virsystemd.h"
54
#include "virtypedparam.h"
55
#include "virhostcpu.h"
56
#include "virthread.h"
57

58 59
VIR_LOG_INIT("util.cgroup");

60 61
#define VIR_FROM_THIS VIR_FROM_CGROUP

62
#define CGROUP_NB_TOTAL_CPU_STAT_PARAM 3
63
#define CGROUP_NB_PER_CPU_STAT_PARAM   1
64

65 66
VIR_ENUM_IMPL(virCgroupController,
              VIR_CGROUP_CONTROLLER_LAST,
R
Ryota Ozaki 已提交
67
              "cpu", "cpuacct", "cpuset", "memory", "devices",
68
              "freezer", "blkio", "net_cls", "perf_event",
69 70
              "name=systemd",
);
71

E
Eric Blake 已提交
72

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
/**
 * 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 "";
        }
    }
}


111
#ifdef __linux__
E
Eric Blake 已提交
112 113
bool
virCgroupAvailable(void)
114
{
115 116
    size_t i;
    virCgroupBackendPtr *backends = virCgroupBackendGetAll();
117

118
    if (!backends)
119 120
        return false;

121 122 123
    for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
        if (backends[i] && backends[i]->available())
            return true;
124 125
    }

126
    return false;
127 128
}

E
Eric Blake 已提交
129 130 131 132 133 134

static int
virCgroupPartitionNeedsEscaping(const char *path)
{
    FILE *fp = NULL;
    int ret = 0;
135
    VIR_AUTOFREE(char *) line = NULL;
E
Eric Blake 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
    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;

        tmp = strchrnul(line, ' ');
        *tmp = '\0';
        len = tmp - line;

        if (STRPREFIX(path, line) &&
            path[len] == '.') {
            ret = 1;
            goto cleanup;
        }
    }

    if (ferror(fp)) {
        virReportSystemError(errno, "%s",
                             _("Error while reading /proc/cgroups"));
        goto cleanup;
    }

194
 cleanup:
E
Eric Blake 已提交
195 196 197 198 199
    VIR_FORCE_FCLOSE(fp);
    return ret;
}


200
int
E
Eric Blake 已提交
201 202 203
virCgroupPartitionEscape(char **path)
{
    int rc;
204
    char *newstr = NULL;
E
Eric Blake 已提交
205 206 207 208

    if ((rc = virCgroupPartitionNeedsEscaping(*path)) <= 0)
        return rc;

209
    if (virAsprintf(&newstr, "_%s", *path) < 0)
E
Eric Blake 已提交
210 211
        return -1;

212 213 214
    VIR_FREE(*path);
    *path = newstr;

E
Eric Blake 已提交
215 216
    return 0;
}
E
Eric Blake 已提交
217 218


219 220 221 222
/*
 * Process /proc/mounts figuring out what controllers are
 * mounted and where
 */
223
static int
224
virCgroupDetectMounts(virCgroupPtr group)
225
{
226
    FILE *mounts = NULL;
227 228
    struct mntent entry;
    char buf[CGROUP_MAX_VAL];
229
    int ret = -1;
230
    size_t i;
231

232
    mounts = fopen("/proc/mounts", "r");
233
    if (mounts == NULL) {
234
        virReportSystemError(errno, "%s", _("Unable to open /proc/mounts"));
235
        return -1;
236 237 238
    }

    while (getmntent_r(mounts, &entry, buf, sizeof(buf)) != NULL) {
239 240 241 242 243 244 245 246
        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;
            }
247
        }
248 249
    }

250 251
    ret = 0;
 cleanup:
252
    VIR_FORCE_FCLOSE(mounts);
253
    return ret;
254 255
}

256 257

/*
258 259 260 261
 * virCgroupDetectPlacement:
 * @group: the group to process
 * @path: the relative path to append, not starting with '/'
 *
262 263
 * Process /proc/self/cgroup figuring out what cgroup
 * sub-path the current process is assigned to. ie not
264 265 266 267 268 269 270 271 272 273 274 275 276 277
 * 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.
278
 */
E
Eric Blake 已提交
279 280 281 282
static int
virCgroupDetectPlacement(virCgroupPtr group,
                         pid_t pid,
                         const char *path)
283
{
284 285
    FILE *mapping  = NULL;
    char line[1024];
286
    int ret = -1;
287
    VIR_AUTOFREE(char *) procfile = NULL;
288

289
    VIR_DEBUG("Detecting placement for pid %lld path %s",
M
Michal Privoznik 已提交
290
              (long long) pid, path);
291 292 293 294
    if (pid == -1) {
        if (VIR_STRDUP(procfile, "/proc/self/cgroup") < 0)
            goto cleanup;
    } else {
M
Michal Privoznik 已提交
295 296
        if (virAsprintf(&procfile, "/proc/%lld/cgroup",
                        (long long) pid) < 0)
297 298 299 300
            goto cleanup;
    }

    mapping = fopen(procfile, "r");
301
    if (mapping == NULL) {
302 303 304 305
        virReportSystemError(errno,
                             _("Unable to open '%s'"),
                             procfile);
        goto cleanup;
306 307
    }

308
    while (fgets(line, sizeof(line), mapping) != NULL) {
309
        size_t i;
310
        char *controllers = strchr(line, ':');
311 312
        char *selfpath = controllers ? strchr(controllers + 1, ':') : NULL;
        char *nl = selfpath ? strchr(selfpath, '\n') : NULL;
313

314
        if (!controllers || !selfpath)
315 316 317 318 319
            continue;

        if (nl)
            *nl = '\0';

320
        *selfpath = '\0';
321
        controllers++;
322
        selfpath++;
323

324 325 326 327 328 329
        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;
            }
330 331 332
        }
    }

333
    ret = 0;
334

335
 cleanup:
336
    VIR_FORCE_FCLOSE(mapping);
337
    return ret;
338 339
}

E
Eric Blake 已提交
340

341 342 343 344 345 346 347
static int
virCgroupDetect(virCgroupPtr group,
                pid_t pid,
                int controllers,
                const char *path,
                virCgroupPtr parent)
{
348
    size_t i;
349 350
    bool backendAvailable = false;
    int controllersAvailable = 0;
351
    virCgroupBackendPtr *backends = virCgroupBackendGetAll();
352 353 354 355

    VIR_DEBUG("group=%p controllers=%d path=%s parent=%p",
              group, controllers, path, parent);

356 357 358 359 360
    if (!backends)
        return -1;

    for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
        if (backends[i] && backends[i]->available()) {
361 362
            group->backends[i] = backends[i];
            backendAvailable = true;
363 364 365
        }
    }

366
    if (!backendAvailable) {
367 368 369 370 371
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no cgroup backend available"));
        return -1;
    }

372
    if (parent) {
373 374 375 376 377 378
        for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
            if (group->backends[i] &&
                group->backends[i]->copyMounts(group, parent) < 0) {
                return -1;
            }
        }
379 380 381 382 383
    } else {
        if (virCgroupDetectMounts(group) < 0)
            return -1;
    }

384 385 386
    /* In some cases we can copy part of the placement info
     * based on the parent cgroup...
     */
387 388 389 390 391 392 393 394
    if (parent || path[0] == '/') {
        for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
            if (group->backends[i] &&
                group->backends[i]->copyPlacement(group, path, parent) < 0) {
                return -1;
            }
        }
    }
395 396 397 398

    /* ... but use /proc/cgroups to fill in the rest */
    if (virCgroupDetectPlacement(group, pid, path) < 0)
        return -1;
399

400
    /* Check that for every mounted controller, we found our placement */
401 402 403 404 405 406
    for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
        if (group->backends[i] &&
            group->backends[i]->validatePlacement(group, pid) < 0) {
            return -1;
        }
    }
407

408 409
    for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
        if (group->backends[i]) {
410
            int rc = group->backends[i]->detectControllers(group, controllers, parent);
411 412 413 414 415 416 417 418 419 420 421 422 423
            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;
    }

424
    return 0;
425 426
}

427

428
char *
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
virCgroupGetBlockDevString(const char *path)
{
    char *ret = NULL;
    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 */
    if (virAsprintf(&ret, "%d:%d ", major(sb.st_rdev), minor(sb.st_rdev)) < 0)
        return NULL;

    return ret;
}


457
int
458
virCgroupSetValueRaw(const char *path,
E
Eric Blake 已提交
459
                     const char *value)
460
{
461
    char *tmp;
462

463 464
    VIR_DEBUG("Set value '%s' to '%s'", path, value);
    if (virFileWriteStr(path, value, 0) < 0) {
465
        if (errno == EINVAL &&
466
            (tmp = strrchr(path, '/'))) {
467 468 469
            virReportSystemError(errno,
                                 _("Invalid value '%s' for '%s'"),
                                 value, tmp + 1);
470
            return -1;
471
        }
472
        virReportSystemError(errno,
473
                             _("Unable to write to '%s'"), path);
474
        return -1;
475 476
    }

477
    return 0;
478 479
}

E
Eric Blake 已提交
480

481
int
482
virCgroupGetValueRaw(const char *path,
E
Eric Blake 已提交
483
                     char **value)
484
{
485
    int rc;
486

487
    *value = NULL;
488

489
    VIR_DEBUG("Get value %s", path);
490

491
    if ((rc = virFileReadAll(path, 1024*1024, value)) < 0) {
492
        virReportSystemError(errno,
493
                             _("Unable to read from '%s'"), path);
494
        return -1;
495 496
    }

497 498 499
    /* Terminated with '\n' has sometimes harmful effects to the caller */
    if (rc > 0 && (*value)[rc - 1] == '\n')
        (*value)[rc - 1] = '\0';
500

501
    return 0;
502 503
}

E
Eric Blake 已提交
504

505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
int
virCgroupSetValueStr(virCgroupPtr group,
                     int controller,
                     const char *key,
                     const char *value)
{
    VIR_AUTOFREE(char *) keypath = NULL;

    if (virCgroupPathOfController(group, controller, key, &keypath) < 0)
        return -1;

    return virCgroupSetValueRaw(keypath, value);
}


int
virCgroupGetValueStr(virCgroupPtr group,
                     int controller,
                     const char *key,
                     char **value)
{
    VIR_AUTOFREE(char *) keypath = NULL;

    if (virCgroupPathOfController(group, controller, key, &keypath) < 0)
        return -1;

    return virCgroupGetValueRaw(keypath, value);
}


535
int
536
virCgroupGetValueForBlkDev(const char *str,
537 538 539
                           const char *path,
                           char **value)
{
540
    VIR_AUTOFREE(char *) prefix = NULL;
541 542
    char **lines = NULL;
    int ret = -1;
543 544

    if (!(prefix = virCgroupGetBlockDevString(path)))
545
        goto error;
546 547

    if (!(lines = virStringSplit(str, "\n", -1)))
548
        goto error;
549

550
    if (VIR_STRDUP(*value, virStringListGetFirstWithPrefix(lines, prefix)) < 0)
551
        goto error;
552

553 554 555 556
    ret = 0;
 error:
    virStringListFree(lines);
    return ret;
557 558 559
}


560
int
E
Eric Blake 已提交
561 562 563 564
virCgroupSetValueU64(virCgroupPtr group,
                     int controller,
                     const char *key,
                     unsigned long long int value)
565
{
566
    VIR_AUTOFREE(char *) strval = NULL;
567

568 569
    if (virAsprintf(&strval, "%llu", value) < 0)
        return -1;
570

571
    return virCgroupSetValueStr(group, controller, key, strval);
572 573 574
}


575
int
E
Eric Blake 已提交
576 577 578 579
virCgroupSetValueI64(virCgroupPtr group,
                     int controller,
                     const char *key,
                     long long int value)
580
{
581
    VIR_AUTOFREE(char *) strval = NULL;
582

583 584
    if (virAsprintf(&strval, "%lld", value) < 0)
        return -1;
585

586
    return virCgroupSetValueStr(group, controller, key, strval);
587 588
}

E
Eric Blake 已提交
589

590
int
E
Eric Blake 已提交
591 592 593 594
virCgroupGetValueI64(virCgroupPtr group,
                     int controller,
                     const char *key,
                     long long int *value)
595
{
596
    VIR_AUTOFREE(char *) strval = NULL;
597

598
    if (virCgroupGetValueStr(group, controller, key, &strval) < 0)
599
        return -1;
600

601 602 603 604
    if (virStrToLong_ll(strval, NULL, 10, value) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to parse '%s' as an integer"),
                       strval);
605
        return -1;
606
    }
607

608
    return 0;
609 610
}

E
Eric Blake 已提交
611

612
int
E
Eric Blake 已提交
613 614 615 616
virCgroupGetValueU64(virCgroupPtr group,
                     int controller,
                     const char *key,
                     unsigned long long int *value)
617
{
618
    VIR_AUTOFREE(char *) strval = NULL;
619

620
    if (virCgroupGetValueStr(group, controller, key, &strval) < 0)
621
        return -1;
622

623 624 625 626
    if (virStrToLong_ull(strval, NULL, 10, value) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to parse '%s' as an integer"),
                       strval);
627
        return -1;
628
    }
629

630
    return 0;
631 632 633
}


E
Eric Blake 已提交
634 635 636 637 638
static int
virCgroupMakeGroup(virCgroupPtr parent,
                   virCgroupPtr group,
                   bool create,
                   unsigned int flags)
639
{
640 641 642 643 644 645 646 647
    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;
        }
648 649
    }

650
    return 0;
651 652
}

653

654 655 656 657 658 659 660 661 662 663 664 665 666 667
/**
 * virCgroupNew:
 * @path: path for the new group
 * @parent: parent group, or NULL
 * @controllers: bitmask of controllers to activate
 *
 * Create a new cgroup storing it in @group.
 *
 * If @path starts with a '/' it is treated as an
 * absolute path, and @parent is ignored. Otherwise
 * it is treated as being relative to @parent. If
 * @parent is NULL, then the placement of the current
 * process is used.
 *
668
 * Returns 0 on success, -1 on error
669
 */
670
int
E
Eric Blake 已提交
671 672 673 674 675
virCgroupNew(pid_t pid,
             const char *path,
             virCgroupPtr parent,
             int controllers,
             virCgroupPtr *group)
676
{
677 678
    VIR_DEBUG("pid=%lld path=%s parent=%p controllers=%d group=%p",
              (long long) pid, path, parent, controllers, group);
679
    *group = NULL;
680

681 682
    if (VIR_ALLOC((*group)) < 0)
        goto error;
683

684
    if (path[0] == '/' || !parent) {
685 686
        if (VIR_STRDUP((*group)->path, path) < 0)
            goto error;
687 688 689 690
    } else {
        if (virAsprintf(&(*group)->path, "%s%s%s",
                        parent->path,
                        STREQ(parent->path, "") ? "" : "/",
691 692
                        path) < 0)
            goto error;
693 694
    }

695
    if (virCgroupDetect(*group, pid, controllers, path, parent) < 0)
696
        goto error;
697

698 699
    return 0;

700
 error:
701
    virCgroupFree(group);
702
    *group = NULL;
703

704
    return -1;
705
}
706

707

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
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;
}


726
/**
727
 * virCgroupAddProcess:
728
 *
729 730
 * @group: The cgroup to add a process to
 * @pid: The pid of the process to add
731
 *
732
 * Will add the process to all controllers, except the
733 734 735 736 737
 * systemd unit controller.
 *
 * Returns: 0 on success, -1 on error
 */
int
738
virCgroupAddProcess(virCgroupPtr group, pid_t pid)
739
{
740
    return virCgroupAddTaskInternal(group, pid, VIR_CGROUP_TASK_PROCESS);
741 742 743
}

/**
744
 * virCgroupAddMachineProcess:
745
 *
746 747
 * @group: The cgroup to add a process to
 * @pid: The pid of the process to add
748
 *
749
 * Will add the process to all controllers, including the
750 751 752 753 754
 * systemd unit controller.
 *
 * Returns: 0 on success, -1 on error
 */
int
755
virCgroupAddMachineProcess(virCgroupPtr group, pid_t pid)
756
{
757 758 759
    return virCgroupAddTaskInternal(group, pid,
                                    VIR_CGROUP_TASK_PROCESS |
                                    VIR_CGROUP_TASK_SYSTEMD);
760 761
}

762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
/**
 * 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)
{
777
    return virCgroupAddTaskInternal(group, pid, VIR_CGROUP_TASK_THREAD);
778 779
}

E
Eric Blake 已提交
780 781 782

static int
virCgroupSetPartitionSuffix(const char *path, char **res)
783
{
784
    char **tokens;
785
    size_t i;
786
    int ret = -1;
787

788
    if (!(tokens = virStringSplit(path, "/", 0)))
789
        return ret;
790

791
    for (i = 0; tokens[i] != NULL; i++) {
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
        /* Whitelist the 3 top level fixed dirs
         * 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], '.')) {
            if (VIR_REALLOC_N(tokens[i],
807
                              strlen(tokens[i]) + strlen(".partition") + 1) < 0)
808
                goto cleanup;
809 810
            strcat(tokens[i], ".partition");
        }
811

812
        if (virCgroupPartitionEscape(&(tokens[i])) < 0)
813
            goto cleanup;
814 815
    }

816
    if (!(*res = virStringListJoin((const char **)tokens, "/")))
817
        goto cleanup;
818

819 820 821 822 823
    ret = 0;

 cleanup:
    virStringListFree(tokens);
    return ret;
824 825
}

E
Eric Blake 已提交
826

827 828 829 830 831 832 833
/**
 * 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
834
 * partition path identified by @path.
835
 *
836
 * Returns 0 on success, -1 on failure
837
 */
E
Eric Blake 已提交
838 839 840 841 842
int
virCgroupNewPartition(const char *path,
                      bool create,
                      int controllers,
                      virCgroupPtr *group)
843
{
844
    int ret = -1;
845 846
    VIR_AUTOFREE(char *) parentPath = NULL;
    VIR_AUTOFREE(char *) newPath = NULL;
847
    virCgroupPtr parent = NULL;
848 849 850
    VIR_DEBUG("path=%s create=%d controllers=%x",
              path, create, controllers);

851 852 853 854 855 856
    if (path[0] != '/') {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Partition path '%s' must start with '/'"),
                       path);
        return -1;
    }
857

858
    if (virCgroupSetPartitionSuffix(path, &newPath) < 0)
859
        goto cleanup;
860

861 862
    if (virCgroupNew(-1, newPath, NULL, controllers, group) < 0)
        goto cleanup;
863

864
    if (STRNEQ(newPath, "/")) {
865
        char *tmp;
866
        if (VIR_STRDUP(parentPath, newPath) < 0)
867
            goto cleanup;
868 869 870 871 872

        tmp = strrchr(parentPath, '/');
        tmp++;
        *tmp = '\0';

873
        if (virCgroupNew(-1, parentPath, NULL, controllers, &parent) < 0)
874
            goto cleanup;
875

876
        if (virCgroupMakeGroup(parent, *group, create, VIR_CGROUP_NONE) < 0)
877
            goto cleanup;
878 879
    }

880 881 882
    ret = 0;
 cleanup:
    if (ret != 0)
883 884
        virCgroupFree(group);
    virCgroupFree(&parent);
885
    return ret;
886 887
}

888

G
Gao feng 已提交
889
/**
890
* virCgroupNewSelf:
G
Gao feng 已提交
891 892 893
*
* @group: Pointer to returned virCgroupPtr
*
894 895 896
* Obtain a cgroup representing the config of the
* current process
*
897
* Returns 0 on success, or -1 on error
G
Gao feng 已提交
898
*/
E
Eric Blake 已提交
899 900
int
virCgroupNewSelf(virCgroupPtr *group)
G
Gao feng 已提交
901
{
902
    return virCgroupNewDetect(-1, -1, group);
G
Gao feng 已提交
903
}
904

905

906 907 908 909 910 911 912 913
/**
 * virCgroupNewDomainPartition:
 *
 * @partition: partition holding the domain
 * @driver: name of the driver
 * @name: name of the domain
 * @group: Pointer to returned virCgroupPtr
 *
914
 * Returns 0 on success, or -1 on error
915
 */
E
Eric Blake 已提交
916 917 918 919 920 921
int
virCgroupNewDomainPartition(virCgroupPtr partition,
                            const char *driver,
                            const char *name,
                            bool create,
                            virCgroupPtr *group)
922
{
923
    VIR_AUTOFREE(char *)grpname = NULL;
924

925
    if (virAsprintf(&grpname, "%s.libvirt-%s",
926
                    name, driver) < 0)
927
        return -1;
928

929
    if (virCgroupPartitionEscape(&grpname) < 0)
930
        return -1;
931

932
    if (virCgroupNew(-1, grpname, partition, -1, group) < 0)
933
        return -1;
934 935 936 937 938 939 940 941 942 943 944

    /*
     * 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.
     */
E
Eric Blake 已提交
945 946
    if (virCgroupMakeGroup(partition, *group, create,
                           VIR_CGROUP_MEM_HIERACHY) < 0) {
947
        virCgroupFree(group);
948
        return -1;
949 950
    }

951
    return 0;
952
}
953

E
Eric Blake 已提交
954

955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
/**
 * 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)
{
973
    VIR_AUTOFREE(char *) name = NULL;
974 975 976 977 978
    int controllers;

    switch (nameval) {
    case VIR_CGROUP_THREAD_VCPU:
        if (virAsprintf(&name, "vcpu%d", id) < 0)
979
            return -1;
980 981 982
        break;
    case VIR_CGROUP_THREAD_EMULATOR:
        if (VIR_STRDUP(name, "emulator") < 0)
983
            return -1;
984 985 986
        break;
    case VIR_CGROUP_THREAD_IOTHREAD:
        if (virAsprintf(&name, "iothread%d", id) < 0)
987
            return -1;
988 989 990 991
        break;
    case VIR_CGROUP_THREAD_LAST:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected name value %d"), nameval);
992
        return -1;
993 994 995 996 997 998 999
    }

    controllers = ((1 << VIR_CGROUP_CONTROLLER_CPU) |
                   (1 << VIR_CGROUP_CONTROLLER_CPUACCT) |
                   (1 << VIR_CGROUP_CONTROLLER_CPUSET));

    if (virCgroupNew(-1, name, domain, controllers, group) < 0)
1000
        return -1;
1001

1002
    if (virCgroupMakeGroup(domain, *group, create, VIR_CGROUP_THREAD) < 0) {
1003
        virCgroupFree(group);
1004
        return -1;
1005 1006
    }

1007
    return 0;
1008 1009 1010
}


E
Eric Blake 已提交
1011 1012 1013 1014
int
virCgroupNewDetect(pid_t pid,
                   int controllers,
                   virCgroupPtr *group)
1015
{
1016
    return virCgroupNew(pid, "", NULL, controllers, group);
1017 1018
}

E
Eric Blake 已提交
1019

1020 1021 1022
/*
 * Returns 0 on success (but @group may be NULL), -1 on fatal error
 */
E
Eric Blake 已提交
1023 1024 1025 1026 1027
int
virCgroupNewDetectMachine(const char *name,
                          const char *drivername,
                          pid_t pid,
                          int controllers,
1028
                          char *machinename,
E
Eric Blake 已提交
1029
                          virCgroupPtr *group)
1030
{
1031 1032
    size_t i;

1033
    if (virCgroupNewDetect(pid, controllers, group) < 0) {
1034 1035 1036 1037 1038
        if (virCgroupNewIgnoreError())
            return 0;
        return -1;
    }

1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
    for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
        if ((*group)->backends[i] &&
            !(*group)->backends[i]->validateMachineGroup(*group, name,
                                                         drivername,
                                                         machinename)) {
            VIR_DEBUG("Failed to validate machine name for '%s' driver '%s'",
                      name, drivername);
            virCgroupFree(group);
            return 0;
        }
1049 1050 1051 1052 1053
    }

    return 0;
}

E
Eric Blake 已提交
1054

1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
static int
virCgroupEnableMissingControllers(char *path,
                                  pid_t pidleader,
                                  int controllers,
                                  virCgroupPtr *group)
{
    virCgroupPtr parent = NULL;
    char *offset = path;
    int ret = -1;

    if (virCgroupNew(pidleader,
1066
                     "/",
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
                     NULL,
                     controllers,
                     &parent) < 0)
        return ret;

    for (;;) {
        virCgroupPtr tmp;
        char *t = strchr(offset + 1, '/');
        if (t)
            *t = '\0';

        if (virCgroupNew(pidleader,
                         path,
                         parent,
                         controllers,
                         &tmp) < 0)
            goto cleanup;

1085
        if (virCgroupMakeGroup(parent, tmp, true, VIR_CGROUP_SYSTEMD) < 0) {
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
            virCgroupFree(&tmp);
            goto cleanup;
        }
        if (t) {
            *t = '/';
            offset = t;
            virCgroupFree(&parent);
            parent = tmp;
        } else {
            *group = tmp;
            break;
        }
    }

    ret = 0;
 cleanup:
    virCgroupFree(&parent);
    return ret;
}


1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
/*
 * 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,
1117 1118
                           size_t nnicindexes,
                           int *nicindexes,
1119 1120
                           const char *partition,
                           int controllers,
1121
                           unsigned int maxthreads,
1122
                           virCgroupPtr *group)
1123
{
1124
    int rv;
1125
    virCgroupPtr init;
1126
    VIR_AUTOFREE(char *) path = NULL;
1127
    size_t i;
1128 1129 1130 1131 1132 1133 1134 1135

    VIR_DEBUG("Trying to setup machine '%s' via systemd", name);
    if ((rv = virSystemdCreateMachine(name,
                                      drivername,
                                      uuid,
                                      rootdir,
                                      pidleader,
                                      isContainer,
1136 1137
                                      nnicindexes,
                                      nicindexes,
1138 1139
                                      partition,
                                      maxthreads)) < 0)
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
        return rv;

    if (controllers != -1)
        controllers |= (1 << VIR_CGROUP_CONTROLLER_SYSTEMD);

    VIR_DEBUG("Detecting systemd placement");
    if (virCgroupNewDetect(pidleader,
                           controllers,
                           &init) < 0)
        return -1;
1150

1151 1152 1153 1154 1155 1156
    for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
        if (init->backends[i] &&
            (path = init->backends[i]->stealPlacement(init))) {
            break;
        }
    }
1157
    virCgroupFree(&init);
1158 1159

    if (!path || STREQ(path, "/") || path[0] != '/') {
1160 1161
        VIR_DEBUG("Systemd didn't setup its controller, path=%s",
                  NULLSTR(path));
1162
        return -2;
1163 1164
    }

1165 1166
    if (virCgroupEnableMissingControllers(path, pidleader,
                                          controllers, group) < 0) {
1167
        return -1;
1168 1169
    }

1170 1171 1172 1173 1174 1175 1176 1177
    if (virCgroupAddProcess(*group, pidleader) < 0) {
        virErrorPtr saved = virSaveLastError();
        virCgroupRemove(*group);
        virCgroupFree(group);
        if (saved) {
            virSetError(saved);
            virFreeError(saved);
        }
1178 1179
    }

1180
    return 0;
1181
}
1182

E
Eric Blake 已提交
1183

1184 1185 1186
/*
 * Returns 0 on success, -1 on fatal error
 */
1187
int virCgroupTerminateMachine(const char *name)
1188
{
1189
    return virSystemdTerminateMachine(name);
1190 1191 1192
}


1193 1194 1195
static int
virCgroupNewMachineManual(const char *name,
                          const char *drivername,
1196
                          pid_t pidleader,
1197 1198 1199 1200
                          const char *partition,
                          int controllers,
                          virCgroupPtr *group)
{
1201 1202
    virCgroupPtr parent = NULL;
    int ret = -1;
1203 1204

    VIR_DEBUG("Fallback to non-systemd setup");
1205 1206 1207 1208 1209
    if (virCgroupNewPartition(partition,
                              STREQ(partition, "/machine"),
                              controllers,
                              &parent) < 0) {
        if (virCgroupNewIgnoreError())
1210
            goto done;
1211

1212
        goto cleanup;
1213 1214 1215 1216 1217 1218 1219
    }

    if (virCgroupNewDomainPartition(parent,
                                    drivername,
                                    name,
                                    true,
                                    group) < 0)
1220
        goto cleanup;
1221

1222
    if (virCgroupAddProcess(*group, pidleader) < 0) {
1223 1224
        virErrorPtr saved = virSaveLastError();
        virCgroupRemove(*group);
1225
        virCgroupFree(group);
1226 1227 1228 1229 1230 1231
        if (saved) {
            virSetError(saved);
            virFreeError(saved);
        }
    }

1232 1233 1234 1235
 done:
    ret = 0;

 cleanup:
1236
    virCgroupFree(&parent);
1237
    return ret;
1238 1239
}

E
Eric Blake 已提交
1240 1241 1242 1243 1244 1245 1246 1247

int
virCgroupNewMachine(const char *name,
                    const char *drivername,
                    const unsigned char *uuid,
                    const char *rootdir,
                    pid_t pidleader,
                    bool isContainer,
1248 1249
                    size_t nnicindexes,
                    int *nicindexes,
E
Eric Blake 已提交
1250 1251
                    const char *partition,
                    int controllers,
1252
                    unsigned int maxthreads,
E
Eric Blake 已提交
1253
                    virCgroupPtr *group)
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
{
    int rv;

    *group = NULL;

    if ((rv = virCgroupNewMachineSystemd(name,
                                         drivername,
                                         uuid,
                                         rootdir,
                                         pidleader,
                                         isContainer,
1265 1266
                                         nnicindexes,
                                         nicindexes,
1267 1268
                                         partition,
                                         controllers,
1269
                                         maxthreads,
1270 1271 1272 1273 1274 1275 1276 1277
                                         group)) == 0)
        return 0;

    if (rv == -1)
        return -1;

    return virCgroupNewMachineManual(name,
                                     drivername,
1278
                                     pidleader,
1279 1280 1281 1282 1283
                                     partition,
                                     controllers,
                                     group);
}

E
Eric Blake 已提交
1284 1285 1286

bool
virCgroupNewIgnoreError(void)
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
{
    if (virLastErrorIsSystemErrno(ENXIO) ||
        virLastErrorIsSystemErrno(EPERM) ||
        virLastErrorIsSystemErrno(EACCES)) {
        virResetLastError();
        VIR_DEBUG("No cgroups present/configured/accessible, ignoring error");
        return true;
    }
    return false;
}

E
Eric Blake 已提交
1298

E
Eric Blake 已提交
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
/**
 * 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)
{
1311 1312
    size_t i;

E
Eric Blake 已提交
1313 1314 1315 1316
    if (!cgroup)
        return false;
    if (controller < 0 || controller >= VIR_CGROUP_CONTROLLER_LAST)
        return false;
1317

1318 1319 1320 1321 1322 1323 1324 1325
    for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
        if (cgroup->backends[i] &&
            cgroup->backends[i]->hasController(cgroup, controller)) {
            return true;
        }
    }

    return false;
E
Eric Blake 已提交
1326 1327 1328 1329 1330
}


int
virCgroupPathOfController(virCgroupPtr group,
1331
                          unsigned int controller,
E
Eric Blake 已提交
1332 1333 1334
                          const char *key,
                          char **path)
{
1335 1336 1337
    if (controller >= VIR_CGROUP_CONTROLLER_LAST) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid controller id '%d'"), controller);
E
Eric Blake 已提交
1338 1339 1340
        return -1;
    }

1341 1342
    VIR_CGROUP_BACKEND_CALL(group, controller, pathOfController, -1,
                            controller, key, path);
E
Eric Blake 已提交
1343 1344 1345
}


1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363
/**
 * 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)
{
1364 1365
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            getBlkioIoServiced, -1,
1366 1367
                            bytes_read, bytes_write,
                            requests_read, requests_write);
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390
}


/**
 * 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)
{
1391 1392
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            getBlkioIoDeviceServiced, -1,
1393 1394
                            path, bytes_read, bytes_write,
                            requests_read, requests_write);
1395 1396 1397
}


1398 1399 1400 1401 1402 1403
/**
 * virCgroupSetBlkioWeight:
 *
 * @group: The cgroup to change io weight for
 * @weight: The Weight for this cgroup
 *
1404
 * Returns: 0 on success, -1 on error
1405
 */
E
Eric Blake 已提交
1406 1407
int
virCgroupSetBlkioWeight(virCgroupPtr group, unsigned int weight)
1408
{
1409 1410
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            setBlkioWeight, -1, weight);
1411 1412
}

E
Eric Blake 已提交
1413

1414 1415 1416 1417 1418 1419
/**
 * virCgroupGetBlkioWeight:
 *
 * @group: The cgroup to get weight for
 * @Weight: Pointer to returned weight
 *
1420
 * Returns: 0 on success, -1 on error
1421
 */
E
Eric Blake 已提交
1422 1423
int
virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight)
1424
{
1425 1426
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            getBlkioWeight, -1, weight);
1427 1428
}

1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
/**
 * 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
 */
int
virCgroupSetBlkioDeviceReadIops(virCgroupPtr group,
                                const char *path,
                                unsigned int riops)
{
1442 1443
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            setBlkioDeviceReadIops, -1, path, riops);
1444 1445
}

E
Eric Blake 已提交
1446

1447
/**
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
 * 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
 */
int
virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group,
                                 const char *path,
                                 unsigned int wiops)
{
1460 1461
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            setBlkioDeviceWriteIops, -1, path, wiops);
1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477
}


/**
 * 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
 */
int
virCgroupSetBlkioDeviceReadBps(virCgroupPtr group,
                               const char *path,
                               unsigned long long rbps)
{
1478 1479
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            setBlkioDeviceReadBps, -1, path, rbps);
1480 1481 1482 1483 1484 1485 1486
}

/**
 * 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
1487
 *
1488 1489 1490 1491 1492 1493 1494
 * Returns: 0 on success, -1 on error
 */
int
virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group,
                                const char *path,
                                unsigned long long wbps)
{
1495 1496
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            setBlkioDeviceWriteBps, -1, path, wbps);
1497 1498 1499 1500 1501 1502 1503
}


/**
 * virCgroupSetBlkioDeviceWeight:
 * @group: The cgroup to change block io setting for
 * @path: The path of device
1504 1505
 * @weight: The new device weight (100-1000),
 * (10-1000) after kernel 2.6.39, or 0 to clear
1506
 *
1507
 * Returns: 0 on success, -1 on error
1508
 */
E
Eric Blake 已提交
1509 1510 1511 1512
int
virCgroupSetBlkioDeviceWeight(virCgroupPtr group,
                              const char *path,
                              unsigned int weight)
1513
{
1514 1515
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            setBlkioDeviceWeight, -1, path, weight);
1516
}
1517

1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530
/**
 * 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
 */
int
virCgroupGetBlkioDeviceReadIops(virCgroupPtr group,
                                const char *path,
                                unsigned int *riops)
{
1531 1532
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            getBlkioDeviceReadIops, -1, path, riops);
1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547
}

/**
 * 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
 */
int
virCgroupGetBlkioDeviceWriteIops(virCgroupPtr group,
                                 const char *path,
                                 unsigned int *wiops)
{
1548 1549
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            getBlkioDeviceWriteIops, -1, path, wiops);
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
}

/**
 * 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
 */
int
virCgroupGetBlkioDeviceReadBps(virCgroupPtr group,
                               const char *path,
                               unsigned long long *rbps)
{
1565 1566
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            getBlkioDeviceReadBps, -1, path, rbps);
1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581
}

/**
 * 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
 */
int
virCgroupGetBlkioDeviceWriteBps(virCgroupPtr group,
                                const char *path,
                                unsigned long long *wbps)
{
1582 1583
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            getBlkioDeviceWriteBps, -1, path, wbps);
1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598
}

/**
 * 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
 */
int
virCgroupGetBlkioDeviceWeight(virCgroupPtr group,
                              const char *path,
                              unsigned int *weight)
{
1599 1600
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
                            getBlkioDeviceWeight, -1, path, weight);
1601 1602
}

1603

1604 1605 1606 1607 1608 1609 1610 1611
/**
 * virCgroupSetMemory:
 *
 * @group: The cgroup to change memory for
 * @kb: The memory amount in kilobytes
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1612 1613
int
virCgroupSetMemory(virCgroupPtr group, unsigned long long kb)
1614
{
1615 1616
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
                            setMemory, -1, kb);
1617 1618
}

E
Eric Blake 已提交
1619

1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641
/**
 * 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)
{
1642 1643
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
                            getMemoryStat, -1, cache,
1644 1645 1646
                            activeAnon, inactiveAnon,
                            activeFile, inactiveFile,
                            unevictable);
1647 1648 1649
}


R
Ryota Ozaki 已提交
1650 1651 1652 1653 1654 1655 1656 1657
/**
 * virCgroupGetMemoryUsage:
 *
 * @group: The cgroup to change memory for
 * @kb: Pointer to returned used memory in kilobytes
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1658 1659
int
virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb)
R
Ryota Ozaki 已提交
1660
{
1661 1662
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
                            getMemoryUsage, -1, kb);
R
Ryota Ozaki 已提交
1663 1664
}

E
Eric Blake 已提交
1665

1666 1667 1668 1669 1670 1671 1672 1673
/**
 * virCgroupSetMemoryHardLimit:
 *
 * @group: The cgroup to change memory hard limit for
 * @kb: The memory amount in kilobytes
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1674 1675
int
virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long long kb)
1676
{
1677 1678
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
                            setMemoryHardLimit, -1, kb);
1679 1680
}

E
Eric Blake 已提交
1681

1682 1683 1684 1685 1686 1687 1688 1689
/**
 * virCgroupGetMemoryHardLimit:
 *
 * @group: The cgroup to get the memory hard limit for
 * @kb: The memory amount in kilobytes
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1690 1691
int
virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long long *kb)
1692
{
1693 1694
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
                            getMemoryHardLimit, -1, kb);
1695 1696
}

E
Eric Blake 已提交
1697

1698 1699 1700 1701 1702 1703 1704 1705
/**
 * virCgroupSetMemorySoftLimit:
 *
 * @group: The cgroup to change memory soft limit for
 * @kb: The memory amount in kilobytes
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1706 1707
int
virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long long kb)
1708
{
1709 1710
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
                            setMemorySoftLimit, -1, kb);
1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
}


/**
 * virCgroupGetMemorySoftLimit:
 *
 * @group: The cgroup to get the memory soft limit for
 * @kb: The memory amount in kilobytes
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1722 1723
int
virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long long *kb)
1724
{
1725 1726
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
                            getMemorySoftLimit, -1, kb);
1727 1728
}

E
Eric Blake 已提交
1729

1730
/**
1731
 * virCgroupSetMemSwapHardLimit:
1732
 *
1733 1734
 * @group: The cgroup to change mem+swap hard limit for
 * @kb: The mem+swap amount in kilobytes
1735 1736 1737
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1738 1739
int
virCgroupSetMemSwapHardLimit(virCgroupPtr group, unsigned long long kb)
1740
{
1741 1742
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
                            setMemSwapHardLimit, -1, kb);
1743 1744
}

E
Eric Blake 已提交
1745

1746
/**
1747
 * virCgroupGetMemSwapHardLimit:
1748
 *
1749 1750
 * @group: The cgroup to get mem+swap hard limit for
 * @kb: The mem+swap amount in kilobytes
1751 1752 1753
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1754 1755
int
virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb)
1756
{
1757 1758
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
                            getMemSwapHardLimit, -1, kb);
1759 1760
}

E
Eric Blake 已提交
1761

G
Gao feng 已提交
1762 1763 1764 1765 1766 1767 1768 1769
/**
 * virCgroupGetMemSwapUsage:
 *
 * @group: The cgroup to get mem+swap usage for
 * @kb: The mem+swap amount in kilobytes
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1770 1771
int
virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb)
G
Gao feng 已提交
1772
{
1773 1774
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
                            getMemSwapUsage, -1, kb);
G
Gao feng 已提交
1775 1776
}

E
Eric Blake 已提交
1777

1778 1779 1780 1781 1782 1783 1784 1785
/**
 * virCgroupSetCpusetMems:
 *
 * @group: The cgroup to set cpuset.mems for
 * @mems: the numa nodes to set
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1786 1787
int
virCgroupSetCpusetMems(virCgroupPtr group, const char *mems)
1788
{
1789 1790
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
                            setCpusetMems, -1, mems);
1791 1792
}

E
Eric Blake 已提交
1793

1794 1795 1796 1797 1798 1799 1800 1801
/**
 * virCgroupGetCpusetMems:
 *
 * @group: The cgroup to get cpuset.mems for
 * @mems: the numa nodes to get
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1802 1803
int
virCgroupGetCpusetMems(virCgroupPtr group, char **mems)
1804
{
1805 1806
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
                            getCpusetMems, -1, mems);
1807 1808
}

E
Eric Blake 已提交
1809

1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820
/**
 * 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)
{
1821 1822
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
                            setCpusetMemoryMigrate, -1, migrate);
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836
}


/**
 * virCgroupGetCpusetMemoryMigrate:
 *
 * @group: The cgroup to get cpuset.memory_migrate for
 * @migrate: Migration setting
 *
 * Returns: 0 on success
 */
int
virCgroupGetCpusetMemoryMigrate(virCgroupPtr group, bool *migrate)
{
1837 1838
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
                            getCpusetMemoryMigrate, -1, migrate);
1839 1840 1841
}


1842 1843 1844 1845 1846 1847
/**
 * virCgroupSetCpusetCpus:
 *
 * @group: The cgroup to set cpuset.cpus for
 * @cpus: the cpus to set
 *
N
Nitesh Konkar 已提交
1848
 * Returns: 0 on success
1849
 */
E
Eric Blake 已提交
1850 1851
int
virCgroupSetCpusetCpus(virCgroupPtr group, const char *cpus)
1852
{
1853 1854
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
                            setCpusetCpus, -1, cpus);
1855 1856
}

E
Eric Blake 已提交
1857

1858 1859 1860 1861 1862 1863
/**
 * virCgroupGetCpusetCpus:
 *
 * @group: The cgroup to get cpuset.cpus for
 * @cpus: the cpus to get
 *
N
Nitesh Konkar 已提交
1864
 * Returns: 0 on success
1865
 */
E
Eric Blake 已提交
1866 1867
int
virCgroupGetCpusetCpus(virCgroupPtr group, char **cpus)
1868
{
1869 1870
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
                            getCpusetCpus, -1, cpus);
1871 1872
}

E
Eric Blake 已提交
1873

1874 1875 1876
/**
 * virCgroupDenyAllDevices:
 *
1877
 * @group: The cgroup to deny all permissions, for all devices
1878 1879 1880
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1881 1882
int
virCgroupDenyAllDevices(virCgroupPtr group)
1883
{
1884 1885
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
                            denyAllDevices, -1);
1886 1887
}

1888 1889 1890
/**
 * virCgroupAllowAllDevices:
 *
1891
 * Allows the permission for all devices by setting lines similar
1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904
 * 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)
{
1905 1906
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
                            allowAllDevices, -1, perms);
1907 1908
}

E
Eric Blake 已提交
1909

1910 1911 1912 1913 1914
/**
 * virCgroupAllowDevice:
 *
 * @group: The cgroup to allow a device for
 * @type: The device type (i.e., 'c' or 'b')
1915 1916
 * @major: The major number of the device, a negative value means '*'
 * @minor: The minor number of the device, a negative value means '*'
1917
 * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow
1918 1919 1920
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1921 1922 1923
int
virCgroupAllowDevice(virCgroupPtr group, char type, int major, int minor,
                     int perms)
1924
{
1925 1926
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
                            allowDevice, -1, type, major, minor, perms);
1927
}
1928

E
Eric Blake 已提交
1929

1930 1931 1932 1933 1934
/**
 * virCgroupAllowDevicePath:
 *
 * @group: The cgroup to allow the device for
 * @path: the device to allow
1935
 * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow
1936
 * @ignoreEacces: Ignore lack of permission (mostly for NFS mounts)
1937 1938 1939 1940
 *
 * Queries the type of device and its major/minor number, and
 * adds that to the cgroup ACL
 *
1941
 * Returns: 0 on success, 1 if path exists but is not a device or is not
1942
 * accessible, or * -1 on error
1943
 */
E
Eric Blake 已提交
1944
int
1945 1946 1947 1948
virCgroupAllowDevicePath(virCgroupPtr group,
                         const char *path,
                         int perms,
                         bool ignoreEacces)
1949 1950 1951
{
    struct stat sb;

1952
    if (stat(path, &sb) < 0) {
1953 1954 1955
        if (errno == EACCES && ignoreEacces)
            return 1;

1956 1957 1958 1959 1960
        virReportSystemError(errno,
                             _("Path '%s' is not accessible"),
                             path);
        return -1;
    }
1961 1962

    if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode))
1963
        return 1;
1964

1965 1966
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
                            allowDevice, -1,
1967 1968 1969 1970
                            S_ISCHR(sb.st_mode) ? 'c' : 'b',
                            major(sb.st_rdev),
                            minor(sb.st_rdev),
                            perms);
1971
}
D
Daniel P. Berrange 已提交
1972

1973 1974 1975 1976 1977 1978

/**
 * virCgroupDenyDevice:
 *
 * @group: The cgroup to deny a device for
 * @type: The device type (i.e., 'c' or 'b')
1979 1980
 * @major: The major number of the device, a negative value means '*'
 * @minor: The minor number of the device, a negative value means '*'
1981
 * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to deny
1982 1983 1984
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
1985 1986 1987
int
virCgroupDenyDevice(virCgroupPtr group, char type, int major, int minor,
                    int perms)
1988
{
1989 1990
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
                            denyDevice, -1, type, major, minor, perms);
1991 1992
}

E
Eric Blake 已提交
1993

1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007
/**
 * 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.
 */
E
Eric Blake 已提交
2008
int
2009 2010 2011 2012
virCgroupDenyDevicePath(virCgroupPtr group,
                        const char *path,
                        int perms,
                        bool ignoreEacces)
2013 2014 2015
{
    struct stat sb;

2016
    if (stat(path, &sb) < 0) {
2017 2018 2019
        if (errno == EACCES && ignoreEacces)
            return 1;

2020 2021 2022 2023 2024
        virReportSystemError(errno,
                             _("Path '%s' is not accessible"),
                             path);
        return -1;
    }
2025 2026

    if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode))
2027
        return 1;
2028

2029 2030
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
                            denyDevice, -1,
2031 2032 2033 2034
                            S_ISCHR(sb.st_mode) ? 'c' : 'b',
                            major(sb.st_rdev),
                            minor(sb.st_rdev),
                            perms);
2035 2036
}

E
Eric Blake 已提交
2037

2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053
/* 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,
2054
                          virBitmapPtr guestvcpus,
2055
                          unsigned long long *sum_cpu_time,
2056 2057
                          size_t nsum,
                          virBitmapPtr cpumap)
2058
{
2059
    int ret = -1;
2060
    ssize_t i = -1;
2061
    virCgroupPtr group_vcpu = NULL;
2062

2063
    while ((i = virBitmapNextSetBit(guestvcpus, i)) >= 0) {
2064
        VIR_AUTOFREE(char *) buf = NULL;
2065 2066
        char *pos;
        unsigned long long tmp;
2067
        ssize_t j;
2068

J
John Ferlan 已提交
2069 2070
        if (virCgroupNewThread(group, VIR_CGROUP_THREAD_VCPU, i,
                               false, &group_vcpu) < 0)
2071
            goto cleanup;
2072 2073

        if (virCgroupGetCpuacctPercpuUsage(group_vcpu, &buf) < 0)
2074
            goto cleanup;
2075 2076

        pos = buf;
2077 2078 2079
        for (j = virBitmapNextSetBit(cpumap, -1);
             j >= 0 && j < nsum;
             j = virBitmapNextSetBit(cpumap, j)) {
2080 2081 2082
            if (virStrToLong_ull(pos, &pos, 10, &tmp) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cpuacct parse error"));
2083
                goto cleanup;
2084 2085 2086
            }
            sum_cpu_time[j] += tmp;
        }
2087

2088
        virCgroupFree(&group_vcpu);
2089 2090
    }

2091 2092
    ret = 0;
 cleanup:
2093
    virCgroupFree(&group_vcpu);
2094
    return ret;
2095 2096 2097
}


2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117
/**
 * 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.
 */
2118 2119 2120 2121 2122
int
virCgroupGetPercpuStats(virCgroupPtr group,
                        virTypedParameterPtr params,
                        unsigned int nparams,
                        int start_cpu,
2123
                        unsigned int ncpus,
2124
                        virBitmapPtr guestvcpus)
2125
{
2126
    int ret = -1;
2127
    size_t i;
2128
    int need_cpus, total_cpus;
2129
    char *pos;
2130 2131
    VIR_AUTOFREE(char *) buf = NULL;
    VIR_AUTOFREE(unsigned long long *) sum_cpu_time = NULL;
2132 2133 2134
    virTypedParameterPtr ent;
    int param_idx;
    unsigned long long cpu_time;
2135
    virBitmapPtr cpumap = NULL;
2136 2137

    /* return the number of supported params */
2138
    if (nparams == 0 && ncpus != 0) {
2139
        if (!guestvcpus)
2140 2141 2142 2143
            return CGROUP_NB_PER_CPU_STAT_PARAM;
        else
            return CGROUP_NB_PER_CPU_STAT_PARAM + 1;
    }
2144 2145

    /* To parse account file, we need to know how many cpus are present.  */
2146
    if (!(cpumap = virHostCPUGetPresentBitmap()))
2147
        return -1;
2148

2149 2150
    total_cpus = virBitmapSize(cpumap);

2151
    /* return total number of cpus */
2152 2153 2154 2155
    if (ncpus == 0) {
        ret = total_cpus;
        goto cleanup;
    }
2156

2157
    if (start_cpu >= total_cpus) {
2158 2159
        virReportError(VIR_ERR_INVALID_ARG,
                       _("start_cpu %d larger than maximum of %d"),
2160
                       start_cpu, total_cpus - 1);
2161
        goto cleanup;
2162 2163 2164 2165
    }

    /* we get percpu cputime accounting info. */
    if (virCgroupGetCpuacctPercpuUsage(group, &buf))
2166
        goto cleanup;
2167 2168 2169 2170 2171 2172
    pos = buf;

    /* return percpu cputime in index 0 */
    param_idx = 0;

    /* number of cpus to compute */
J
Ján Tomko 已提交
2173
    need_cpus = MIN(total_cpus, start_cpu + ncpus);
2174

J
Ján Tomko 已提交
2175
    for (i = 0; i < need_cpus; i++) {
J
Ján Tomko 已提交
2176
        if (!virBitmapIsBitSet(cpumap, i)) {
2177 2178
            cpu_time = 0;
        } else if (virStrToLong_ull(pos, &pos, 10, &cpu_time) < 0) {
2179 2180
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cpuacct parse error"));
2181
            goto cleanup;
2182 2183 2184 2185 2186 2187
        }
        if (i < start_cpu)
            continue;
        ent = &params[(i - start_cpu) * nparams + param_idx];
        if (virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME,
                                    VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
2188
            goto cleanup;
2189 2190
    }

2191
    /* return percpu vcputime in index 1 */
2192
    param_idx = 1;
2193

2194
    if (guestvcpus && param_idx < nparams) {
2195
        if (VIR_ALLOC_N(sum_cpu_time, need_cpus) < 0)
2196
            goto cleanup;
2197 2198
        if (virCgroupGetPercpuVcpuSum(group, guestvcpus, sum_cpu_time,
                                      need_cpus, cpumap) < 0)
2199
            goto cleanup;
2200 2201

        for (i = start_cpu; i < need_cpus; i++) {
2202 2203
            int idx = (i - start_cpu) * nparams + param_idx;
            if (virTypedParameterAssign(&params[idx],
2204 2205 2206
                                        VIR_DOMAIN_CPU_STATS_VCPUTIME,
                                        VIR_TYPED_PARAM_ULLONG,
                                        sum_cpu_time[i]) < 0)
2207
                goto cleanup;
2208 2209 2210
        }

        param_idx++;
2211 2212
    }

2213 2214 2215 2216 2217
    ret = param_idx;

 cleanup:
    virBitmapFree(cpumap);
    return ret;
2218 2219
}

2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269

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(&params[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(&params[1],
                                    VIR_DOMAIN_CPU_STATS_USERTIME,
                                    VIR_TYPED_PARAM_ULLONG, user) < 0)
            return -1;
        if (nparams > 2 &&
            virTypedParameterAssign(&params[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;
}


E
Eric Blake 已提交
2270 2271
int
virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares)
2272
{
2273 2274
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
                            setCpuShares, -1, shares);
2275 2276
}

E
Eric Blake 已提交
2277 2278 2279

int
virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares)
2280
{
2281 2282
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
                            getCpuShares, -1, shares);
2283
}
2284

E
Eric Blake 已提交
2285

2286 2287 2288 2289 2290 2291 2292 2293
/**
 * virCgroupSetCpuCfsPeriod:
 *
 * @group: The cgroup to change cpu.cfs_period_us for
 * @cfs_period: The bandwidth period in usecs
 *
 * Returns: 0 on success
 */
E
Eric Blake 已提交
2294 2295
int
virCgroupSetCpuCfsPeriod(virCgroupPtr group, unsigned long long cfs_period)
2296
{
2297 2298
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
                            setCpuCfsPeriod, -1, cfs_period);
2299 2300
}

E
Eric Blake 已提交
2301

2302 2303 2304 2305 2306 2307 2308 2309
/**
 * 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
 */
E
Eric Blake 已提交
2310 2311
int
virCgroupGetCpuCfsPeriod(virCgroupPtr group, unsigned long long *cfs_period)
2312
{
2313 2314
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
                            getCpuCfsPeriod, -1, cfs_period);
2315 2316
}

E
Eric Blake 已提交
2317

2318 2319 2320 2321 2322 2323 2324 2325 2326
/**
 * 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
 */
E
Eric Blake 已提交
2327 2328
int
virCgroupSetCpuCfsQuota(virCgroupPtr group, long long cfs_quota)
2329
{
2330 2331
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
                            setCpuCfsQuota, -1, cfs_quota);
2332 2333
}

E
Eric Blake 已提交
2334 2335 2336

int
virCgroupGetCpuacctPercpuUsage(virCgroupPtr group, char **usage)
2337
{
2338 2339
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT,
                            getCpuacctPercpuUsage, -1, usage);
2340 2341
}

E
Eric Blake 已提交
2342

2343
int
E
Eric Blake 已提交
2344 2345 2346 2347 2348
virCgroupRemoveRecursively(char *grppath)
{
    DIR *grpdir;
    struct dirent *ent;
    int rc = 0;
E
Eric Blake 已提交
2349
    int direrr;
E
Eric Blake 已提交
2350

J
Ján Tomko 已提交
2351
    if (virDirOpenQuiet(&grpdir, grppath) < 0) {
E
Eric Blake 已提交
2352 2353 2354 2355 2356 2357 2358
        if (errno == ENOENT)
            return 0;
        rc = -errno;
        VIR_ERROR(_("Unable to open %s (%d)"), grppath, errno);
        return rc;
    }

E
Eric Blake 已提交
2359 2360 2361
    /* 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) {
2362
        VIR_AUTOFREE(char *) path = NULL;
E
Eric Blake 已提交
2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373

        if (ent->d_type != DT_DIR) continue;

        if (virAsprintf(&path, "%s/%s", grppath, ent->d_name) == -1) {
            rc = -ENOMEM;
            break;
        }
        rc = virCgroupRemoveRecursively(path);
        if (rc != 0)
            break;
    }
E
Eric Blake 已提交
2374 2375 2376 2377 2378
    if (direrr < 0) {
        rc = -errno;
        VIR_ERROR(_("Failed to readdir for %s (%d)"), grppath, errno);
    }

J
Ján Tomko 已提交
2379
    VIR_DIR_CLOSE(grpdir);
E
Eric Blake 已提交
2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405

    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)
{
2406 2407 2408
    size_t i;

    for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
2409 2410 2411 2412
        if (group->backends[i]) {
            int rc = group->backends[i]->remove(group);
            if (rc < 0)
                return rc;
2413 2414 2415 2416
        }
    }

    return 0;
E
Eric Blake 已提交
2417 2418 2419
}


2420 2421 2422
/*
 * Returns 1 if some PIDs are killed, 0 if none are killed, or -1 on error
 */
E
Eric Blake 已提交
2423
static int
2424 2425 2426 2427 2428
virCgroupKillInternal(virCgroupPtr group,
                      int signum,
                      virHashTablePtr pids,
                      int controller,
                      const char *taskFile)
2429
{
2430
    int ret = -1;
2431
    bool killedAny = false;
2432
    VIR_AUTOFREE(char *) keypath = NULL;
2433
    bool done = false;
E
Eric Blake 已提交
2434 2435 2436
    FILE *fp = NULL;
    VIR_DEBUG("group=%p path=%s signum=%d pids=%p",
              group, group->path, signum, pids);
2437

2438
    if (virCgroupPathOfController(group, controller, taskFile, &keypath) < 0)
2439
        return -1;
2440 2441 2442 2443 2444 2445 2446

    /* 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"))) {
2447 2448 2449 2450 2451 2452
            if (errno == ENOENT) {
                VIR_DEBUG("No file %s, assuming done", keypath);
                killedAny = false;
                goto done;
            }

2453 2454 2455
            virReportSystemError(errno,
                                 _("Failed to read %s"),
                                 keypath);
2456 2457 2458
            goto cleanup;
        } else {
            while (!feof(fp)) {
M
Michal Privoznik 已提交
2459 2460
                long pid_value;
                if (fscanf(fp, "%ld", &pid_value) != 1) {
2461 2462
                    if (feof(fp))
                        break;
2463 2464 2465
                    virReportSystemError(errno,
                                         _("Failed to read %s"),
                                         keypath);
E
Eric Blake 已提交
2466
                    goto cleanup;
2467
                }
2468
                if (virHashLookup(pids, (void*)pid_value))
2469 2470
                    continue;

M
Michal Privoznik 已提交
2471
                VIR_DEBUG("pid=%ld", pid_value);
2472 2473
                /* Cgroups is a Linux concept, so this cast is safe.  */
                if (kill((pid_t)pid_value, signum) < 0) {
2474
                    if (errno != ESRCH) {
2475
                        virReportSystemError(errno,
M
Michal Privoznik 已提交
2476
                                             _("Failed to kill process %ld"),
2477
                                             pid_value);
2478 2479 2480 2481
                        goto cleanup;
                    }
                    /* Leave RC == 0 since we didn't kill one */
                } else {
2482
                    killedAny = true;
2483 2484 2485
                    done = false;
                }

2486
                ignore_value(virHashAddEntry(pids, (void*)pid_value, (void*)1));
2487 2488 2489 2490 2491
            }
            VIR_FORCE_FCLOSE(fp);
        }
    }

2492
 done:
2493
    ret = killedAny ? 1 : 0;
2494

2495
 cleanup:
E
Eric Blake 已提交
2496
    VIR_FORCE_FCLOSE(fp);
2497

2498
    return ret;
2499 2500 2501
}


E
Eric Blake 已提交
2502 2503
static uint32_t
virCgroupPidCode(const void *name, uint32_t seed)
2504
{
M
Michal Privoznik 已提交
2505
    long pid_value = (long)(intptr_t)name;
2506
    return virHashCodeGen(&pid_value, sizeof(pid_value), seed);
2507
}
E
Eric Blake 已提交
2508 2509 2510 2511


static bool
virCgroupPidEqual(const void *namea, const void *nameb)
2512 2513 2514
{
    return namea == nameb;
}
E
Eric Blake 已提交
2515 2516 2517 2518


static void *
virCgroupPidCopy(const void *name)
2519 2520 2521 2522
{
    return (void*)name;
}

E
Eric Blake 已提交
2523

2524
int
E
Eric Blake 已提交
2525 2526 2527
virCgroupKillRecursiveInternal(virCgroupPtr group,
                               int signum,
                               virHashTablePtr pids,
2528 2529
                               int controller,
                               const char *taskFile,
E
Eric Blake 已提交
2530
                               bool dormdir)
2531
{
2532
    int ret = -1;
2533
    int rc;
2534
    bool killedAny = false;
2535
    VIR_AUTOFREE(char *) keypath = NULL;
2536
    DIR *dp = NULL;
2537
    virCgroupPtr subgroup = NULL;
2538
    struct dirent *ent;
E
Eric Blake 已提交
2539
    int direrr;
E
Eric Blake 已提交
2540 2541
    VIR_DEBUG("group=%p path=%s signum=%d pids=%p",
              group, group->path, signum, pids);
2542

2543
    if (virCgroupPathOfController(group, controller, "", &keypath) < 0)
2544
        return -1;
2545

2546 2547
    if ((rc = virCgroupKillInternal(group, signum, pids,
                                    controller, taskFile)) < 0) {
2548
        goto cleanup;
2549
    }
2550 2551
    if (rc == 1)
        killedAny = true;
2552

2553
    VIR_DEBUG("Iterate over children of %s (killedAny=%d)", keypath, killedAny);
J
Ján Tomko 已提交
2554
    if ((rc = virDirOpenIfExists(&dp, keypath)) < 0)
2555
        goto cleanup;
J
Ján Tomko 已提交
2556 2557 2558 2559 2560

    if (rc == 0) {
        VIR_DEBUG("Path %s does not exist, assuming done", keypath);
        killedAny = false;
        goto done;
2561 2562
    }

E
Eric Blake 已提交
2563
    while ((direrr = virDirRead(dp, &ent, keypath)) > 0) {
2564 2565 2566 2567 2568
        if (ent->d_type != DT_DIR)
            continue;

        VIR_DEBUG("Process subdir %s", ent->d_name);

2569
        if (virCgroupNew(-1, ent->d_name, group, -1, &subgroup) < 0)
2570 2571
            goto cleanup;

E
Eric Blake 已提交
2572
        if ((rc = virCgroupKillRecursiveInternal(subgroup, signum, pids,
2573
                                                 controller, taskFile, true)) < 0)
2574 2575
            goto cleanup;
        if (rc == 1)
2576
            killedAny = true;
2577 2578 2579

        if (dormdir)
            virCgroupRemove(subgroup);
2580

2581
        virCgroupFree(&subgroup);
2582
    }
E
Eric Blake 已提交
2583 2584
    if (direrr < 0)
        goto cleanup;
2585

2586
 done:
2587
    ret = killedAny ? 1 : 0;
2588

2589
 cleanup:
2590
    virCgroupFree(&subgroup);
J
Ján Tomko 已提交
2591
    VIR_DIR_CLOSE(dp);
2592
    return ret;
2593 2594
}

E
Eric Blake 已提交
2595 2596 2597

int
virCgroupKillRecursive(virCgroupPtr group, int signum)
2598
{
2599 2600 2601
    int ret = 0;
    int rc;
    size_t i;
2602
    bool backendAvailable = false;
2603
    virCgroupBackendPtr *backends = virCgroupBackendGetAll();
2604 2605 2606 2607 2608 2609
    virHashTablePtr pids = virHashCreateFull(100,
                                             NULL,
                                             virCgroupPidCode,
                                             virCgroupPidEqual,
                                             virCgroupPidCopy,
                                             NULL);
2610

2611
    VIR_DEBUG("group=%p path=%s signum=%d", group, group->path, signum);
2612

2613
    for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
2614 2615
        if (backends && backends[i] && backends[i]->available()) {
            backendAvailable = true;
2616 2617 2618 2619 2620 2621 2622 2623 2624 2625
            rc = backends[i]->killRecursive(group, signum, pids);
            if (rc < 0) {
                ret = -1;
                goto cleanup;
            }
            if (rc > 0)
                ret = rc;
        }
    }

2626 2627 2628 2629 2630 2631
    if (!backends || !backendAvailable) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no cgroup backend available"));
        goto cleanup;
    }

2632 2633
 cleanup:
    virHashFree(pids);
2634
    return ret;
2635 2636 2637
}


E
Eric Blake 已提交
2638 2639
int
virCgroupKillPainfully(virCgroupPtr group)
2640
{
2641
    size_t i;
2642
    int ret;
2643
    VIR_DEBUG("cgroup=%p path=%s", group, group->path);
2644
    for (i = 0; i < 15; i++) {
2645 2646 2647 2648 2649 2650
        int signum;
        if (i == 0)
            signum = SIGTERM;
        else if (i == 8)
            signum = SIGKILL;
        else
J
Ján Tomko 已提交
2651
            signum = 0; /* Just check for existence */
2652

2653 2654 2655 2656
        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)
2657 2658
            break;

2659
        g_usleep(200 * 1000);
2660
    }
2661 2662
    VIR_DEBUG("Complete %d", ret);
    return ret;
2663
}
2664

E
Eric Blake 已提交
2665

2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677
/**
 * 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)
{
2678 2679
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
                            getCpuCfsQuota, -1, cfs_quota);
2680 2681 2682 2683 2684 2685
}


int
virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage)
{
2686 2687
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT,
                            getCpuacctUsage, -1, usage);
2688 2689 2690 2691 2692 2693 2694
}


int
virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user,
                        unsigned long long *sys)
{
2695 2696
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT,
                            getCpuacctStat, -1, user, sys);
2697 2698 2699 2700 2701 2702
}


int
virCgroupSetFreezerState(virCgroupPtr group, const char *state)
{
2703 2704
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_FREEZER,
                            setFreezerState, -1, state);
2705 2706 2707 2708 2709 2710
}


int
virCgroupGetFreezerState(virCgroupPtr group, char **state)
{
2711 2712
    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_FREEZER,
                            getFreezerState, -1, state);
2713 2714 2715
}


E
Eric Blake 已提交
2716
int
2717 2718
virCgroupBindMount(virCgroupPtr group, const char *oldroot,
                   const char *mountopts)
2719
{
2720 2721 2722 2723 2724 2725 2726 2727 2728 2729
    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;
2730
}
2731 2732


2733 2734 2735 2736 2737
int virCgroupSetOwner(virCgroupPtr cgroup,
                      uid_t uid,
                      gid_t gid,
                      int controllers)
{
2738 2739 2740 2741 2742 2743 2744 2745 2746 2747
    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;
2748 2749 2750
}


2751 2752 2753 2754 2755 2756 2757 2758 2759 2760
/**
 * 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)
{
2761 2762
    VIR_CGROUP_BACKEND_CALL(cgroup, VIR_CGROUP_CONTROLLER_CPU,
                            supportsCpuBW, false);
2763 2764
}

2765 2766 2767
int
virCgroupHasEmptyTasks(virCgroupPtr cgroup, int controller)
{
2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778
    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;
2779
}
2780

2781 2782 2783
bool
virCgroupControllerAvailable(int controller)
{
2784 2785
    virCgroupPtr cgroup;
    bool ret = false;
2786 2787

    if (virCgroupNewSelf(&cgroup) < 0)
2788
        return ret;
2789

2790
    ret = virCgroupHasController(cgroup, controller);
2791
    virCgroupFree(&cgroup);
2792
    return ret;
2793 2794
}

2795
#else /* !__linux__ */
2796

2797 2798 2799 2800 2801 2802 2803
bool
virCgroupAvailable(void)
{
    return false;
}


2804
int
J
Ján Tomko 已提交
2805 2806 2807 2808
virCgroupNewPartition(const char *path G_GNUC_UNUSED,
                      bool create G_GNUC_UNUSED,
                      int controllers G_GNUC_UNUSED,
                      virCgroupPtr *group G_GNUC_UNUSED)
2809 2810 2811 2812 2813 2814 2815 2816
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
2817
virCgroupNewSelf(virCgroupPtr *group G_GNUC_UNUSED)
2818 2819 2820 2821 2822 2823 2824 2825
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
2826 2827 2828 2829 2830
virCgroupNewDomainPartition(virCgroupPtr partition G_GNUC_UNUSED,
                            const char *driver G_GNUC_UNUSED,
                            const char *name G_GNUC_UNUSED,
                            bool create G_GNUC_UNUSED,
                            virCgroupPtr *group G_GNUC_UNUSED)
2831 2832 2833 2834 2835 2836 2837
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


2838
int
J
Ján Tomko 已提交
2839 2840 2841 2842 2843
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)
2844 2845 2846 2847 2848 2849 2850
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


2851
int
J
Ján Tomko 已提交
2852 2853 2854
virCgroupNewDetect(pid_t pid G_GNUC_UNUSED,
                   int controllers G_GNUC_UNUSED,
                   virCgroupPtr *group G_GNUC_UNUSED)
2855 2856 2857 2858 2859 2860 2861
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


2862
int
J
Ján Tomko 已提交
2863 2864 2865 2866 2867 2868
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)
2869 2870 2871 2872 2873 2874
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

J
Ján Tomko 已提交
2875

J
Ján Tomko 已提交
2876
int virCgroupTerminateMachine(const char *name G_GNUC_UNUSED)
J
Ján Tomko 已提交
2877 2878 2879 2880 2881 2882 2883
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


2884
int
J
Ján Tomko 已提交
2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896
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)
2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910
{
    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;
}

2911 2912

bool
J
Ján Tomko 已提交
2913 2914
virCgroupHasController(virCgroupPtr cgroup G_GNUC_UNUSED,
                       int controller G_GNUC_UNUSED)
2915 2916 2917 2918 2919
{
    return false;
}


2920
int
J
Ján Tomko 已提交
2921 2922 2923 2924
virCgroupPathOfController(virCgroupPtr group G_GNUC_UNUSED,
                          unsigned int controller G_GNUC_UNUSED,
                          const char *key G_GNUC_UNUSED,
                          char **path G_GNUC_UNUSED)
2925 2926 2927 2928 2929 2930 2931
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


2932
int
J
Ján Tomko 已提交
2933 2934
virCgroupAddProcess(virCgroupPtr group G_GNUC_UNUSED,
                    pid_t pid G_GNUC_UNUSED)
2935 2936 2937 2938 2939 2940 2941
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


2942
int
J
Ján Tomko 已提交
2943 2944
virCgroupAddMachineProcess(virCgroupPtr group G_GNUC_UNUSED,
                           pid_t pid G_GNUC_UNUSED)
2945 2946 2947 2948 2949 2950 2951
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


2952
int
J
Ján Tomko 已提交
2953 2954
virCgroupAddThread(virCgroupPtr group G_GNUC_UNUSED,
                   pid_t pid G_GNUC_UNUSED)
2955 2956 2957 2958 2959 2960 2961
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


2962
int
J
Ján Tomko 已提交
2963 2964 2965 2966 2967
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)
2968 2969 2970 2971 2972 2973 2974 2975
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
2976 2977 2978 2979 2980 2981
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)
2982 2983 2984 2985 2986 2987 2988
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


2989
int
J
Ján Tomko 已提交
2990 2991
virCgroupSetBlkioWeight(virCgroupPtr group G_GNUC_UNUSED,
                        unsigned int weight G_GNUC_UNUSED)
2992 2993 2994 2995 2996 2997 2998 2999
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3000 3001
virCgroupGetBlkioWeight(virCgroupPtr group G_GNUC_UNUSED,
                        unsigned int *weight G_GNUC_UNUSED)
3002 3003 3004 3005 3006 3007 3008
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


3009
int
J
Ján Tomko 已提交
3010 3011 3012
virCgroupSetBlkioDeviceWeight(virCgroupPtr group G_GNUC_UNUSED,
                              const char *path G_GNUC_UNUSED,
                              unsigned int weight G_GNUC_UNUSED)
3013 3014 3015 3016 3017 3018
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

3019
int
J
Ján Tomko 已提交
3020 3021 3022
virCgroupSetBlkioDeviceReadIops(virCgroupPtr group G_GNUC_UNUSED,
                                const char *path G_GNUC_UNUSED,
                                unsigned int riops G_GNUC_UNUSED)
3023 3024 3025 3026 3027 3028 3029
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

int
J
Ján Tomko 已提交
3030 3031 3032
virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group G_GNUC_UNUSED,
                                 const char *path G_GNUC_UNUSED,
                                 unsigned int wiops G_GNUC_UNUSED)
3033 3034 3035 3036 3037 3038 3039
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

int
J
Ján Tomko 已提交
3040 3041 3042
virCgroupSetBlkioDeviceReadBps(virCgroupPtr group G_GNUC_UNUSED,
                               const char *path G_GNUC_UNUSED,
                               unsigned long long rbps G_GNUC_UNUSED)
3043 3044 3045 3046 3047 3048 3049
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

int
J
Ján Tomko 已提交
3050 3051 3052
virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group G_GNUC_UNUSED,
                                const char *path G_GNUC_UNUSED,
                                unsigned long long wbps G_GNUC_UNUSED)
3053 3054 3055 3056 3057 3058
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

3059
int
J
Ján Tomko 已提交
3060 3061 3062
virCgroupGetBlkioDeviceWeight(virCgroupPtr group G_GNUC_UNUSED,
                              const char *path G_GNUC_UNUSED,
                              unsigned int *weight G_GNUC_UNUSED)
3063 3064 3065 3066 3067 3068 3069
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

int
J
Ján Tomko 已提交
3070 3071 3072
virCgroupGetBlkioDeviceReadIops(virCgroupPtr group G_GNUC_UNUSED,
                                const char *path G_GNUC_UNUSED,
                                unsigned int *riops G_GNUC_UNUSED)
3073 3074 3075 3076 3077 3078 3079
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

int
J
Ján Tomko 已提交
3080 3081 3082
virCgroupGetBlkioDeviceWriteIops(virCgroupPtr group G_GNUC_UNUSED,
                                 const char *path G_GNUC_UNUSED,
                                 unsigned int *wiops G_GNUC_UNUSED)
3083 3084 3085 3086 3087 3088 3089
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

int
J
Ján Tomko 已提交
3090 3091 3092
virCgroupGetBlkioDeviceReadBps(virCgroupPtr group G_GNUC_UNUSED,
                               const char *path G_GNUC_UNUSED,
                               unsigned long long *rbps G_GNUC_UNUSED)
3093 3094 3095 3096 3097 3098 3099
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

int
J
Ján Tomko 已提交
3100 3101 3102
virCgroupGetBlkioDeviceWriteBps(virCgroupPtr group G_GNUC_UNUSED,
                                const char *path G_GNUC_UNUSED,
                                unsigned long long *wbps G_GNUC_UNUSED)
3103 3104 3105 3106 3107
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}
3108

3109
int
J
Ján Tomko 已提交
3110 3111
virCgroupSetMemory(virCgroupPtr group G_GNUC_UNUSED,
                   unsigned long long kb G_GNUC_UNUSED)
3112 3113 3114 3115 3116 3117 3118
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


P
Pavel Hrdina 已提交
3119
int
J
Ján Tomko 已提交
3120 3121 3122 3123 3124 3125 3126
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)
P
Pavel Hrdina 已提交
3127 3128 3129 3130 3131 3132 3133
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


3134
int
J
Ján Tomko 已提交
3135 3136
virCgroupGetMemoryUsage(virCgroupPtr group G_GNUC_UNUSED,
                        unsigned long *kb G_GNUC_UNUSED)
3137 3138 3139 3140 3141 3142 3143 3144
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3145 3146
virCgroupSetMemoryHardLimit(virCgroupPtr group G_GNUC_UNUSED,
                            unsigned long long kb G_GNUC_UNUSED)
3147 3148 3149 3150 3151 3152 3153 3154
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3155 3156
virCgroupGetMemoryHardLimit(virCgroupPtr group G_GNUC_UNUSED,
                            unsigned long long *kb G_GNUC_UNUSED)
3157 3158 3159 3160 3161 3162 3163 3164
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3165 3166
virCgroupSetMemorySoftLimit(virCgroupPtr group G_GNUC_UNUSED,
                            unsigned long long kb G_GNUC_UNUSED)
3167 3168 3169 3170 3171 3172 3173 3174
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3175 3176
virCgroupGetMemorySoftLimit(virCgroupPtr group G_GNUC_UNUSED,
                            unsigned long long *kb G_GNUC_UNUSED)
3177 3178 3179 3180 3181 3182 3183 3184
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3185 3186
virCgroupSetMemSwapHardLimit(virCgroupPtr group G_GNUC_UNUSED,
                             unsigned long long kb G_GNUC_UNUSED)
3187 3188 3189 3190 3191 3192 3193 3194
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3195 3196
virCgroupGetMemSwapHardLimit(virCgroupPtr group G_GNUC_UNUSED,
                             unsigned long long *kb G_GNUC_UNUSED)
3197 3198 3199 3200 3201 3202 3203 3204
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3205 3206
virCgroupGetMemSwapUsage(virCgroupPtr group G_GNUC_UNUSED,
                         unsigned long long *kb G_GNUC_UNUSED)
3207 3208 3209 3210 3211 3212 3213 3214
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3215 3216
virCgroupSetCpusetMems(virCgroupPtr group G_GNUC_UNUSED,
                       const char *mems G_GNUC_UNUSED)
3217 3218 3219 3220 3221 3222 3223 3224
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3225 3226
virCgroupGetCpusetMems(virCgroupPtr group G_GNUC_UNUSED,
                       char **mems G_GNUC_UNUSED)
3227 3228 3229 3230 3231 3232
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

3233 3234

int
J
Ján Tomko 已提交
3235 3236
virCgroupSetCpusetMemoryMigrate(virCgroupPtr group G_GNUC_UNUSED,
                                bool migrate G_GNUC_UNUSED)
3237 3238 3239 3240 3241 3242 3243 3244
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3245 3246
virCgroupGetCpusetMemoryMigrate(virCgroupPtr group G_GNUC_UNUSED,
                                bool *migrate G_GNUC_UNUSED)
3247 3248 3249 3250 3251 3252
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

3253 3254

int
J
Ján Tomko 已提交
3255 3256
virCgroupSetCpusetCpus(virCgroupPtr group G_GNUC_UNUSED,
                       const char *cpus G_GNUC_UNUSED)
3257 3258 3259 3260 3261 3262 3263 3264
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3265 3266
virCgroupGetCpusetCpus(virCgroupPtr group G_GNUC_UNUSED,
                       char **cpus G_GNUC_UNUSED)
3267 3268 3269 3270 3271 3272
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

3273
int
J
Ján Tomko 已提交
3274 3275
virCgroupAllowAllDevices(virCgroupPtr group G_GNUC_UNUSED,
                         int perms G_GNUC_UNUSED)
3276 3277 3278 3279 3280
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}
3281 3282

int
J
Ján Tomko 已提交
3283
virCgroupDenyAllDevices(virCgroupPtr group G_GNUC_UNUSED)
3284 3285 3286 3287 3288 3289 3290 3291
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3292 3293 3294 3295 3296
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)
3297 3298 3299 3300 3301 3302 3303
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


3304
int
J
Ján Tomko 已提交
3305 3306 3307 3308
virCgroupAllowDevicePath(virCgroupPtr group G_GNUC_UNUSED,
                         const char *path G_GNUC_UNUSED,
                         int perms G_GNUC_UNUSED,
                         bool ignoreEaccess G_GNUC_UNUSED)
3309 3310 3311 3312 3313 3314 3315
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


3316
int
J
Ján Tomko 已提交
3317 3318 3319 3320 3321
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)
3322 3323 3324 3325 3326 3327 3328
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


3329
int
J
Ján Tomko 已提交
3330 3331 3332 3333
virCgroupDenyDevicePath(virCgroupPtr group G_GNUC_UNUSED,
                        const char *path G_GNUC_UNUSED,
                        int perms G_GNUC_UNUSED,
                        bool ignoreEacces G_GNUC_UNUSED)
3334 3335 3336 3337 3338 3339 3340
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


3341
int
J
Ján Tomko 已提交
3342 3343
virCgroupSetCpuShares(virCgroupPtr group G_GNUC_UNUSED,
                      unsigned long long shares G_GNUC_UNUSED)
3344 3345 3346 3347 3348 3349 3350 3351
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3352 3353
virCgroupGetCpuShares(virCgroupPtr group G_GNUC_UNUSED,
                      unsigned long long *shares G_GNUC_UNUSED)
3354 3355 3356 3357 3358 3359 3360 3361
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3362 3363
virCgroupSetCpuCfsPeriod(virCgroupPtr group G_GNUC_UNUSED,
                         unsigned long long cfs_period G_GNUC_UNUSED)
3364 3365 3366 3367 3368 3369 3370 3371
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3372 3373
virCgroupGetCpuCfsPeriod(virCgroupPtr group G_GNUC_UNUSED,
                         unsigned long long *cfs_period G_GNUC_UNUSED)
3374 3375 3376 3377 3378 3379 3380 3381
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3382 3383
virCgroupSetCpuCfsQuota(virCgroupPtr group G_GNUC_UNUSED,
                        long long cfs_quota G_GNUC_UNUSED)
3384 3385 3386 3387 3388 3389 3390 3391
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3392
virCgroupRemove(virCgroupPtr group G_GNUC_UNUSED)
3393 3394 3395 3396 3397 3398 3399
{
    virReportSystemError(ENXIO, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


3400
int
J
Ján Tomko 已提交
3401 3402
virCgroupKillRecursive(virCgroupPtr group G_GNUC_UNUSED,
                       int signum G_GNUC_UNUSED)
3403 3404 3405 3406 3407 3408 3409 3410
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3411
virCgroupKillPainfully(virCgroupPtr group G_GNUC_UNUSED)
3412 3413 3414 3415 3416 3417 3418
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


3419
int
J
Ján Tomko 已提交
3420 3421
virCgroupGetCpuCfsQuota(virCgroupPtr group G_GNUC_UNUSED,
                        long long *cfs_quota G_GNUC_UNUSED)
3422 3423 3424 3425 3426 3427 3428 3429
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3430 3431
virCgroupGetCpuacctUsage(virCgroupPtr group G_GNUC_UNUSED,
                         unsigned long long *usage G_GNUC_UNUSED)
3432 3433 3434 3435 3436 3437 3438 3439
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3440 3441
virCgroupGetCpuacctPercpuUsage(virCgroupPtr group G_GNUC_UNUSED,
                               char **usage G_GNUC_UNUSED)
3442 3443 3444 3445 3446 3447 3448 3449
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3450 3451 3452
virCgroupGetCpuacctStat(virCgroupPtr group G_GNUC_UNUSED,
                        unsigned long long *user G_GNUC_UNUSED,
                        unsigned long long *sys G_GNUC_UNUSED)
3453 3454 3455 3456 3457 3458 3459
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


3460
int
J
Ján Tomko 已提交
3461 3462 3463
virCgroupGetDomainTotalCpuStats(virCgroupPtr group G_GNUC_UNUSED,
                                virTypedParameterPtr params G_GNUC_UNUSED,
                                int nparams G_GNUC_UNUSED)
3464 3465 3466 3467 3468 3469 3470
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


3471
int
J
Ján Tomko 已提交
3472 3473
virCgroupSetFreezerState(virCgroupPtr group G_GNUC_UNUSED,
                         const char *state G_GNUC_UNUSED)
3474 3475 3476 3477 3478 3479 3480 3481
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3482 3483
virCgroupGetFreezerState(virCgroupPtr group G_GNUC_UNUSED,
                         char **state G_GNUC_UNUSED)
3484 3485 3486 3487 3488 3489 3490
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


E
Eric Blake 已提交
3491
int
J
Ján Tomko 已提交
3492 3493 3494
virCgroupBindMount(virCgroupPtr group G_GNUC_UNUSED,
                   const char *oldroot G_GNUC_UNUSED,
                   const char *mountopts G_GNUC_UNUSED)
3495
{
3496 3497 3498
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
3499
}
3500

3501 3502

bool
J
Ján Tomko 已提交
3503
virCgroupSupportsCpuBW(virCgroupPtr cgroup G_GNUC_UNUSED)
3504 3505 3506 3507 3508
{
    VIR_DEBUG("Control groups not supported on this platform");
    return false;
}

E
Eric Blake 已提交
3509 3510

int
J
Ján Tomko 已提交
3511 3512 3513 3514 3515 3516
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)
E
Eric Blake 已提交
3517 3518 3519 3520 3521 3522 3523 3524
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}


int
J
Ján Tomko 已提交
3525 3526 3527 3528
virCgroupSetOwner(virCgroupPtr cgroup G_GNUC_UNUSED,
                  uid_t uid G_GNUC_UNUSED,
                  gid_t gid G_GNUC_UNUSED,
                  int controllers G_GNUC_UNUSED)
E
Eric Blake 已提交
3529 3530 3531 3532 3533 3534
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

3535
int
J
Ján Tomko 已提交
3536 3537
virCgroupHasEmptyTasks(virCgroupPtr cgroup G_GNUC_UNUSED,
                       int controller G_GNUC_UNUSED)
3538 3539 3540 3541 3542 3543
{
    virReportSystemError(ENOSYS, "%s",
                         _("Control groups not supported on this platform"));
    return -1;
}

3544
bool
J
Ján Tomko 已提交
3545
virCgroupControllerAvailable(int controller G_GNUC_UNUSED)
3546 3547 3548
{
    return false;
}
3549
#endif /* !__linux__ */
3550 3551


3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578
/**
 * virCgroupFree:
 *
 * @group: The group structure to free
 */
void
virCgroupFree(virCgroupPtr *group)
{
    size_t i;

    if (*group == NULL)
        return;

    for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
        VIR_FREE((*group)->legacy[i].mountPoint);
        VIR_FREE((*group)->legacy[i].linkPoint);
        VIR_FREE((*group)->legacy[i].placement);
    }

    VIR_FREE((*group)->unified.mountPoint);
    VIR_FREE((*group)->unified.placement);

    VIR_FREE((*group)->path);
    VIR_FREE(*group);
}


3579 3580 3581 3582 3583
int
virCgroupDelThread(virCgroupPtr cgroup,
                   virCgroupThreadName nameval,
                   int idx)
{
3584
    virCgroupPtr new_cgroup = NULL;
3585 3586 3587 3588 3589 3590 3591

    if (cgroup) {
        if (virCgroupNewThread(cgroup, nameval, idx, false, &new_cgroup) < 0)
            return -1;

        /* Remove the offlined cgroup */
        virCgroupRemove(new_cgroup);
3592
        virCgroupFree(&new_cgroup);
3593 3594 3595 3596
    }

    return 0;
}