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, 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 */ 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 } 906