root/tools/testing/selftests/cgroup/test_freezer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cg_check_frozen
  2. cg_freeze_nowait
  3. cg_prepare_for_wait
  4. cg_wait_for
  5. cg_enter_and_wait_for_frozen
  6. cg_freeze_wait
  7. child_fn
  8. test_cgfreezer_simple
  9. test_cgfreezer_tree
  10. forkbomb_fn
  11. test_cgfreezer_forkbomb
  12. test_cgfreezer_mkdir
  13. test_cgfreezer_rmdir
  14. test_cgfreezer_migrate
  15. test_cgfreezer_ptrace
  16. proc_check_stopped
  17. test_cgfreezer_stopped
  18. test_cgfreezer_ptraced
  19. vfork_fn
  20. test_cgfreezer_vfork
  21. main

   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  */
  29 static 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  */
  52 static 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  */
  60 static 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  */
  85 static 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  */
 116 static 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 
 140 out:
 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  */
 150 static 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);
 169 out:
 170         close(fd);
 171         return ret;
 172 }
 173 
 174 /*
 175  * A simple process running in a sleep loop until being
 176  * re-parented.
 177  */
 178 static 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  */
 193 static 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 
 223 cleanup:
 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  */
 245 static 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 
 385 cleanup:
 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  */
 397 static 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  */
 417 static 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 
 444 cleanup:
 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  */
 456 static 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 
 494 cleanup:
 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  */
 510 static 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 
 546 cleanup:
 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  */
 565 static 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 
 627 cleanup:
 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  */
 640 static 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 
 690 cleanup:
 691         if (cgroup)
 692                 cg_destroy(cgroup);
 693         free(cgroup);
 694         return ret;
 695 }
 696 
 697 /*
 698  * Check if the process is stopped.
 699  */
 700 static int proc_check_stopped(int pid)
 701 {
 702         char buf[PAGE_SIZE];
 703         int len;
 704 
 705         len = proc_read_text(pid, "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  */
 722 static 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 
 756 cleanup:
 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  */
 766 static 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 
 813 cleanup:
 814         if (cgroup)
 815                 cg_destroy(cgroup);
 816         free(cgroup);
 817         return ret;
 818 }
 819 
 820 static 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  */
 835 static 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 
 857 cleanup:
 858         if (cgroup)
 859                 cg_destroy(cgroup);
 860         free(cgroup);
 861         return ret;
 862 }
 863 
 864 #define T(x) { x, #x }
 865 struct 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 
 882 int 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 }

/* [<][>][^][v][top][bottom][index][help] */