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