linux/tools/testing/selftests/cgroup/test_freezer.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#include <stdbool.h>
   3#include <linux/limits.h>
   4#include <sys/ptrace.h>
   5#include <sys/types.h>
   6#include <sys/mman.h>
   7#include <unistd.h>
   8#include <stdio.h>
   9#include <errno.h>
  10#include <poll.h>
  11#include <stdlib.h>
  12#include <sys/inotify.h>
  13#include <string.h>
  14#include <sys/wait.h>
  15
  16#include "../kselftest.h"
  17#include "cgroup_util.h"
  18
  19#define DEBUG
  20#ifdef DEBUG
  21#define debug(args...) fprintf(stderr, args)
  22#else
  23#define debug(args...)
  24#endif
  25
  26/*
  27 * Check if the cgroup is frozen by looking at the cgroup.events::frozen value.
  28 */
  29static int cg_check_frozen(const char *cgroup, bool frozen)
  30{
  31        if (frozen) {
  32                if (cg_read_strstr(cgroup, "cgroup.events", "frozen 1") != 0) {
  33                        debug("Cgroup %s isn't frozen\n", cgroup);
  34                        return -1;
  35                }
  36        } else {
  37                /*
  38                 * Check the cgroup.events::frozen value.
  39                 */
  40                if (cg_read_strstr(cgroup, "cgroup.events", "frozen 0") != 0) {
  41                        debug("Cgroup %s is frozen\n", cgroup);
  42                        return -1;
  43                }
  44        }
  45
  46        return 0;
  47}
  48
  49/*
  50 * Freeze the given cgroup.
  51 */
  52static int cg_freeze_nowait(const char *cgroup, bool freeze)
  53{
  54        return cg_write(cgroup, "cgroup.freeze", freeze ? "1" : "0");
  55}
  56
  57/*
  58 * Prepare for waiting on cgroup.events file.
  59 */
  60static int cg_prepare_for_wait(const char *cgroup)
  61{
  62        int fd, ret = -1;
  63
  64        fd = inotify_init1(0);
  65        if (fd == -1) {
  66                debug("Error: inotify_init1() failed\n");
  67                return fd;
  68        }
  69
  70        ret = inotify_add_watch(fd, cg_control(cgroup, "cgroup.events"),
  71                                IN_MODIFY);
  72        if (ret == -1) {
  73                debug("Error: inotify_add_watch() failed\n");
  74                close(fd);
  75                fd = -1;
  76        }
  77
  78        return fd;
  79}
  80
  81/*
  82 * Wait for an event. If there are no events for 10 seconds,
  83 * treat this an error.
  84 */
  85static int cg_wait_for(int fd)
  86{
  87        int ret = -1;
  88        struct pollfd fds = {
  89                .fd = fd,
  90                .events = POLLIN,
  91        };
  92
  93        while (true) {
  94                ret = poll(&fds, 1, 10000);
  95
  96                if (ret == -1) {
  97                        if (errno == EINTR)
  98                                continue;
  99                        debug("Error: poll() failed\n");
 100                        break;
 101                }
 102
 103                if (ret > 0 && fds.revents & POLLIN) {
 104                        ret = 0;
 105                        break;
 106                }
 107        }
 108
 109        return ret;
 110}
 111
 112/*
 113 * Attach a task to the given cgroup and wait for a cgroup frozen event.
 114 * All transient events (e.g. populated) are ignored.
 115 */
 116static int cg_enter_and_wait_for_frozen(const char *cgroup, int pid,
 117                                        bool frozen)
 118{
 119        int fd, ret = -1;
 120        int attempts;
 121
 122        fd = cg_prepare_for_wait(cgroup);
 123        if (fd < 0)
 124                return fd;
 125
 126        ret = cg_enter(cgroup, pid);
 127        if (ret)
 128                goto out;
 129
 130        for (attempts = 0; attempts < 10; attempts++) {
 131                ret = cg_wait_for(fd);
 132                if (ret)
 133                        break;
 134
 135                ret = cg_check_frozen(cgroup, frozen);
 136                if (ret)
 137                        continue;
 138        }
 139
 140out:
 141        close(fd);
 142        return ret;
 143}
 144
 145/*
 146 * Freeze the given cgroup and wait for the inotify signal.
 147 * If there are no events in 10 seconds, treat this as an error.
 148 * Then check that the cgroup is in the desired state.
 149 */
 150static int cg_freeze_wait(const char *cgroup, bool freeze)
 151{
 152        int fd, ret = -1;
 153
 154        fd = cg_prepare_for_wait(cgroup);
 155        if (fd < 0)
 156                return fd;
 157
 158        ret = cg_freeze_nowait(cgroup, freeze);
 159        if (ret) {
 160                debug("Error: cg_freeze_nowait() failed\n");
 161                goto out;
 162        }
 163
 164        ret = cg_wait_for(fd);
 165        if (ret)
 166                goto out;
 167
 168        ret = cg_check_frozen(cgroup, freeze);
 169out:
 170        close(fd);
 171        return ret;
 172}
 173
 174/*
 175 * A simple process running in a sleep loop until being
 176 * re-parented.
 177 */
 178static int child_fn(const char *cgroup, void *arg)
 179{
 180        int ppid = getppid();
 181
 182        while (getppid() == ppid)
 183                usleep(1000);
 184
 185        return getppid() == ppid;
 186}
 187
 188/*
 189 * A simple test for the cgroup freezer: populated the cgroup with 100
 190 * running processes and freeze it. Then unfreeze it. Then it kills all
 191 * processes and destroys the cgroup.
 192 */
 193static int test_cgfreezer_simple(const char *root)
 194{
 195        int ret = KSFT_FAIL;
 196        char *cgroup = NULL;
 197        int i;
 198
 199        cgroup = cg_name(root, "cg_test_simple");
 200        if (!cgroup)
 201                goto cleanup;
 202
 203        if (cg_create(cgroup))
 204                goto cleanup;
 205
 206        for (i = 0; i < 100; i++)
 207                cg_run_nowait(cgroup, child_fn, NULL);
 208
 209        if (cg_wait_for_proc_count(cgroup, 100))
 210                goto cleanup;
 211
 212        if (cg_check_frozen(cgroup, false))
 213                goto cleanup;
 214
 215        if (cg_freeze_wait(cgroup, true))
 216                goto cleanup;
 217
 218        if (cg_freeze_wait(cgroup, false))
 219                goto cleanup;
 220
 221        ret = KSFT_PASS;
 222
 223cleanup:
 224        if (cgroup)
 225                cg_destroy(cgroup);
 226        free(cgroup);
 227        return ret;
 228}
 229
 230/*
 231 * The test creates the following hierarchy:
 232 *       A
 233 *    / / \ \
 234 *   B  E  I K
 235 *  /\  |
 236 * C  D F
 237 *      |
 238 *      G
 239 *      |
 240 *      H
 241 *
 242 * with a process in C, H and 3 processes in K.
 243 * Then it tries to freeze and unfreeze the whole tree.
 244 */
 245static int test_cgfreezer_tree(const char *root)
 246{
 247        char *cgroup[10] = {0};
 248        int ret = KSFT_FAIL;
 249        int i;
 250
 251        cgroup[0] = cg_name(root, "cg_test_tree_A");
 252        if (!cgroup[0])
 253                goto cleanup;
 254
 255        cgroup[1] = cg_name(cgroup[0], "B");
 256        if (!cgroup[1])
 257                goto cleanup;
 258
 259        cgroup[2] = cg_name(cgroup[1], "C");
 260        if (!cgroup[2])
 261                goto cleanup;
 262
 263        cgroup[3] = cg_name(cgroup[1], "D");
 264        if (!cgroup[3])
 265                goto cleanup;
 266
 267        cgroup[4] = cg_name(cgroup[0], "E");
 268        if (!cgroup[4])
 269                goto cleanup;
 270
 271        cgroup[5] = cg_name(cgroup[4], "F");
 272        if (!cgroup[5])
 273                goto cleanup;
 274
 275        cgroup[6] = cg_name(cgroup[5], "G");
 276        if (!cgroup[6])
 277                goto cleanup;
 278
 279        cgroup[7] = cg_name(cgroup[6], "H");
 280        if (!cgroup[7])
 281                goto cleanup;
 282
 283        cgroup[8] = cg_name(cgroup[0], "I");
 284        if (!cgroup[8])
 285                goto cleanup;
 286
 287        cgroup[9] = cg_name(cgroup[0], "K");
 288        if (!cgroup[9])
 289                goto cleanup;
 290
 291        for (i = 0; i < 10; i++)
 292                if (cg_create(cgroup[i]))
 293                        goto cleanup;
 294
 295        cg_run_nowait(cgroup[2], child_fn, NULL);
 296        cg_run_nowait(cgroup[7], child_fn, NULL);
 297        cg_run_nowait(cgroup[9], child_fn, NULL);
 298        cg_run_nowait(cgroup[9], child_fn, NULL);
 299        cg_run_nowait(cgroup[9], child_fn, NULL);
 300
 301        /*
 302         * Wait until all child processes will enter
 303         * corresponding cgroups.
 304         */
 305
 306        if (cg_wait_for_proc_count(cgroup[2], 1) ||
 307            cg_wait_for_proc_count(cgroup[7], 1) ||
 308            cg_wait_for_proc_count(cgroup[9], 3))
 309                goto cleanup;
 310
 311        /*
 312         * Freeze B.
 313         */
 314        if (cg_freeze_wait(cgroup[1], true))
 315                goto cleanup;
 316
 317        /*
 318         * Freeze F.
 319         */
 320        if (cg_freeze_wait(cgroup[5], true))
 321                goto cleanup;
 322
 323        /*
 324         * Freeze G.
 325         */
 326        if (cg_freeze_wait(cgroup[6], true))
 327                goto cleanup;
 328
 329        /*
 330         * Check that A and E are not frozen.
 331         */
 332        if (cg_check_frozen(cgroup[0], false))
 333                goto cleanup;
 334
 335        if (cg_check_frozen(cgroup[4], false))
 336                goto cleanup;
 337
 338        /*
 339         * Freeze A. Check that A, B and E are frozen.
 340         */
 341        if (cg_freeze_wait(cgroup[0], true))
 342                goto cleanup;
 343
 344        if (cg_check_frozen(cgroup[1], true))
 345                goto cleanup;
 346
 347        if (cg_check_frozen(cgroup[4], true))
 348                goto cleanup;
 349
 350        /*
 351         * Unfreeze B, F and G
 352         */
 353        if (cg_freeze_nowait(cgroup[1], false))
 354                goto cleanup;
 355
 356        if (cg_freeze_nowait(cgroup[5], false))
 357                goto cleanup;
 358
 359        if (cg_freeze_nowait(cgroup[6], false))
 360                goto cleanup;
 361
 362        /*
 363         * Check that C and H are still frozen.
 364         */
 365        if (cg_check_frozen(cgroup[2], true))
 366                goto cleanup;
 367
 368        if (cg_check_frozen(cgroup[7], true))
 369                goto cleanup;
 370
 371        /*
 372         * Unfreeze A. Check that A, C and K are not frozen.
 373         */
 374        if (cg_freeze_wait(cgroup[0], false))
 375                goto cleanup;
 376
 377        if (cg_check_frozen(cgroup[2], false))
 378                goto cleanup;
 379
 380        if (cg_check_frozen(cgroup[9], false))
 381                goto cleanup;
 382
 383        ret = KSFT_PASS;
 384
 385cleanup:
 386        for (i = 9; i >= 0 && cgroup[i]; i--) {
 387                cg_destroy(cgroup[i]);
 388                free(cgroup[i]);
 389        }
 390
 391        return ret;
 392}
 393
 394/*
 395 * A fork bomb emulator.
 396 */
 397static int forkbomb_fn(const char *cgroup, void *arg)
 398{
 399        int ppid;
 400
 401        fork();
 402        fork();
 403
 404        ppid = getppid();
 405
 406        while (getppid() == ppid)
 407                usleep(1000);
 408
 409        return getppid() == ppid;
 410}
 411
 412/*
 413 * The test runs a fork bomb in a cgroup and tries to freeze it.
 414 * Then it kills all processes and checks that cgroup isn't populated
 415 * anymore.
 416 */
 417static int test_cgfreezer_forkbomb(const char *root)
 418{
 419        int ret = KSFT_FAIL;
 420        char *cgroup = NULL;
 421
 422        cgroup = cg_name(root, "cg_forkbomb_test");
 423        if (!cgroup)
 424                goto cleanup;
 425
 426        if (cg_create(cgroup))
 427                goto cleanup;
 428
 429        cg_run_nowait(cgroup, forkbomb_fn, NULL);
 430
 431        usleep(100000);
 432
 433        if (cg_freeze_wait(cgroup, true))
 434                goto cleanup;
 435
 436        if (cg_killall(cgroup))
 437                goto cleanup;
 438
 439        if (cg_wait_for_proc_count(cgroup, 0))
 440                goto cleanup;
 441
 442        ret = KSFT_PASS;
 443
 444cleanup:
 445        if (cgroup)
 446                cg_destroy(cgroup);
 447        free(cgroup);
 448        return ret;
 449}
 450
 451/*
 452 * The test creates a cgroups and freezes it. Then it creates a child cgroup
 453 * and populates it with a task. After that it checks that the child cgroup
 454 * is frozen and the parent cgroup remains frozen too.
 455 */
 456static int test_cgfreezer_mkdir(const char *root)
 457{
 458        int ret = KSFT_FAIL;
 459        char *parent, *child = NULL;
 460        int pid;
 461
 462        parent = cg_name(root, "cg_test_mkdir_A");
 463        if (!parent)
 464                goto cleanup;
 465
 466        child = cg_name(parent, "cg_test_mkdir_B");
 467        if (!child)
 468                goto cleanup;
 469
 470        if (cg_create(parent))
 471                goto cleanup;
 472
 473        if (cg_freeze_wait(parent, true))
 474                goto cleanup;
 475
 476        if (cg_create(child))
 477                goto cleanup;
 478
 479        pid = cg_run_nowait(child, child_fn, NULL);
 480        if (pid < 0)
 481                goto cleanup;
 482
 483        if (cg_wait_for_proc_count(child, 1))
 484                goto cleanup;
 485
 486        if (cg_check_frozen(child, true))
 487                goto cleanup;
 488
 489        if (cg_check_frozen(parent, true))
 490                goto cleanup;
 491
 492        ret = KSFT_PASS;
 493
 494cleanup:
 495        if (child)
 496                cg_destroy(child);
 497        free(child);
 498        if (parent)
 499                cg_destroy(parent);
 500        free(parent);
 501        return ret;
 502}
 503
 504/*
 505 * The test creates two nested cgroups, freezes the parent
 506 * and removes the child. Then it checks that the parent cgroup
 507 * remains frozen and it's possible to create a new child
 508 * without unfreezing. The new child is frozen too.
 509 */
 510static int test_cgfreezer_rmdir(const char *root)
 511{
 512        int ret = KSFT_FAIL;
 513        char *parent, *child = NULL;
 514
 515        parent = cg_name(root, "cg_test_rmdir_A");
 516        if (!parent)
 517                goto cleanup;
 518
 519        child = cg_name(parent, "cg_test_rmdir_B");
 520        if (!child)
 521                goto cleanup;
 522
 523        if (cg_create(parent))
 524                goto cleanup;
 525
 526        if (cg_create(child))
 527                goto cleanup;
 528
 529        if (cg_freeze_wait(parent, true))
 530                goto cleanup;
 531
 532        if (cg_destroy(child))
 533                goto cleanup;
 534
 535        if (cg_check_frozen(parent, true))
 536                goto cleanup;
 537
 538        if (cg_create(child))
 539                goto cleanup;
 540
 541        if (cg_check_frozen(child, true))
 542                goto cleanup;
 543
 544        ret = KSFT_PASS;
 545
 546cleanup:
 547        if (child)
 548                cg_destroy(child);
 549        free(child);
 550        if (parent)
 551                cg_destroy(parent);
 552        free(parent);
 553        return ret;
 554}
 555
 556/*
 557 * The test creates two cgroups: A and B, runs a process in A
 558 * and performs several migrations:
 559 * 1) A (running) -> B (frozen)
 560 * 2) B (frozen) -> A (running)
 561 * 3) A (frozen) -> B (frozen)
 562 *
 563 * On each step it checks the actual state of both cgroups.
 564 */
 565static int test_cgfreezer_migrate(const char *root)
 566{
 567        int ret = KSFT_FAIL;
 568        char *cgroup[2] = {0};
 569        int pid;
 570
 571        cgroup[0] = cg_name(root, "cg_test_migrate_A");
 572        if (!cgroup[0])
 573                goto cleanup;
 574
 575        cgroup[1] = cg_name(root, "cg_test_migrate_B");
 576        if (!cgroup[1])
 577                goto cleanup;
 578
 579        if (cg_create(cgroup[0]))
 580                goto cleanup;
 581
 582        if (cg_create(cgroup[1]))
 583                goto cleanup;
 584
 585        pid = cg_run_nowait(cgroup[0], child_fn, NULL);
 586        if (pid < 0)
 587                goto cleanup;
 588
 589        if (cg_wait_for_proc_count(cgroup[0], 1))
 590                goto cleanup;
 591
 592        /*
 593         * Migrate from A (running) to B (frozen)
 594         */
 595        if (cg_freeze_wait(cgroup[1], true))
 596                goto cleanup;
 597
 598        if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true))
 599                goto cleanup;
 600
 601        if (cg_check_frozen(cgroup[0], false))
 602                goto cleanup;
 603
 604        /*
 605         * Migrate from B (frozen) to A (running)
 606         */
 607        if (cg_enter_and_wait_for_frozen(cgroup[0], pid, false))
 608                goto cleanup;
 609
 610        if (cg_check_frozen(cgroup[1], true))
 611                goto cleanup;
 612
 613        /*
 614         * Migrate from A (frozen) to B (frozen)
 615         */
 616        if (cg_freeze_wait(cgroup[0], true))
 617                goto cleanup;
 618
 619        if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true))
 620                goto cleanup;
 621
 622        if (cg_check_frozen(cgroup[0], true))
 623                goto cleanup;
 624
 625        ret = KSFT_PASS;
 626
 627cleanup:
 628        if (cgroup[0])
 629                cg_destroy(cgroup[0]);
 630        free(cgroup[0]);
 631        if (cgroup[1])
 632                cg_destroy(cgroup[1]);
 633        free(cgroup[1]);
 634        return ret;
 635}
 636
 637/*
 638 * The test checks that ptrace works with a tracing process in a frozen cgroup.
 639 */
 640static int test_cgfreezer_ptrace(const char *root)
 641{
 642        int ret = KSFT_FAIL;
 643        char *cgroup = NULL;
 644        siginfo_t siginfo;
 645        int pid;
 646
 647        cgroup = cg_name(root, "cg_test_ptrace");
 648        if (!cgroup)
 649                goto cleanup;
 650
 651        if (cg_create(cgroup))
 652                goto cleanup;
 653
 654        pid = cg_run_nowait(cgroup, child_fn, NULL);
 655        if (pid < 0)
 656                goto cleanup;
 657
 658        if (cg_wait_for_proc_count(cgroup, 1))
 659                goto cleanup;
 660
 661        if (cg_freeze_wait(cgroup, true))
 662                goto cleanup;
 663
 664        if (ptrace(PTRACE_SEIZE, pid, NULL, NULL))
 665                goto cleanup;
 666
 667        if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL))
 668                goto cleanup;
 669
 670        waitpid(pid, NULL, 0);
 671
 672        /*
 673         * Cgroup has to remain frozen, however the test task
 674         * is in traced state.
 675         */
 676        if (cg_check_frozen(cgroup, true))
 677                goto cleanup;
 678
 679        if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo))
 680                goto cleanup;
 681
 682        if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
 683                goto cleanup;
 684
 685        if (cg_check_frozen(cgroup, true))
 686                goto cleanup;
 687
 688        ret = KSFT_PASS;
 689
 690cleanup:
 691        if (cgroup)
 692                cg_destroy(cgroup);
 693        free(cgroup);
 694        return ret;
 695}
 696
 697/*
 698 * Check if the process is stopped.
 699 */
 700static int proc_check_stopped(int pid)
 701{
 702        char buf[PAGE_SIZE];
 703        int len;
 704
 705        len = proc_read_text(pid, 0, "stat", buf, sizeof(buf));
 706        if (len == -1) {
 707                debug("Can't get %d stat\n", pid);
 708                return -1;
 709        }
 710
 711        if (strstr(buf, "(test_freezer) T ") == NULL) {
 712                debug("Process %d in the unexpected state: %s\n", pid, buf);
 713                return -1;
 714        }
 715
 716        return 0;
 717}
 718
 719/*
 720 * Test that it's possible to freeze a cgroup with a stopped process.
 721 */
 722static int test_cgfreezer_stopped(const char *root)
 723{
 724        int pid, ret = KSFT_FAIL;
 725        char *cgroup = NULL;
 726
 727        cgroup = cg_name(root, "cg_test_stopped");
 728        if (!cgroup)
 729                goto cleanup;
 730
 731        if (cg_create(cgroup))
 732                goto cleanup;
 733
 734        pid = cg_run_nowait(cgroup, child_fn, NULL);
 735
 736        if (cg_wait_for_proc_count(cgroup, 1))
 737                goto cleanup;
 738
 739        if (kill(pid, SIGSTOP))
 740                goto cleanup;
 741
 742        if (cg_check_frozen(cgroup, false))
 743                goto cleanup;
 744
 745        if (cg_freeze_wait(cgroup, true))
 746                goto cleanup;
 747
 748        if (cg_freeze_wait(cgroup, false))
 749                goto cleanup;
 750
 751        if (proc_check_stopped(pid))
 752                goto cleanup;
 753
 754        ret = KSFT_PASS;
 755
 756cleanup:
 757        if (cgroup)
 758                cg_destroy(cgroup);
 759        free(cgroup);
 760        return ret;
 761}
 762
 763/*
 764 * Test that it's possible to freeze a cgroup with a ptraced process.
 765 */
 766static int test_cgfreezer_ptraced(const char *root)
 767{
 768        int pid, ret = KSFT_FAIL;
 769        char *cgroup = NULL;
 770        siginfo_t siginfo;
 771
 772        cgroup = cg_name(root, "cg_test_ptraced");
 773        if (!cgroup)
 774                goto cleanup;
 775
 776        if (cg_create(cgroup))
 777                goto cleanup;
 778
 779        pid = cg_run_nowait(cgroup, child_fn, NULL);
 780
 781        if (cg_wait_for_proc_count(cgroup, 1))
 782                goto cleanup;
 783
 784        if (ptrace(PTRACE_SEIZE, pid, NULL, NULL))
 785                goto cleanup;
 786
 787        if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL))
 788                goto cleanup;
 789
 790        waitpid(pid, NULL, 0);
 791
 792        if (cg_check_frozen(cgroup, false))
 793                goto cleanup;
 794
 795        if (cg_freeze_wait(cgroup, true))
 796                goto cleanup;
 797
 798        /*
 799         * cg_check_frozen(cgroup, true) will fail here,
 800         * because the task in in the TRACEd state.
 801         */
 802        if (cg_freeze_wait(cgroup, false))
 803                goto cleanup;
 804
 805        if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo))
 806                goto cleanup;
 807
 808        if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
 809                goto cleanup;
 810
 811        ret = KSFT_PASS;
 812
 813cleanup:
 814        if (cgroup)
 815                cg_destroy(cgroup);
 816        free(cgroup);
 817        return ret;
 818}
 819
 820static int vfork_fn(const char *cgroup, void *arg)
 821{
 822        int pid = vfork();
 823
 824        if (pid == 0)
 825                while (true)
 826                        sleep(1);
 827
 828        return pid;
 829}
 830
 831/*
 832 * Test that it's possible to freeze a cgroup with a process,
 833 * which called vfork() and is waiting for a child.
 834 */
 835static int test_cgfreezer_vfork(const char *root)
 836{
 837        int ret = KSFT_FAIL;
 838        char *cgroup = NULL;
 839
 840        cgroup = cg_name(root, "cg_test_vfork");
 841        if (!cgroup)
 842                goto cleanup;
 843
 844        if (cg_create(cgroup))
 845                goto cleanup;
 846
 847        cg_run_nowait(cgroup, vfork_fn, NULL);
 848
 849        if (cg_wait_for_proc_count(cgroup, 2))
 850                goto cleanup;
 851
 852        if (cg_freeze_wait(cgroup, true))
 853                goto cleanup;
 854
 855        ret = KSFT_PASS;
 856
 857cleanup:
 858        if (cgroup)
 859                cg_destroy(cgroup);
 860        free(cgroup);
 861        return ret;
 862}
 863
 864#define T(x) { x, #x }
 865struct cgfreezer_test {
 866        int (*fn)(const char *root);
 867        const char *name;
 868} tests[] = {
 869        T(test_cgfreezer_simple),
 870        T(test_cgfreezer_tree),
 871        T(test_cgfreezer_forkbomb),
 872        T(test_cgfreezer_mkdir),
 873        T(test_cgfreezer_rmdir),
 874        T(test_cgfreezer_migrate),
 875        T(test_cgfreezer_ptrace),
 876        T(test_cgfreezer_stopped),
 877        T(test_cgfreezer_ptraced),
 878        T(test_cgfreezer_vfork),
 879};
 880#undef T
 881
 882int main(int argc, char *argv[])
 883{
 884        char root[PATH_MAX];
 885        int i, ret = EXIT_SUCCESS;
 886
 887        if (cg_find_unified_root(root, sizeof(root)))
 888                ksft_exit_skip("cgroup v2 isn't mounted\n");
 889        for (i = 0; i < ARRAY_SIZE(tests); i++) {
 890                switch (tests[i].fn(root)) {
 891                case KSFT_PASS:
 892                        ksft_test_result_pass("%s\n", tests[i].name);
 893                        break;
 894                case KSFT_SKIP:
 895                        ksft_test_result_skip("%s\n", tests[i].name);
 896                        break;
 897                default:
 898                        ret = EXIT_FAILURE;
 899                        ksft_test_result_fail("%s\n", tests[i].name);
 900                        break;
 901                }
 902        }
 903
 904        return ret;
 905}
 906