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 <stdlib.h> 11 #include <string.h> 12 #include <sys/wait.h> 13 14 #include "../kselftest.h" 15 #include "cgroup_util.h" 16 17 #define DEBUG 18 #ifdef DEBUG 19 #define debug(args...) fprintf(stderr, args) 20 #else 21 #define debug(args...) 22 #endif 23 24 /* 25 * Check if the cgroup is frozen by looking at the cgroup.events::frozen value. 26 */ 27 static int cg_check_frozen(const char *cgroup, bool frozen) 28 { 29 if (frozen) { 30 if (cg_read_strstr(cgroup, "cgroup.events", "frozen 1") != 0) { 31 debug("Cgroup %s isn't frozen\n", cgroup); 32 return -1; 33 } 34 } else { 35 /* 36 * Check the cgroup.events::frozen value. 37 */ 38 if (cg_read_strstr(cgroup, "cgroup.events", "frozen 0") != 0) { 39 debug("Cgroup %s is frozen\n", cgroup); 40 return -1; 41 } 42 } 43 44 return 0; 45 } 46 47 /* 48 * Freeze the given cgroup. 49 */ 50 static int cg_freeze_nowait(const char *cgroup, bool freeze) 51 { 52 return cg_write(cgroup, "cgroup.freeze", freeze ? "1" : "0"); 53 } 54 55 /* 56 * Attach a task to the given cgroup and wait for a cgroup frozen event. 57 * All transient events (e.g. populated) are ignored. 58 */ 59 static int cg_enter_and_wait_for_frozen(const char *cgroup, int pid, 60 bool frozen) 61 { 62 int fd, ret = -1; 63 int attempts; 64 65 fd = cg_prepare_for_wait(cgroup); 66 if (fd < 0) 67 return fd; 68 69 ret = cg_enter(cgroup, pid); 70 if (ret) 71 goto out; 72 73 for (attempts = 0; attempts < 10; attempts++) { 74 ret = cg_wait_for(fd); 75 if (ret) 76 break; 77 78 ret = cg_check_frozen(cgroup, frozen); 79 if (ret) 80 continue; 81 } 82 83 out: 84 close(fd); 85 return ret; 86 } 87 88 /* 89 * Freeze the given cgroup and wait for the inotify signal. 90 * If there are no events in 10 seconds, treat this as an error. 91 * Then check that the cgroup is in the desired state. 92 */ 93 static int cg_freeze_wait(const char *cgroup, bool freeze) 94 { 95 int fd, ret = -1; 96 97 fd = cg_prepare_for_wait(cgroup); 98 if (fd < 0) 99 return fd; 100 101 ret = cg_freeze_nowait(cgroup, freeze); 102 if (ret) { 103 debug("Error: cg_freeze_nowait() failed\n"); 104 goto out; 105 } 106 107 ret = cg_wait_for(fd); 108 if (ret) 109 goto out; 110 111 ret = cg_check_frozen(cgroup, freeze); 112 out: 113 close(fd); 114 return ret; 115 } 116 117 /* 118 * A simple process running in a sleep loop until being 119 * re-parented. 120 */ 121 static int child_fn(const char *cgroup, void *arg) 122 { 123 int ppid = getppid(); 124 125 while (getppid() == ppid) 126 usleep(1000); 127 128 return getppid() == ppid; 129 } 130 131 /* 132 * A simple test for the cgroup freezer: populated the cgroup with 100 133 * running processes and freeze it. Then unfreeze it. Then it kills all 134 * processes and destroys the cgroup. 135 */ 136 static int test_cgfreezer_simple(const char *root) 137 { 138 int ret = KSFT_FAIL; 139 char *cgroup = NULL; 140 int i; 141 142 cgroup = cg_name(root, "cg_test_simple"); 143 if (!cgroup) 144 goto cleanup; 145 146 if (cg_create(cgroup)) 147 goto cleanup; 148 149 for (i = 0; i < 100; i++) 150 cg_run_nowait(cgroup, child_fn, NULL); 151 152 if (cg_wait_for_proc_count(cgroup, 100)) 153 goto cleanup; 154 155 if (cg_check_frozen(cgroup, false)) 156 goto cleanup; 157 158 if (cg_freeze_wait(cgroup, true)) 159 goto cleanup; 160 161 if (cg_freeze_wait(cgroup, false)) 162 goto cleanup; 163 164 ret = KSFT_PASS; 165 166 cleanup: 167 if (cgroup) 168 cg_destroy(cgroup); 169 free(cgroup); 170 return ret; 171 } 172 173 /* 174 * The test creates the following hierarchy: 175 * A 176 * / / \ \ 177 * B E I K 178 * /\ | 179 * C D F 180 * | 181 * G 182 * | 183 * H 184 * 185 * with a process in C, H and 3 processes in K. 186 * Then it tries to freeze and unfreeze the whole tree. 187 */ 188 static int test_cgfreezer_tree(const char *root) 189 { 190 char *cgroup[10] = {0}; 191 int ret = KSFT_FAIL; 192 int i; 193 194 cgroup[0] = cg_name(root, "cg_test_tree_A"); 195 if (!cgroup[0]) 196 goto cleanup; 197 198 cgroup[1] = cg_name(cgroup[0], "B"); 199 if (!cgroup[1]) 200 goto cleanup; 201 202 cgroup[2] = cg_name(cgroup[1], "C"); 203 if (!cgroup[2]) 204 goto cleanup; 205 206 cgroup[3] = cg_name(cgroup[1], "D"); 207 if (!cgroup[3]) 208 goto cleanup; 209 210 cgroup[4] = cg_name(cgroup[0], "E"); 211 if (!cgroup[4]) 212 goto cleanup; 213 214 cgroup[5] = cg_name(cgroup[4], "F"); 215 if (!cgroup[5]) 216 goto cleanup; 217 218 cgroup[6] = cg_name(cgroup[5], "G"); 219 if (!cgroup[6]) 220 goto cleanup; 221 222 cgroup[7] = cg_name(cgroup[6], "H"); 223 if (!cgroup[7]) 224 goto cleanup; 225 226 cgroup[8] = cg_name(cgroup[0], "I"); 227 if (!cgroup[8]) 228 goto cleanup; 229 230 cgroup[9] = cg_name(cgroup[0], "K"); 231 if (!cgroup[9]) 232 goto cleanup; 233 234 for (i = 0; i < 10; i++) 235 if (cg_create(cgroup[i])) 236 goto cleanup; 237 238 cg_run_nowait(cgroup[2], child_fn, NULL); 239 cg_run_nowait(cgroup[7], child_fn, NULL); 240 cg_run_nowait(cgroup[9], child_fn, NULL); 241 cg_run_nowait(cgroup[9], child_fn, NULL); 242 cg_run_nowait(cgroup[9], child_fn, NULL); 243 244 /* 245 * Wait until all child processes will enter 246 * corresponding cgroups. 247 */ 248 249 if (cg_wait_for_proc_count(cgroup[2], 1) || 250 cg_wait_for_proc_count(cgroup[7], 1) || 251 cg_wait_for_proc_count(cgroup[9], 3)) 252 goto cleanup; 253 254 /* 255 * Freeze B. 256 */ 257 if (cg_freeze_wait(cgroup[1], true)) 258 goto cleanup; 259 260 /* 261 * Freeze F. 262 */ 263 if (cg_freeze_wait(cgroup[5], true)) 264 goto cleanup; 265 266 /* 267 * Freeze G. 268 */ 269 if (cg_freeze_wait(cgroup[6], true)) 270 goto cleanup; 271 272 /* 273 * Check that A and E are not frozen. 274 */ 275 if (cg_check_frozen(cgroup[0], false)) 276 goto cleanup; 277 278 if (cg_check_frozen(cgroup[4], false)) 279 goto cleanup; 280 281 /* 282 * Freeze A. Check that A, B and E are frozen. 283 */ 284 if (cg_freeze_wait(cgroup[0], true)) 285 goto cleanup; 286 287 if (cg_check_frozen(cgroup[1], true)) 288 goto cleanup; 289 290 if (cg_check_frozen(cgroup[4], true)) 291 goto cleanup; 292 293 /* 294 * Unfreeze B, F and G 295 */ 296 if (cg_freeze_nowait(cgroup[1], false)) 297 goto cleanup; 298 299 if (cg_freeze_nowait(cgroup[5], false)) 300 goto cleanup; 301 302 if (cg_freeze_nowait(cgroup[6], false)) 303 goto cleanup; 304 305 /* 306 * Check that C and H are still frozen. 307 */ 308 if (cg_check_frozen(cgroup[2], true)) 309 goto cleanup; 310 311 if (cg_check_frozen(cgroup[7], true)) 312 goto cleanup; 313 314 /* 315 * Unfreeze A. Check that A, C and K are not frozen. 316 */ 317 if (cg_freeze_wait(cgroup[0], false)) 318 goto cleanup; 319 320 if (cg_check_frozen(cgroup[2], false)) 321 goto cleanup; 322 323 if (cg_check_frozen(cgroup[9], false)) 324 goto cleanup; 325 326 ret = KSFT_PASS; 327 328 cleanup: 329 for (i = 9; i >= 0 && cgroup[i]; i--) { 330 cg_destroy(cgroup[i]); 331 free(cgroup[i]); 332 } 333 334 return ret; 335 } 336 337 /* 338 * A fork bomb emulator. 339 */ 340 static int forkbomb_fn(const char *cgroup, void *arg) 341 { 342 int ppid; 343 344 fork(); 345 fork(); 346 347 ppid = getppid(); 348 349 while (getppid() == ppid) 350 usleep(1000); 351 352 return getppid() == ppid; 353 } 354 355 /* 356 * The test runs a fork bomb in a cgroup and tries to freeze it. 357 * Then it kills all processes and checks that cgroup isn't populated 358 * anymore. 359 */ 360 static int test_cgfreezer_forkbomb(const char *root) 361 { 362 int ret = KSFT_FAIL; 363 char *cgroup = NULL; 364 365 cgroup = cg_name(root, "cg_forkbomb_test"); 366 if (!cgroup) 367 goto cleanup; 368 369 if (cg_create(cgroup)) 370 goto cleanup; 371 372 cg_run_nowait(cgroup, forkbomb_fn, NULL); 373 374 usleep(100000); 375 376 if (cg_freeze_wait(cgroup, true)) 377 goto cleanup; 378 379 if (cg_killall(cgroup)) 380 goto cleanup; 381 382 if (cg_wait_for_proc_count(cgroup, 0)) 383 goto cleanup; 384 385 ret = KSFT_PASS; 386 387 cleanup: 388 if (cgroup) 389 cg_destroy(cgroup); 390 free(cgroup); 391 return ret; 392 } 393 394 /* 395 * The test creates a cgroups and freezes it. Then it creates a child cgroup 396 * and populates it with a task. After that it checks that the child cgroup 397 * is frozen and the parent cgroup remains frozen too. 398 */ 399 static int test_cgfreezer_mkdir(const char *root) 400 { 401 int ret = KSFT_FAIL; 402 char *parent, *child = NULL; 403 int pid; 404 405 parent = cg_name(root, "cg_test_mkdir_A"); 406 if (!parent) 407 goto cleanup; 408 409 child = cg_name(parent, "cg_test_mkdir_B"); 410 if (!child) 411 goto cleanup; 412 413 if (cg_create(parent)) 414 goto cleanup; 415 416 if (cg_freeze_wait(parent, true)) 417 goto cleanup; 418 419 if (cg_create(child)) 420 goto cleanup; 421 422 pid = cg_run_nowait(child, child_fn, NULL); 423 if (pid < 0) 424 goto cleanup; 425 426 if (cg_wait_for_proc_count(child, 1)) 427 goto cleanup; 428 429 if (cg_check_frozen(child, true)) 430 goto cleanup; 431 432 if (cg_check_frozen(parent, true)) 433 goto cleanup; 434 435 ret = KSFT_PASS; 436 437 cleanup: 438 if (child) 439 cg_destroy(child); 440 free(child); 441 if (parent) 442 cg_destroy(parent); 443 free(parent); 444 return ret; 445 } 446 447 /* 448 * The test creates two nested cgroups, freezes the parent 449 * and removes the child. Then it checks that the parent cgroup 450 * remains frozen and it's possible to create a new child 451 * without unfreezing. The new child is frozen too. 452 */ 453 static int test_cgfreezer_rmdir(const char *root) 454 { 455 int ret = KSFT_FAIL; 456 char *parent, *child = NULL; 457 458 parent = cg_name(root, "cg_test_rmdir_A"); 459 if (!parent) 460 goto cleanup; 461 462 child = cg_name(parent, "cg_test_rmdir_B"); 463 if (!child) 464 goto cleanup; 465 466 if (cg_create(parent)) 467 goto cleanup; 468 469 if (cg_create(child)) 470 goto cleanup; 471 472 if (cg_freeze_wait(parent, true)) 473 goto cleanup; 474 475 if (cg_destroy(child)) 476 goto cleanup; 477 478 if (cg_check_frozen(parent, true)) 479 goto cleanup; 480 481 if (cg_create(child)) 482 goto cleanup; 483 484 if (cg_check_frozen(child, true)) 485 goto cleanup; 486 487 ret = KSFT_PASS; 488 489 cleanup: 490 if (child) 491 cg_destroy(child); 492 free(child); 493 if (parent) 494 cg_destroy(parent); 495 free(parent); 496 return ret; 497 } 498 499 /* 500 * The test creates two cgroups: A and B, runs a process in A 501 * and performs several migrations: 502 * 1) A (running) -> B (frozen) 503 * 2) B (frozen) -> A (running) 504 * 3) A (frozen) -> B (frozen) 505 * 506 * On each step it checks the actual state of both cgroups. 507 */ 508 static int test_cgfreezer_migrate(const char *root) 509 { 510 int ret = KSFT_FAIL; 511 char *cgroup[2] = {0}; 512 int pid; 513 514 cgroup[0] = cg_name(root, "cg_test_migrate_A"); 515 if (!cgroup[0]) 516 goto cleanup; 517 518 cgroup[1] = cg_name(root, "cg_test_migrate_B"); 519 if (!cgroup[1]) 520 goto cleanup; 521 522 if (cg_create(cgroup[0])) 523 goto cleanup; 524 525 if (cg_create(cgroup[1])) 526 goto cleanup; 527 528 pid = cg_run_nowait(cgroup[0], child_fn, NULL); 529 if (pid < 0) 530 goto cleanup; 531 532 if (cg_wait_for_proc_count(cgroup[0], 1)) 533 goto cleanup; 534 535 /* 536 * Migrate from A (running) to B (frozen) 537 */ 538 if (cg_freeze_wait(cgroup[1], true)) 539 goto cleanup; 540 541 if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true)) 542 goto cleanup; 543 544 if (cg_check_frozen(cgroup[0], false)) 545 goto cleanup; 546 547 /* 548 * Migrate from B (frozen) to A (running) 549 */ 550 if (cg_enter_and_wait_for_frozen(cgroup[0], pid, false)) 551 goto cleanup; 552 553 if (cg_check_frozen(cgroup[1], true)) 554 goto cleanup; 555 556 /* 557 * Migrate from A (frozen) to B (frozen) 558 */ 559 if (cg_freeze_wait(cgroup[0], true)) 560 goto cleanup; 561 562 if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true)) 563 goto cleanup; 564 565 if (cg_check_frozen(cgroup[0], true)) 566 goto cleanup; 567 568 ret = KSFT_PASS; 569 570 cleanup: 571 if (cgroup[0]) 572 cg_destroy(cgroup[0]); 573 free(cgroup[0]); 574 if (cgroup[1]) 575 cg_destroy(cgroup[1]); 576 free(cgroup[1]); 577 return ret; 578 } 579 580 /* 581 * The test checks that ptrace works with a tracing process in a frozen cgroup. 582 */ 583 static int test_cgfreezer_ptrace(const char *root) 584 { 585 int ret = KSFT_FAIL; 586 char *cgroup = NULL; 587 siginfo_t siginfo; 588 int pid; 589 590 cgroup = cg_name(root, "cg_test_ptrace"); 591 if (!cgroup) 592 goto cleanup; 593 594 if (cg_create(cgroup)) 595 goto cleanup; 596 597 pid = cg_run_nowait(cgroup, child_fn, NULL); 598 if (pid < 0) 599 goto cleanup; 600 601 if (cg_wait_for_proc_count(cgroup, 1)) 602 goto cleanup; 603 604 if (cg_freeze_wait(cgroup, true)) 605 goto cleanup; 606 607 if (ptrace(PTRACE_SEIZE, pid, NULL, NULL)) 608 goto cleanup; 609 610 if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) 611 goto cleanup; 612 613 waitpid(pid, NULL, 0); 614 615 /* 616 * Cgroup has to remain frozen, however the test task 617 * is in traced state. 618 */ 619 if (cg_check_frozen(cgroup, true)) 620 goto cleanup; 621 622 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo)) 623 goto cleanup; 624 625 if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) 626 goto cleanup; 627 628 if (cg_check_frozen(cgroup, true)) 629 goto cleanup; 630 631 ret = KSFT_PASS; 632 633 cleanup: 634 if (cgroup) 635 cg_destroy(cgroup); 636 free(cgroup); 637 return ret; 638 } 639 640 /* 641 * Check if the process is stopped. 642 */ 643 static int proc_check_stopped(int pid) 644 { 645 char buf[PAGE_SIZE]; 646 int len; 647 648 len = proc_read_text(pid, 0, "stat", buf, sizeof(buf)); 649 if (len == -1) { 650 debug("Can't get %d stat\n", pid); 651 return -1; 652 } 653 654 if (strstr(buf, "(test_freezer) T ") == NULL) { 655 debug("Process %d in the unexpected state: %s\n", pid, buf); 656 return -1; 657 } 658 659 return 0; 660 } 661 662 /* 663 * Test that it's possible to freeze a cgroup with a stopped process. 664 */ 665 static int test_cgfreezer_stopped(const char *root) 666 { 667 int pid, ret = KSFT_FAIL; 668 char *cgroup = NULL; 669 670 cgroup = cg_name(root, "cg_test_stopped"); 671 if (!cgroup) 672 goto cleanup; 673 674 if (cg_create(cgroup)) 675 goto cleanup; 676 677 pid = cg_run_nowait(cgroup, child_fn, NULL); 678 679 if (cg_wait_for_proc_count(cgroup, 1)) 680 goto cleanup; 681 682 if (kill(pid, SIGSTOP)) 683 goto cleanup; 684 685 if (cg_check_frozen(cgroup, false)) 686 goto cleanup; 687 688 if (cg_freeze_wait(cgroup, true)) 689 goto cleanup; 690 691 if (cg_freeze_wait(cgroup, false)) 692 goto cleanup; 693 694 if (proc_check_stopped(pid)) 695 goto cleanup; 696 697 ret = KSFT_PASS; 698 699 cleanup: 700 if (cgroup) 701 cg_destroy(cgroup); 702 free(cgroup); 703 return ret; 704 } 705 706 /* 707 * Test that it's possible to freeze a cgroup with a ptraced process. 708 */ 709 static int test_cgfreezer_ptraced(const char *root) 710 { 711 int pid, ret = KSFT_FAIL; 712 char *cgroup = NULL; 713 siginfo_t siginfo; 714 715 cgroup = cg_name(root, "cg_test_ptraced"); 716 if (!cgroup) 717 goto cleanup; 718 719 if (cg_create(cgroup)) 720 goto cleanup; 721 722 pid = cg_run_nowait(cgroup, child_fn, NULL); 723 724 if (cg_wait_for_proc_count(cgroup, 1)) 725 goto cleanup; 726 727 if (ptrace(PTRACE_SEIZE, pid, NULL, NULL)) 728 goto cleanup; 729 730 if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) 731 goto cleanup; 732 733 waitpid(pid, NULL, 0); 734 735 if (cg_check_frozen(cgroup, false)) 736 goto cleanup; 737 738 if (cg_freeze_wait(cgroup, true)) 739 goto cleanup; 740 741 /* 742 * cg_check_frozen(cgroup, true) will fail here, 743 * because the task is in the TRACEd state. 744 */ 745 if (cg_freeze_wait(cgroup, false)) 746 goto cleanup; 747 748 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo)) 749 goto cleanup; 750 751 if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) 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 static int vfork_fn(const char *cgroup, void *arg) 764 { 765 int pid = vfork(); 766 767 if (pid == 0) 768 while (true) 769 sleep(1); 770 771 return pid; 772 } 773 774 /* 775 * Test that it's possible to freeze a cgroup with a process, 776 * which called vfork() and is waiting for a child. 777 */ 778 static int test_cgfreezer_vfork(const char *root) 779 { 780 int ret = KSFT_FAIL; 781 char *cgroup = NULL; 782 783 cgroup = cg_name(root, "cg_test_vfork"); 784 if (!cgroup) 785 goto cleanup; 786 787 if (cg_create(cgroup)) 788 goto cleanup; 789 790 cg_run_nowait(cgroup, vfork_fn, NULL); 791 792 if (cg_wait_for_proc_count(cgroup, 2)) 793 goto cleanup; 794 795 if (cg_freeze_wait(cgroup, true)) 796 goto cleanup; 797 798 ret = KSFT_PASS; 799 800 cleanup: 801 if (cgroup) 802 cg_destroy(cgroup); 803 free(cgroup); 804 return ret; 805 } 806 807 /* 808 * Get the current frozen_usec for the cgroup. 809 */ 810 static long cg_check_freezetime(const char *cgroup) 811 { 812 return cg_read_key_long(cgroup, "cgroup.stat.local", 813 "frozen_usec "); 814 } 815 816 /* 817 * Test that the freeze time will behave as expected for an empty cgroup. 818 */ 819 static int test_cgfreezer_time_empty(const char *root) 820 { 821 int ret = KSFT_FAIL; 822 char *cgroup = NULL; 823 long prev, curr; 824 825 cgroup = cg_name(root, "cg_time_test_empty"); 826 if (!cgroup) 827 goto cleanup; 828 829 /* 830 * 1) Create an empty cgroup and check that its freeze time 831 * is 0. 832 */ 833 if (cg_create(cgroup)) 834 goto cleanup; 835 836 curr = cg_check_freezetime(cgroup); 837 if (curr < 0) { 838 ret = KSFT_SKIP; 839 goto cleanup; 840 } 841 if (curr > 0) { 842 debug("Expect time (%ld) to be 0\n", curr); 843 goto cleanup; 844 } 845 846 if (cg_freeze_nowait(cgroup, true)) 847 goto cleanup; 848 849 /* 850 * 2) Sleep for 1000 us. Check that the freeze time is at 851 * least 1000 us. 852 */ 853 usleep(1000); 854 curr = cg_check_freezetime(cgroup); 855 if (curr < 1000) { 856 debug("Expect time (%ld) to be at least 1000 us\n", 857 curr); 858 goto cleanup; 859 } 860 861 /* 862 * 3) Unfreeze the cgroup. Check that the freeze time is 863 * larger than at 2). 864 */ 865 if (cg_freeze_nowait(cgroup, false)) 866 goto cleanup; 867 prev = curr; 868 curr = cg_check_freezetime(cgroup); 869 if (curr <= prev) { 870 debug("Expect time (%ld) to be more than previous check (%ld)\n", 871 curr, prev); 872 goto cleanup; 873 } 874 875 /* 876 * 4) Check the freeze time again to ensure that it has not 877 * changed. 878 */ 879 prev = curr; 880 curr = cg_check_freezetime(cgroup); 881 if (curr != prev) { 882 debug("Expect time (%ld) to be unchanged from previous check (%ld)\n", 883 curr, prev); 884 goto cleanup; 885 } 886 887 ret = KSFT_PASS; 888 889 cleanup: 890 if (cgroup) 891 cg_destroy(cgroup); 892 free(cgroup); 893 return ret; 894 } 895 896 /* 897 * A simple test for cgroup freezer time accounting. This test follows 898 * the same flow as test_cgfreezer_time_empty, but with a single process 899 * in the cgroup. 900 */ 901 static int test_cgfreezer_time_simple(const char *root) 902 { 903 int ret = KSFT_FAIL; 904 char *cgroup = NULL; 905 long prev, curr; 906 907 cgroup = cg_name(root, "cg_time_test_simple"); 908 if (!cgroup) 909 goto cleanup; 910 911 /* 912 * 1) Create a cgroup and check that its freeze time is 0. 913 */ 914 if (cg_create(cgroup)) 915 goto cleanup; 916 917 curr = cg_check_freezetime(cgroup); 918 if (curr < 0) { 919 ret = KSFT_SKIP; 920 goto cleanup; 921 } 922 if (curr > 0) { 923 debug("Expect time (%ld) to be 0\n", curr); 924 goto cleanup; 925 } 926 927 /* 928 * 2) Populate the cgroup with one child and check that the 929 * freeze time is still 0. 930 */ 931 cg_run_nowait(cgroup, child_fn, NULL); 932 prev = curr; 933 curr = cg_check_freezetime(cgroup); 934 if (curr > prev) { 935 debug("Expect time (%ld) to be 0\n", curr); 936 goto cleanup; 937 } 938 939 if (cg_freeze_nowait(cgroup, true)) 940 goto cleanup; 941 942 /* 943 * 3) Sleep for 1000 us. Check that the freeze time is at 944 * least 1000 us. 945 */ 946 usleep(1000); 947 prev = curr; 948 curr = cg_check_freezetime(cgroup); 949 if (curr < 1000) { 950 debug("Expect time (%ld) to be at least 1000 us\n", 951 curr); 952 goto cleanup; 953 } 954 955 /* 956 * 4) Unfreeze the cgroup. Check that the freeze time is 957 * larger than at 3). 958 */ 959 if (cg_freeze_nowait(cgroup, false)) 960 goto cleanup; 961 prev = curr; 962 curr = cg_check_freezetime(cgroup); 963 if (curr <= prev) { 964 debug("Expect time (%ld) to be more than previous check (%ld)\n", 965 curr, prev); 966 goto cleanup; 967 } 968 969 /* 970 * 5) Sleep for 1000 us. Check that the freeze time is the 971 * same as at 4). 972 */ 973 usleep(1000); 974 prev = curr; 975 curr = cg_check_freezetime(cgroup); 976 if (curr != prev) { 977 debug("Expect time (%ld) to be unchanged from previous check (%ld)\n", 978 curr, prev); 979 goto cleanup; 980 } 981 982 ret = KSFT_PASS; 983 984 cleanup: 985 if (cgroup) 986 cg_destroy(cgroup); 987 free(cgroup); 988 return ret; 989 } 990 991 /* 992 * Test that freezer time accounting works as expected, even while we're 993 * populating a cgroup with processes. 994 */ 995 static int test_cgfreezer_time_populate(const char *root) 996 { 997 int ret = KSFT_FAIL; 998 char *cgroup = NULL; 999 long prev, curr; 1000 int i; 1001 1002 cgroup = cg_name(root, "cg_time_test_populate"); 1003 if (!cgroup) 1004 goto cleanup; 1005 1006 if (cg_create(cgroup)) 1007 goto cleanup; 1008 1009 curr = cg_check_freezetime(cgroup); 1010 if (curr < 0) { 1011 ret = KSFT_SKIP; 1012 goto cleanup; 1013 } 1014 if (curr > 0) { 1015 debug("Expect time (%ld) to be 0\n", curr); 1016 goto cleanup; 1017 } 1018 1019 /* 1020 * 1) Populate the cgroup with 100 processes. Check that 1021 * the freeze time is 0. 1022 */ 1023 for (i = 0; i < 100; i++) 1024 cg_run_nowait(cgroup, child_fn, NULL); 1025 prev = curr; 1026 curr = cg_check_freezetime(cgroup); 1027 if (curr != prev) { 1028 debug("Expect time (%ld) to be 0\n", curr); 1029 goto cleanup; 1030 } 1031 1032 /* 1033 * 2) Wait for the group to become fully populated. Check 1034 * that the freeze time is 0. 1035 */ 1036 if (cg_wait_for_proc_count(cgroup, 100)) 1037 goto cleanup; 1038 prev = curr; 1039 curr = cg_check_freezetime(cgroup); 1040 if (curr != prev) { 1041 debug("Expect time (%ld) to be 0\n", curr); 1042 goto cleanup; 1043 } 1044 1045 /* 1046 * 3) Freeze the cgroup and then populate it with 100 more 1047 * processes. Check that the freeze time continues to grow. 1048 */ 1049 if (cg_freeze_nowait(cgroup, true)) 1050 goto cleanup; 1051 prev = curr; 1052 curr = cg_check_freezetime(cgroup); 1053 if (curr <= prev) { 1054 debug("Expect time (%ld) to be more than previous check (%ld)\n", 1055 curr, prev); 1056 goto cleanup; 1057 } 1058 1059 for (i = 0; i < 100; i++) 1060 cg_run_nowait(cgroup, child_fn, NULL); 1061 prev = curr; 1062 curr = cg_check_freezetime(cgroup); 1063 if (curr <= prev) { 1064 debug("Expect time (%ld) to be more than previous check (%ld)\n", 1065 curr, prev); 1066 goto cleanup; 1067 } 1068 1069 /* 1070 * 4) Wait for the group to become fully populated. Check 1071 * that the freeze time is larger than at 3). 1072 */ 1073 if (cg_wait_for_proc_count(cgroup, 200)) 1074 goto cleanup; 1075 prev = curr; 1076 curr = cg_check_freezetime(cgroup); 1077 if (curr <= prev) { 1078 debug("Expect time (%ld) to be more than previous check (%ld)\n", 1079 curr, prev); 1080 goto cleanup; 1081 } 1082 1083 /* 1084 * 5) Unfreeze the cgroup. Check that the freeze time is 1085 * larger than at 4). 1086 */ 1087 if (cg_freeze_nowait(cgroup, false)) 1088 goto cleanup; 1089 prev = curr; 1090 curr = cg_check_freezetime(cgroup); 1091 if (curr <= prev) { 1092 debug("Expect time (%ld) to be more than previous check (%ld)\n", 1093 curr, prev); 1094 goto cleanup; 1095 } 1096 1097 /* 1098 * 6) Kill the processes. Check that the freeze time is the 1099 * same as it was at 5). 1100 */ 1101 if (cg_killall(cgroup)) 1102 goto cleanup; 1103 prev = curr; 1104 curr = cg_check_freezetime(cgroup); 1105 if (curr != prev) { 1106 debug("Expect time (%ld) to be unchanged from previous check (%ld)\n", 1107 curr, prev); 1108 goto cleanup; 1109 } 1110 1111 /* 1112 * 7) Freeze and unfreeze the cgroup. Check that the freeze 1113 * time is larger than it was at 6). 1114 */ 1115 if (cg_freeze_nowait(cgroup, true)) 1116 goto cleanup; 1117 if (cg_freeze_nowait(cgroup, false)) 1118 goto cleanup; 1119 prev = curr; 1120 curr = cg_check_freezetime(cgroup); 1121 if (curr <= prev) { 1122 debug("Expect time (%ld) to be more than previous check (%ld)\n", 1123 curr, prev); 1124 goto cleanup; 1125 } 1126 1127 ret = KSFT_PASS; 1128 1129 cleanup: 1130 if (cgroup) 1131 cg_destroy(cgroup); 1132 free(cgroup); 1133 return ret; 1134 } 1135 1136 /* 1137 * Test that frozen time for a cgroup continues to work as expected, 1138 * even as processes are migrated. Frozen cgroup A's freeze time should 1139 * continue to increase and running cgroup B's should stay 0. 1140 */ 1141 static int test_cgfreezer_time_migrate(const char *root) 1142 { 1143 long prev_A, curr_A, curr_B; 1144 char *cgroup[2] = {0}; 1145 int ret = KSFT_FAIL; 1146 int pid; 1147 1148 cgroup[0] = cg_name(root, "cg_time_test_migrate_A"); 1149 if (!cgroup[0]) 1150 goto cleanup; 1151 1152 cgroup[1] = cg_name(root, "cg_time_test_migrate_B"); 1153 if (!cgroup[1]) 1154 goto cleanup; 1155 1156 if (cg_create(cgroup[0])) 1157 goto cleanup; 1158 1159 if (cg_check_freezetime(cgroup[0]) < 0) { 1160 ret = KSFT_SKIP; 1161 goto cleanup; 1162 } 1163 1164 if (cg_create(cgroup[1])) 1165 goto cleanup; 1166 1167 pid = cg_run_nowait(cgroup[0], child_fn, NULL); 1168 if (pid < 0) 1169 goto cleanup; 1170 1171 if (cg_wait_for_proc_count(cgroup[0], 1)) 1172 goto cleanup; 1173 1174 curr_A = cg_check_freezetime(cgroup[0]); 1175 if (curr_A) { 1176 debug("Expect time (%ld) to be 0\n", curr_A); 1177 goto cleanup; 1178 } 1179 curr_B = cg_check_freezetime(cgroup[1]); 1180 if (curr_B) { 1181 debug("Expect time (%ld) to be 0\n", curr_B); 1182 goto cleanup; 1183 } 1184 1185 /* 1186 * Freeze cgroup A. 1187 */ 1188 if (cg_freeze_wait(cgroup[0], true)) 1189 goto cleanup; 1190 prev_A = curr_A; 1191 curr_A = cg_check_freezetime(cgroup[0]); 1192 if (curr_A <= prev_A) { 1193 debug("Expect time (%ld) to be > 0\n", curr_A); 1194 goto cleanup; 1195 } 1196 1197 /* 1198 * Migrate from A (frozen) to B (running). 1199 */ 1200 if (cg_enter(cgroup[1], pid)) 1201 goto cleanup; 1202 1203 usleep(1000); 1204 curr_B = cg_check_freezetime(cgroup[1]); 1205 if (curr_B) { 1206 debug("Expect time (%ld) to be 0\n", curr_B); 1207 goto cleanup; 1208 } 1209 1210 prev_A = curr_A; 1211 curr_A = cg_check_freezetime(cgroup[0]); 1212 if (curr_A <= prev_A) { 1213 debug("Expect time (%ld) to be more than previous check (%ld)\n", 1214 curr_A, prev_A); 1215 goto cleanup; 1216 } 1217 1218 ret = KSFT_PASS; 1219 1220 cleanup: 1221 if (cgroup[0]) 1222 cg_destroy(cgroup[0]); 1223 free(cgroup[0]); 1224 if (cgroup[1]) 1225 cg_destroy(cgroup[1]); 1226 free(cgroup[1]); 1227 return ret; 1228 } 1229 1230 /* 1231 * The test creates a cgroup and freezes it. Then it creates a child cgroup. 1232 * After that it checks that the child cgroup has a non-zero freeze time 1233 * that is less than the parent's. Next, it freezes the child, unfreezes 1234 * the parent, and sleeps. Finally, it checks that the child's freeze 1235 * time has grown larger than the parent's. 1236 */ 1237 static int test_cgfreezer_time_parent(const char *root) 1238 { 1239 char *parent, *child = NULL; 1240 int ret = KSFT_FAIL; 1241 long ptime, ctime; 1242 1243 parent = cg_name(root, "cg_test_parent_A"); 1244 if (!parent) 1245 goto cleanup; 1246 1247 child = cg_name(parent, "cg_test_parent_B"); 1248 if (!child) 1249 goto cleanup; 1250 1251 if (cg_create(parent)) 1252 goto cleanup; 1253 1254 if (cg_check_freezetime(parent) < 0) { 1255 ret = KSFT_SKIP; 1256 goto cleanup; 1257 } 1258 1259 if (cg_freeze_wait(parent, true)) 1260 goto cleanup; 1261 1262 usleep(1000); 1263 if (cg_create(child)) 1264 goto cleanup; 1265 1266 if (cg_check_frozen(child, true)) 1267 goto cleanup; 1268 1269 /* 1270 * Since the parent was frozen the entire time the child cgroup 1271 * was being created, we expect the parent's freeze time to be 1272 * larger than the child's. 1273 * 1274 * Ideally, we would be able to check both times simultaneously, 1275 * but here we get the child's after we get the parent's. 1276 */ 1277 ptime = cg_check_freezetime(parent); 1278 ctime = cg_check_freezetime(child); 1279 if (ptime <= ctime) { 1280 debug("Expect ptime (%ld) > ctime (%ld)\n", ptime, ctime); 1281 goto cleanup; 1282 } 1283 1284 if (cg_freeze_nowait(child, true)) 1285 goto cleanup; 1286 1287 if (cg_freeze_wait(parent, false)) 1288 goto cleanup; 1289 1290 if (cg_check_frozen(child, true)) 1291 goto cleanup; 1292 1293 usleep(100000); 1294 1295 ctime = cg_check_freezetime(child); 1296 ptime = cg_check_freezetime(parent); 1297 1298 if (ctime <= ptime) { 1299 debug("Expect ctime (%ld) > ptime (%ld)\n", ctime, ptime); 1300 goto cleanup; 1301 } 1302 1303 ret = KSFT_PASS; 1304 1305 cleanup: 1306 if (child) 1307 cg_destroy(child); 1308 free(child); 1309 if (parent) 1310 cg_destroy(parent); 1311 free(parent); 1312 return ret; 1313 } 1314 1315 /* 1316 * The test creates a parent cgroup and a child cgroup. Then, it freezes 1317 * the child and checks that the child's freeze time is greater than the 1318 * parent's, which should be zero. 1319 */ 1320 static int test_cgfreezer_time_child(const char *root) 1321 { 1322 char *parent, *child = NULL; 1323 int ret = KSFT_FAIL; 1324 long ptime, ctime; 1325 1326 parent = cg_name(root, "cg_test_child_A"); 1327 if (!parent) 1328 goto cleanup; 1329 1330 child = cg_name(parent, "cg_test_child_B"); 1331 if (!child) 1332 goto cleanup; 1333 1334 if (cg_create(parent)) 1335 goto cleanup; 1336 1337 if (cg_check_freezetime(parent) < 0) { 1338 ret = KSFT_SKIP; 1339 goto cleanup; 1340 } 1341 1342 if (cg_create(child)) 1343 goto cleanup; 1344 1345 if (cg_freeze_wait(child, true)) 1346 goto cleanup; 1347 1348 ctime = cg_check_freezetime(child); 1349 ptime = cg_check_freezetime(parent); 1350 if (ptime != 0) { 1351 debug("Expect ptime (%ld) to be 0\n", ptime); 1352 goto cleanup; 1353 } 1354 1355 if (ctime <= ptime) { 1356 debug("Expect ctime (%ld) <= ptime (%ld)\n", ctime, ptime); 1357 goto cleanup; 1358 } 1359 1360 ret = KSFT_PASS; 1361 1362 cleanup: 1363 if (child) 1364 cg_destroy(child); 1365 free(child); 1366 if (parent) 1367 cg_destroy(parent); 1368 free(parent); 1369 return ret; 1370 } 1371 1372 /* 1373 * The test creates the following hierarchy: 1374 * A 1375 * | 1376 * B 1377 * | 1378 * C 1379 * 1380 * Then it freezes the cgroups in the order C, B, A. 1381 * Then it unfreezes the cgroups in the order A, B, C. 1382 * Then it checks that C's freeze time is larger than B's and 1383 * that B's is larger than A's. 1384 */ 1385 static int test_cgfreezer_time_nested(const char *root) 1386 { 1387 char *cgroup[3] = {0}; 1388 int ret = KSFT_FAIL; 1389 long time[3] = {0}; 1390 int i; 1391 1392 cgroup[0] = cg_name(root, "cg_test_time_A"); 1393 if (!cgroup[0]) 1394 goto cleanup; 1395 1396 cgroup[1] = cg_name(cgroup[0], "B"); 1397 if (!cgroup[1]) 1398 goto cleanup; 1399 1400 cgroup[2] = cg_name(cgroup[1], "C"); 1401 if (!cgroup[2]) 1402 goto cleanup; 1403 1404 if (cg_create(cgroup[0])) 1405 goto cleanup; 1406 1407 if (cg_check_freezetime(cgroup[0]) < 0) { 1408 ret = KSFT_SKIP; 1409 goto cleanup; 1410 } 1411 1412 if (cg_create(cgroup[1])) 1413 goto cleanup; 1414 1415 if (cg_create(cgroup[2])) 1416 goto cleanup; 1417 1418 if (cg_freeze_nowait(cgroup[2], true)) 1419 goto cleanup; 1420 1421 if (cg_freeze_nowait(cgroup[1], true)) 1422 goto cleanup; 1423 1424 if (cg_freeze_nowait(cgroup[0], true)) 1425 goto cleanup; 1426 1427 usleep(1000); 1428 1429 if (cg_freeze_nowait(cgroup[0], false)) 1430 goto cleanup; 1431 1432 if (cg_freeze_nowait(cgroup[1], false)) 1433 goto cleanup; 1434 1435 if (cg_freeze_nowait(cgroup[2], false)) 1436 goto cleanup; 1437 1438 time[2] = cg_check_freezetime(cgroup[2]); 1439 time[1] = cg_check_freezetime(cgroup[1]); 1440 time[0] = cg_check_freezetime(cgroup[0]); 1441 1442 if (time[2] <= time[1]) { 1443 debug("Expect C's time (%ld) > B's time (%ld)", time[2], time[1]); 1444 goto cleanup; 1445 } 1446 1447 if (time[1] <= time[0]) { 1448 debug("Expect B's time (%ld) > A's time (%ld)", time[1], time[0]); 1449 goto cleanup; 1450 } 1451 1452 ret = KSFT_PASS; 1453 1454 cleanup: 1455 for (i = 2; i >= 0 && cgroup[i]; i--) { 1456 cg_destroy(cgroup[i]); 1457 free(cgroup[i]); 1458 } 1459 1460 return ret; 1461 } 1462 1463 #define T(x) { x, #x } 1464 struct cgfreezer_test { 1465 int (*fn)(const char *root); 1466 const char *name; 1467 } tests[] = { 1468 T(test_cgfreezer_simple), 1469 T(test_cgfreezer_tree), 1470 T(test_cgfreezer_forkbomb), 1471 T(test_cgfreezer_mkdir), 1472 T(test_cgfreezer_rmdir), 1473 T(test_cgfreezer_migrate), 1474 T(test_cgfreezer_ptrace), 1475 T(test_cgfreezer_stopped), 1476 T(test_cgfreezer_ptraced), 1477 T(test_cgfreezer_vfork), 1478 T(test_cgfreezer_time_empty), 1479 T(test_cgfreezer_time_simple), 1480 T(test_cgfreezer_time_populate), 1481 T(test_cgfreezer_time_migrate), 1482 T(test_cgfreezer_time_parent), 1483 T(test_cgfreezer_time_child), 1484 T(test_cgfreezer_time_nested), 1485 }; 1486 #undef T 1487 1488 int main(int argc, char *argv[]) 1489 { 1490 char root[PATH_MAX]; 1491 int i, ret = EXIT_SUCCESS; 1492 1493 if (cg_find_unified_root(root, sizeof(root), NULL)) 1494 ksft_exit_skip("cgroup v2 isn't mounted\n"); 1495 for (i = 0; i < ARRAY_SIZE(tests); i++) { 1496 switch (tests[i].fn(root)) { 1497 case KSFT_PASS: 1498 ksft_test_result_pass("%s\n", tests[i].name); 1499 break; 1500 case KSFT_SKIP: 1501 ksft_test_result_skip("%s\n", tests[i].name); 1502 break; 1503 default: 1504 ret = EXIT_FAILURE; 1505 ksft_test_result_fail("%s\n", tests[i].name); 1506 break; 1507 } 1508 } 1509 1510 return ret; 1511 } 1512