15313bfe4SRoman Gushchin /* SPDX-License-Identifier: GPL-2.0 */ 25313bfe4SRoman Gushchin #include <stdbool.h> 35313bfe4SRoman Gushchin #include <linux/limits.h> 45313bfe4SRoman Gushchin #include <sys/ptrace.h> 55313bfe4SRoman Gushchin #include <sys/types.h> 65313bfe4SRoman Gushchin #include <sys/mman.h> 75313bfe4SRoman Gushchin #include <unistd.h> 85313bfe4SRoman Gushchin #include <stdio.h> 95313bfe4SRoman Gushchin #include <errno.h> 105313bfe4SRoman Gushchin #include <poll.h> 115313bfe4SRoman Gushchin #include <stdlib.h> 125313bfe4SRoman Gushchin #include <sys/inotify.h> 135313bfe4SRoman Gushchin #include <string.h> 145313bfe4SRoman Gushchin #include <sys/wait.h> 155313bfe4SRoman Gushchin 165313bfe4SRoman Gushchin #include "../kselftest.h" 175313bfe4SRoman Gushchin #include "cgroup_util.h" 185313bfe4SRoman Gushchin 195313bfe4SRoman Gushchin #define DEBUG 205313bfe4SRoman Gushchin #ifdef DEBUG 215313bfe4SRoman Gushchin #define debug(args...) fprintf(stderr, args) 225313bfe4SRoman Gushchin #else 235313bfe4SRoman Gushchin #define debug(args...) 245313bfe4SRoman Gushchin #endif 255313bfe4SRoman Gushchin 265313bfe4SRoman Gushchin /* 275313bfe4SRoman Gushchin * Check if the cgroup is frozen by looking at the cgroup.events::frozen value. 285313bfe4SRoman Gushchin */ 295313bfe4SRoman Gushchin static int cg_check_frozen(const char *cgroup, bool frozen) 305313bfe4SRoman Gushchin { 315313bfe4SRoman Gushchin if (frozen) { 325313bfe4SRoman Gushchin if (cg_read_strstr(cgroup, "cgroup.events", "frozen 1") != 0) { 335313bfe4SRoman Gushchin debug("Cgroup %s isn't frozen\n", cgroup); 345313bfe4SRoman Gushchin return -1; 355313bfe4SRoman Gushchin } 365313bfe4SRoman Gushchin } else { 375313bfe4SRoman Gushchin /* 385313bfe4SRoman Gushchin * Check the cgroup.events::frozen value. 395313bfe4SRoman Gushchin */ 405313bfe4SRoman Gushchin if (cg_read_strstr(cgroup, "cgroup.events", "frozen 0") != 0) { 415313bfe4SRoman Gushchin debug("Cgroup %s is frozen\n", cgroup); 425313bfe4SRoman Gushchin return -1; 435313bfe4SRoman Gushchin } 445313bfe4SRoman Gushchin } 455313bfe4SRoman Gushchin 465313bfe4SRoman Gushchin return 0; 475313bfe4SRoman Gushchin } 485313bfe4SRoman Gushchin 495313bfe4SRoman Gushchin /* 505313bfe4SRoman Gushchin * Freeze the given cgroup. 515313bfe4SRoman Gushchin */ 525313bfe4SRoman Gushchin static int cg_freeze_nowait(const char *cgroup, bool freeze) 535313bfe4SRoman Gushchin { 545313bfe4SRoman Gushchin return cg_write(cgroup, "cgroup.freeze", freeze ? "1" : "0"); 555313bfe4SRoman Gushchin } 565313bfe4SRoman Gushchin 575313bfe4SRoman Gushchin /* 585313bfe4SRoman Gushchin * Prepare for waiting on cgroup.events file. 595313bfe4SRoman Gushchin */ 605313bfe4SRoman Gushchin static int cg_prepare_for_wait(const char *cgroup) 615313bfe4SRoman Gushchin { 625313bfe4SRoman Gushchin int fd, ret = -1; 635313bfe4SRoman Gushchin 645313bfe4SRoman Gushchin fd = inotify_init1(0); 655313bfe4SRoman Gushchin if (fd == -1) { 665313bfe4SRoman Gushchin debug("Error: inotify_init1() failed\n"); 675313bfe4SRoman Gushchin return fd; 685313bfe4SRoman Gushchin } 695313bfe4SRoman Gushchin 705313bfe4SRoman Gushchin ret = inotify_add_watch(fd, cg_control(cgroup, "cgroup.events"), 715313bfe4SRoman Gushchin IN_MODIFY); 725313bfe4SRoman Gushchin if (ret == -1) { 735313bfe4SRoman Gushchin debug("Error: inotify_add_watch() failed\n"); 745313bfe4SRoman Gushchin close(fd); 755313bfe4SRoman Gushchin } 765313bfe4SRoman Gushchin 775313bfe4SRoman Gushchin return fd; 785313bfe4SRoman Gushchin } 795313bfe4SRoman Gushchin 805313bfe4SRoman Gushchin /* 815313bfe4SRoman Gushchin * Wait for an event. If there are no events for 10 seconds, 825313bfe4SRoman Gushchin * treat this an error. 835313bfe4SRoman Gushchin */ 845313bfe4SRoman Gushchin static int cg_wait_for(int fd) 855313bfe4SRoman Gushchin { 865313bfe4SRoman Gushchin int ret = -1; 875313bfe4SRoman Gushchin struct pollfd fds = { 885313bfe4SRoman Gushchin .fd = fd, 895313bfe4SRoman Gushchin .events = POLLIN, 905313bfe4SRoman Gushchin }; 915313bfe4SRoman Gushchin 925313bfe4SRoman Gushchin while (true) { 935313bfe4SRoman Gushchin ret = poll(&fds, 1, 10000); 945313bfe4SRoman Gushchin 955313bfe4SRoman Gushchin if (ret == -1) { 965313bfe4SRoman Gushchin if (errno == EINTR) 975313bfe4SRoman Gushchin continue; 985313bfe4SRoman Gushchin debug("Error: poll() failed\n"); 995313bfe4SRoman Gushchin break; 1005313bfe4SRoman Gushchin } 1015313bfe4SRoman Gushchin 1025313bfe4SRoman Gushchin if (ret > 0 && fds.revents & POLLIN) { 1035313bfe4SRoman Gushchin ret = 0; 1045313bfe4SRoman Gushchin break; 1055313bfe4SRoman Gushchin } 1065313bfe4SRoman Gushchin } 1075313bfe4SRoman Gushchin 1085313bfe4SRoman Gushchin return ret; 1095313bfe4SRoman Gushchin } 1105313bfe4SRoman Gushchin 1115313bfe4SRoman Gushchin /* 1125313bfe4SRoman Gushchin * Attach a task to the given cgroup and wait for a cgroup frozen event. 1135313bfe4SRoman Gushchin * All transient events (e.g. populated) are ignored. 1145313bfe4SRoman Gushchin */ 1155313bfe4SRoman Gushchin static int cg_enter_and_wait_for_frozen(const char *cgroup, int pid, 1165313bfe4SRoman Gushchin bool frozen) 1175313bfe4SRoman Gushchin { 1185313bfe4SRoman Gushchin int fd, ret = -1; 1195313bfe4SRoman Gushchin int attempts; 1205313bfe4SRoman Gushchin 1215313bfe4SRoman Gushchin fd = cg_prepare_for_wait(cgroup); 1225313bfe4SRoman Gushchin if (fd < 0) 1235313bfe4SRoman Gushchin return fd; 1245313bfe4SRoman Gushchin 1255313bfe4SRoman Gushchin ret = cg_enter(cgroup, pid); 1265313bfe4SRoman Gushchin if (ret) 1275313bfe4SRoman Gushchin goto out; 1285313bfe4SRoman Gushchin 1295313bfe4SRoman Gushchin for (attempts = 0; attempts < 10; attempts++) { 1305313bfe4SRoman Gushchin ret = cg_wait_for(fd); 1315313bfe4SRoman Gushchin if (ret) 1325313bfe4SRoman Gushchin break; 1335313bfe4SRoman Gushchin 1345313bfe4SRoman Gushchin ret = cg_check_frozen(cgroup, frozen); 1355313bfe4SRoman Gushchin if (ret) 1365313bfe4SRoman Gushchin continue; 1375313bfe4SRoman Gushchin } 1385313bfe4SRoman Gushchin 1395313bfe4SRoman Gushchin out: 1405313bfe4SRoman Gushchin close(fd); 1415313bfe4SRoman Gushchin return ret; 1425313bfe4SRoman Gushchin } 1435313bfe4SRoman Gushchin 1445313bfe4SRoman Gushchin /* 1455313bfe4SRoman Gushchin * Freeze the given cgroup and wait for the inotify signal. 1465313bfe4SRoman Gushchin * If there are no events in 10 seconds, treat this as an error. 1475313bfe4SRoman Gushchin * Then check that the cgroup is in the desired state. 1485313bfe4SRoman Gushchin */ 1495313bfe4SRoman Gushchin static int cg_freeze_wait(const char *cgroup, bool freeze) 1505313bfe4SRoman Gushchin { 1515313bfe4SRoman Gushchin int fd, ret = -1; 1525313bfe4SRoman Gushchin 1535313bfe4SRoman Gushchin fd = cg_prepare_for_wait(cgroup); 1545313bfe4SRoman Gushchin if (fd < 0) 1555313bfe4SRoman Gushchin return fd; 1565313bfe4SRoman Gushchin 1575313bfe4SRoman Gushchin ret = cg_freeze_nowait(cgroup, freeze); 1585313bfe4SRoman Gushchin if (ret) { 1595313bfe4SRoman Gushchin debug("Error: cg_freeze_nowait() failed\n"); 1605313bfe4SRoman Gushchin goto out; 1615313bfe4SRoman Gushchin } 1625313bfe4SRoman Gushchin 1635313bfe4SRoman Gushchin ret = cg_wait_for(fd); 1645313bfe4SRoman Gushchin if (ret) 1655313bfe4SRoman Gushchin goto out; 1665313bfe4SRoman Gushchin 1675313bfe4SRoman Gushchin ret = cg_check_frozen(cgroup, freeze); 1685313bfe4SRoman Gushchin out: 1695313bfe4SRoman Gushchin close(fd); 1705313bfe4SRoman Gushchin return ret; 1715313bfe4SRoman Gushchin } 1725313bfe4SRoman Gushchin 1735313bfe4SRoman Gushchin /* 1745313bfe4SRoman Gushchin * A simple process running in a sleep loop until being 1755313bfe4SRoman Gushchin * re-parented. 1765313bfe4SRoman Gushchin */ 1775313bfe4SRoman Gushchin static int child_fn(const char *cgroup, void *arg) 1785313bfe4SRoman Gushchin { 1795313bfe4SRoman Gushchin int ppid = getppid(); 1805313bfe4SRoman Gushchin 1815313bfe4SRoman Gushchin while (getppid() == ppid) 1825313bfe4SRoman Gushchin usleep(1000); 1835313bfe4SRoman Gushchin 1845313bfe4SRoman Gushchin return getppid() == ppid; 1855313bfe4SRoman Gushchin } 1865313bfe4SRoman Gushchin 1875313bfe4SRoman Gushchin /* 1885313bfe4SRoman Gushchin * A simple test for the cgroup freezer: populated the cgroup with 100 1895313bfe4SRoman Gushchin * running processes and freeze it. Then unfreeze it. Then it kills all 1905313bfe4SRoman Gushchin * processes and destroys the cgroup. 1915313bfe4SRoman Gushchin */ 1925313bfe4SRoman Gushchin static int test_cgfreezer_simple(const char *root) 1935313bfe4SRoman Gushchin { 1945313bfe4SRoman Gushchin int ret = KSFT_FAIL; 1955313bfe4SRoman Gushchin char *cgroup = NULL; 1965313bfe4SRoman Gushchin int i; 1975313bfe4SRoman Gushchin 1985313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_test_simple"); 1995313bfe4SRoman Gushchin if (!cgroup) 2005313bfe4SRoman Gushchin goto cleanup; 2015313bfe4SRoman Gushchin 2025313bfe4SRoman Gushchin if (cg_create(cgroup)) 2035313bfe4SRoman Gushchin goto cleanup; 2045313bfe4SRoman Gushchin 2055313bfe4SRoman Gushchin for (i = 0; i < 100; i++) 2065313bfe4SRoman Gushchin cg_run_nowait(cgroup, child_fn, NULL); 2075313bfe4SRoman Gushchin 2085313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 100)) 2095313bfe4SRoman Gushchin goto cleanup; 2105313bfe4SRoman Gushchin 2115313bfe4SRoman Gushchin if (cg_check_frozen(cgroup, false)) 2125313bfe4SRoman Gushchin goto cleanup; 2135313bfe4SRoman Gushchin 2145313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true)) 2155313bfe4SRoman Gushchin goto cleanup; 2165313bfe4SRoman Gushchin 2175313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, false)) 2185313bfe4SRoman Gushchin goto cleanup; 2195313bfe4SRoman Gushchin 2205313bfe4SRoman Gushchin ret = KSFT_PASS; 2215313bfe4SRoman Gushchin 2225313bfe4SRoman Gushchin cleanup: 2235313bfe4SRoman Gushchin if (cgroup) 2245313bfe4SRoman Gushchin cg_destroy(cgroup); 2255313bfe4SRoman Gushchin free(cgroup); 2265313bfe4SRoman Gushchin return ret; 2275313bfe4SRoman Gushchin } 2285313bfe4SRoman Gushchin 2295313bfe4SRoman Gushchin /* 2305313bfe4SRoman Gushchin * The test creates the following hierarchy: 2315313bfe4SRoman Gushchin * A 2325313bfe4SRoman Gushchin * / / \ \ 2335313bfe4SRoman Gushchin * B E I K 2345313bfe4SRoman Gushchin * /\ | 2355313bfe4SRoman Gushchin * C D F 2365313bfe4SRoman Gushchin * | 2375313bfe4SRoman Gushchin * G 2385313bfe4SRoman Gushchin * | 2395313bfe4SRoman Gushchin * H 2405313bfe4SRoman Gushchin * 2415313bfe4SRoman Gushchin * with a process in C, H and 3 processes in K. 2425313bfe4SRoman Gushchin * Then it tries to freeze and unfreeze the whole tree. 2435313bfe4SRoman Gushchin */ 2445313bfe4SRoman Gushchin static int test_cgfreezer_tree(const char *root) 2455313bfe4SRoman Gushchin { 2465313bfe4SRoman Gushchin char *cgroup[10] = {0}; 2475313bfe4SRoman Gushchin int ret = KSFT_FAIL; 2485313bfe4SRoman Gushchin int i; 2495313bfe4SRoman Gushchin 2505313bfe4SRoman Gushchin cgroup[0] = cg_name(root, "cg_test_tree_A"); 2515313bfe4SRoman Gushchin if (!cgroup[0]) 2525313bfe4SRoman Gushchin goto cleanup; 2535313bfe4SRoman Gushchin 2545313bfe4SRoman Gushchin cgroup[1] = cg_name(cgroup[0], "B"); 2555313bfe4SRoman Gushchin if (!cgroup[1]) 2565313bfe4SRoman Gushchin goto cleanup; 2575313bfe4SRoman Gushchin 2585313bfe4SRoman Gushchin cgroup[2] = cg_name(cgroup[1], "C"); 2595313bfe4SRoman Gushchin if (!cgroup[2]) 2605313bfe4SRoman Gushchin goto cleanup; 2615313bfe4SRoman Gushchin 2625313bfe4SRoman Gushchin cgroup[3] = cg_name(cgroup[1], "D"); 2635313bfe4SRoman Gushchin if (!cgroup[3]) 2645313bfe4SRoman Gushchin goto cleanup; 2655313bfe4SRoman Gushchin 2665313bfe4SRoman Gushchin cgroup[4] = cg_name(cgroup[0], "E"); 2675313bfe4SRoman Gushchin if (!cgroup[4]) 2685313bfe4SRoman Gushchin goto cleanup; 2695313bfe4SRoman Gushchin 2705313bfe4SRoman Gushchin cgroup[5] = cg_name(cgroup[4], "F"); 2715313bfe4SRoman Gushchin if (!cgroup[5]) 2725313bfe4SRoman Gushchin goto cleanup; 2735313bfe4SRoman Gushchin 2745313bfe4SRoman Gushchin cgroup[6] = cg_name(cgroup[5], "G"); 2755313bfe4SRoman Gushchin if (!cgroup[6]) 2765313bfe4SRoman Gushchin goto cleanup; 2775313bfe4SRoman Gushchin 2785313bfe4SRoman Gushchin cgroup[7] = cg_name(cgroup[6], "H"); 2795313bfe4SRoman Gushchin if (!cgroup[7]) 2805313bfe4SRoman Gushchin goto cleanup; 2815313bfe4SRoman Gushchin 2825313bfe4SRoman Gushchin cgroup[8] = cg_name(cgroup[0], "I"); 2835313bfe4SRoman Gushchin if (!cgroup[8]) 2845313bfe4SRoman Gushchin goto cleanup; 2855313bfe4SRoman Gushchin 2865313bfe4SRoman Gushchin cgroup[9] = cg_name(cgroup[0], "K"); 2875313bfe4SRoman Gushchin if (!cgroup[9]) 2885313bfe4SRoman Gushchin goto cleanup; 2895313bfe4SRoman Gushchin 2905313bfe4SRoman Gushchin for (i = 0; i < 10; i++) 2915313bfe4SRoman Gushchin if (cg_create(cgroup[i])) 2925313bfe4SRoman Gushchin goto cleanup; 2935313bfe4SRoman Gushchin 2945313bfe4SRoman Gushchin cg_run_nowait(cgroup[2], child_fn, NULL); 2955313bfe4SRoman Gushchin cg_run_nowait(cgroup[7], child_fn, NULL); 2965313bfe4SRoman Gushchin cg_run_nowait(cgroup[9], child_fn, NULL); 2975313bfe4SRoman Gushchin cg_run_nowait(cgroup[9], child_fn, NULL); 2985313bfe4SRoman Gushchin cg_run_nowait(cgroup[9], child_fn, NULL); 2995313bfe4SRoman Gushchin 3005313bfe4SRoman Gushchin /* 3015313bfe4SRoman Gushchin * Wait until all child processes will enter 3025313bfe4SRoman Gushchin * corresponding cgroups. 3035313bfe4SRoman Gushchin */ 3045313bfe4SRoman Gushchin 3055313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup[2], 1) || 3065313bfe4SRoman Gushchin cg_wait_for_proc_count(cgroup[7], 1) || 3075313bfe4SRoman Gushchin cg_wait_for_proc_count(cgroup[9], 3)) 3085313bfe4SRoman Gushchin goto cleanup; 3095313bfe4SRoman Gushchin 3105313bfe4SRoman Gushchin /* 3115313bfe4SRoman Gushchin * Freeze B. 3125313bfe4SRoman Gushchin */ 3135313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[1], true)) 3145313bfe4SRoman Gushchin goto cleanup; 3155313bfe4SRoman Gushchin 3165313bfe4SRoman Gushchin /* 3175313bfe4SRoman Gushchin * Freeze F. 3185313bfe4SRoman Gushchin */ 3195313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[5], true)) 3205313bfe4SRoman Gushchin goto cleanup; 3215313bfe4SRoman Gushchin 3225313bfe4SRoman Gushchin /* 3235313bfe4SRoman Gushchin * Freeze G. 3245313bfe4SRoman Gushchin */ 3255313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[6], true)) 3265313bfe4SRoman Gushchin goto cleanup; 3275313bfe4SRoman Gushchin 3285313bfe4SRoman Gushchin /* 3295313bfe4SRoman Gushchin * Check that A and E are not frozen. 3305313bfe4SRoman Gushchin */ 3315313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[0], false)) 3325313bfe4SRoman Gushchin goto cleanup; 3335313bfe4SRoman Gushchin 3345313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[4], false)) 3355313bfe4SRoman Gushchin goto cleanup; 3365313bfe4SRoman Gushchin 3375313bfe4SRoman Gushchin /* 3385313bfe4SRoman Gushchin * Freeze A. Check that A, B and E are frozen. 3395313bfe4SRoman Gushchin */ 3405313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[0], true)) 3415313bfe4SRoman Gushchin goto cleanup; 3425313bfe4SRoman Gushchin 3435313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[1], true)) 3445313bfe4SRoman Gushchin goto cleanup; 3455313bfe4SRoman Gushchin 3465313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[4], true)) 3475313bfe4SRoman Gushchin goto cleanup; 3485313bfe4SRoman Gushchin 3495313bfe4SRoman Gushchin /* 3505313bfe4SRoman Gushchin * Unfreeze B, F and G 3515313bfe4SRoman Gushchin */ 3525313bfe4SRoman Gushchin if (cg_freeze_nowait(cgroup[1], false)) 3535313bfe4SRoman Gushchin goto cleanup; 3545313bfe4SRoman Gushchin 3555313bfe4SRoman Gushchin if (cg_freeze_nowait(cgroup[5], false)) 3565313bfe4SRoman Gushchin goto cleanup; 3575313bfe4SRoman Gushchin 3585313bfe4SRoman Gushchin if (cg_freeze_nowait(cgroup[6], false)) 3595313bfe4SRoman Gushchin goto cleanup; 3605313bfe4SRoman Gushchin 3615313bfe4SRoman Gushchin /* 3625313bfe4SRoman Gushchin * Check that C and H are still frozen. 3635313bfe4SRoman Gushchin */ 3645313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[2], true)) 3655313bfe4SRoman Gushchin goto cleanup; 3665313bfe4SRoman Gushchin 3675313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[7], true)) 3685313bfe4SRoman Gushchin goto cleanup; 3695313bfe4SRoman Gushchin 3705313bfe4SRoman Gushchin /* 3715313bfe4SRoman Gushchin * Unfreeze A. Check that A, C and K are not frozen. 3725313bfe4SRoman Gushchin */ 3735313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[0], false)) 3745313bfe4SRoman Gushchin goto cleanup; 3755313bfe4SRoman Gushchin 3765313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[2], false)) 3775313bfe4SRoman Gushchin goto cleanup; 3785313bfe4SRoman Gushchin 3795313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[9], false)) 3805313bfe4SRoman Gushchin goto cleanup; 3815313bfe4SRoman Gushchin 3825313bfe4SRoman Gushchin ret = KSFT_PASS; 3835313bfe4SRoman Gushchin 3845313bfe4SRoman Gushchin cleanup: 3855313bfe4SRoman Gushchin for (i = 9; i >= 0 && cgroup[i]; i--) { 3865313bfe4SRoman Gushchin cg_destroy(cgroup[i]); 3875313bfe4SRoman Gushchin free(cgroup[i]); 3885313bfe4SRoman Gushchin } 3895313bfe4SRoman Gushchin 3905313bfe4SRoman Gushchin return ret; 3915313bfe4SRoman Gushchin } 3925313bfe4SRoman Gushchin 3935313bfe4SRoman Gushchin /* 3945313bfe4SRoman Gushchin * A fork bomb emulator. 3955313bfe4SRoman Gushchin */ 3965313bfe4SRoman Gushchin static int forkbomb_fn(const char *cgroup, void *arg) 3975313bfe4SRoman Gushchin { 3985313bfe4SRoman Gushchin int ppid; 3995313bfe4SRoman Gushchin 4005313bfe4SRoman Gushchin fork(); 4015313bfe4SRoman Gushchin fork(); 4025313bfe4SRoman Gushchin 4035313bfe4SRoman Gushchin ppid = getppid(); 4045313bfe4SRoman Gushchin 4055313bfe4SRoman Gushchin while (getppid() == ppid) 4065313bfe4SRoman Gushchin usleep(1000); 4075313bfe4SRoman Gushchin 4085313bfe4SRoman Gushchin return getppid() == ppid; 4095313bfe4SRoman Gushchin } 4105313bfe4SRoman Gushchin 4115313bfe4SRoman Gushchin /* 4125313bfe4SRoman Gushchin * The test runs a fork bomb in a cgroup and tries to freeze it. 4135313bfe4SRoman Gushchin * Then it kills all processes and checks that cgroup isn't populated 4145313bfe4SRoman Gushchin * anymore. 4155313bfe4SRoman Gushchin */ 4165313bfe4SRoman Gushchin static int test_cgfreezer_forkbomb(const char *root) 4175313bfe4SRoman Gushchin { 4185313bfe4SRoman Gushchin int ret = KSFT_FAIL; 4195313bfe4SRoman Gushchin char *cgroup = NULL; 4205313bfe4SRoman Gushchin 4215313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_forkbomb_test"); 4225313bfe4SRoman Gushchin if (!cgroup) 4235313bfe4SRoman Gushchin goto cleanup; 4245313bfe4SRoman Gushchin 4255313bfe4SRoman Gushchin if (cg_create(cgroup)) 4265313bfe4SRoman Gushchin goto cleanup; 4275313bfe4SRoman Gushchin 4285313bfe4SRoman Gushchin cg_run_nowait(cgroup, forkbomb_fn, NULL); 4295313bfe4SRoman Gushchin 4305313bfe4SRoman Gushchin usleep(100000); 4315313bfe4SRoman Gushchin 4325313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true)) 4335313bfe4SRoman Gushchin goto cleanup; 4345313bfe4SRoman Gushchin 4355313bfe4SRoman Gushchin if (cg_killall(cgroup)) 4365313bfe4SRoman Gushchin goto cleanup; 4375313bfe4SRoman Gushchin 4385313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 0)) 4395313bfe4SRoman Gushchin goto cleanup; 4405313bfe4SRoman Gushchin 4415313bfe4SRoman Gushchin ret = KSFT_PASS; 4425313bfe4SRoman Gushchin 4435313bfe4SRoman Gushchin cleanup: 4445313bfe4SRoman Gushchin if (cgroup) 4455313bfe4SRoman Gushchin cg_destroy(cgroup); 4465313bfe4SRoman Gushchin free(cgroup); 4475313bfe4SRoman Gushchin return ret; 4485313bfe4SRoman Gushchin } 4495313bfe4SRoman Gushchin 4505313bfe4SRoman Gushchin /* 45144e9d308SRoman Gushchin * The test creates a cgroups and freezes it. Then it creates a child cgroup 45244e9d308SRoman Gushchin * and populates it with a task. After that it checks that the child cgroup 45344e9d308SRoman Gushchin * is frozen and the parent cgroup remains frozen too. 45444e9d308SRoman Gushchin */ 45544e9d308SRoman Gushchin static int test_cgfreezer_mkdir(const char *root) 45644e9d308SRoman Gushchin { 45744e9d308SRoman Gushchin int ret = KSFT_FAIL; 45844e9d308SRoman Gushchin char *parent, *child = NULL; 45944e9d308SRoman Gushchin int pid; 46044e9d308SRoman Gushchin 46144e9d308SRoman Gushchin parent = cg_name(root, "cg_test_mkdir_A"); 46244e9d308SRoman Gushchin if (!parent) 46344e9d308SRoman Gushchin goto cleanup; 46444e9d308SRoman Gushchin 46544e9d308SRoman Gushchin child = cg_name(parent, "cg_test_mkdir_B"); 46644e9d308SRoman Gushchin if (!child) 46744e9d308SRoman Gushchin goto cleanup; 46844e9d308SRoman Gushchin 46944e9d308SRoman Gushchin if (cg_create(parent)) 47044e9d308SRoman Gushchin goto cleanup; 47144e9d308SRoman Gushchin 47244e9d308SRoman Gushchin if (cg_freeze_wait(parent, true)) 47344e9d308SRoman Gushchin goto cleanup; 47444e9d308SRoman Gushchin 47544e9d308SRoman Gushchin if (cg_create(child)) 47644e9d308SRoman Gushchin goto cleanup; 47744e9d308SRoman Gushchin 47844e9d308SRoman Gushchin pid = cg_run_nowait(child, child_fn, NULL); 47944e9d308SRoman Gushchin if (pid < 0) 48044e9d308SRoman Gushchin goto cleanup; 48144e9d308SRoman Gushchin 48244e9d308SRoman Gushchin if (cg_wait_for_proc_count(child, 1)) 48344e9d308SRoman Gushchin goto cleanup; 48444e9d308SRoman Gushchin 48544e9d308SRoman Gushchin if (cg_check_frozen(child, true)) 48644e9d308SRoman Gushchin goto cleanup; 48744e9d308SRoman Gushchin 48844e9d308SRoman Gushchin if (cg_check_frozen(parent, true)) 48944e9d308SRoman Gushchin goto cleanup; 49044e9d308SRoman Gushchin 49144e9d308SRoman Gushchin ret = KSFT_PASS; 49244e9d308SRoman Gushchin 49344e9d308SRoman Gushchin cleanup: 49444e9d308SRoman Gushchin if (child) 49544e9d308SRoman Gushchin cg_destroy(child); 49644e9d308SRoman Gushchin free(child); 49744e9d308SRoman Gushchin if (parent) 49844e9d308SRoman Gushchin cg_destroy(parent); 49944e9d308SRoman Gushchin free(parent); 50044e9d308SRoman Gushchin return ret; 50144e9d308SRoman Gushchin } 50244e9d308SRoman Gushchin 50344e9d308SRoman Gushchin /* 5045313bfe4SRoman Gushchin * The test creates two nested cgroups, freezes the parent 5055313bfe4SRoman Gushchin * and removes the child. Then it checks that the parent cgroup 5065313bfe4SRoman Gushchin * remains frozen and it's possible to create a new child 5075313bfe4SRoman Gushchin * without unfreezing. The new child is frozen too. 5085313bfe4SRoman Gushchin */ 5095313bfe4SRoman Gushchin static int test_cgfreezer_rmdir(const char *root) 5105313bfe4SRoman Gushchin { 5115313bfe4SRoman Gushchin int ret = KSFT_FAIL; 5125313bfe4SRoman Gushchin char *parent, *child = NULL; 5135313bfe4SRoman Gushchin 5145313bfe4SRoman Gushchin parent = cg_name(root, "cg_test_rmdir_A"); 5155313bfe4SRoman Gushchin if (!parent) 5165313bfe4SRoman Gushchin goto cleanup; 5175313bfe4SRoman Gushchin 5185313bfe4SRoman Gushchin child = cg_name(parent, "cg_test_rmdir_B"); 5195313bfe4SRoman Gushchin if (!child) 5205313bfe4SRoman Gushchin goto cleanup; 5215313bfe4SRoman Gushchin 5225313bfe4SRoman Gushchin if (cg_create(parent)) 5235313bfe4SRoman Gushchin goto cleanup; 5245313bfe4SRoman Gushchin 5255313bfe4SRoman Gushchin if (cg_create(child)) 5265313bfe4SRoman Gushchin goto cleanup; 5275313bfe4SRoman Gushchin 5285313bfe4SRoman Gushchin if (cg_freeze_wait(parent, true)) 5295313bfe4SRoman Gushchin goto cleanup; 5305313bfe4SRoman Gushchin 5315313bfe4SRoman Gushchin if (cg_destroy(child)) 5325313bfe4SRoman Gushchin goto cleanup; 5335313bfe4SRoman Gushchin 5345313bfe4SRoman Gushchin if (cg_check_frozen(parent, true)) 5355313bfe4SRoman Gushchin goto cleanup; 5365313bfe4SRoman Gushchin 5375313bfe4SRoman Gushchin if (cg_create(child)) 5385313bfe4SRoman Gushchin goto cleanup; 5395313bfe4SRoman Gushchin 5405313bfe4SRoman Gushchin if (cg_check_frozen(child, true)) 5415313bfe4SRoman Gushchin goto cleanup; 5425313bfe4SRoman Gushchin 5435313bfe4SRoman Gushchin ret = KSFT_PASS; 5445313bfe4SRoman Gushchin 5455313bfe4SRoman Gushchin cleanup: 5465313bfe4SRoman Gushchin if (child) 5475313bfe4SRoman Gushchin cg_destroy(child); 5485313bfe4SRoman Gushchin free(child); 5495313bfe4SRoman Gushchin if (parent) 5505313bfe4SRoman Gushchin cg_destroy(parent); 5515313bfe4SRoman Gushchin free(parent); 5525313bfe4SRoman Gushchin return ret; 5535313bfe4SRoman Gushchin } 5545313bfe4SRoman Gushchin 5555313bfe4SRoman Gushchin /* 5565313bfe4SRoman Gushchin * The test creates two cgroups: A and B, runs a process in A 5575313bfe4SRoman Gushchin * and performs several migrations: 5585313bfe4SRoman Gushchin * 1) A (running) -> B (frozen) 5595313bfe4SRoman Gushchin * 2) B (frozen) -> A (running) 5605313bfe4SRoman Gushchin * 3) A (frozen) -> B (frozen) 5615313bfe4SRoman Gushchin * 5625313bfe4SRoman Gushchin * On each step it checks the actual state of both cgroups. 5635313bfe4SRoman Gushchin */ 5645313bfe4SRoman Gushchin static int test_cgfreezer_migrate(const char *root) 5655313bfe4SRoman Gushchin { 5665313bfe4SRoman Gushchin int ret = KSFT_FAIL; 5675313bfe4SRoman Gushchin char *cgroup[2] = {0}; 5685313bfe4SRoman Gushchin int pid; 5695313bfe4SRoman Gushchin 5705313bfe4SRoman Gushchin cgroup[0] = cg_name(root, "cg_test_migrate_A"); 5715313bfe4SRoman Gushchin if (!cgroup[0]) 5725313bfe4SRoman Gushchin goto cleanup; 5735313bfe4SRoman Gushchin 5745313bfe4SRoman Gushchin cgroup[1] = cg_name(root, "cg_test_migrate_B"); 5755313bfe4SRoman Gushchin if (!cgroup[1]) 5765313bfe4SRoman Gushchin goto cleanup; 5775313bfe4SRoman Gushchin 5785313bfe4SRoman Gushchin if (cg_create(cgroup[0])) 5795313bfe4SRoman Gushchin goto cleanup; 5805313bfe4SRoman Gushchin 5815313bfe4SRoman Gushchin if (cg_create(cgroup[1])) 5825313bfe4SRoman Gushchin goto cleanup; 5835313bfe4SRoman Gushchin 5845313bfe4SRoman Gushchin pid = cg_run_nowait(cgroup[0], child_fn, NULL); 5855313bfe4SRoman Gushchin if (pid < 0) 5865313bfe4SRoman Gushchin goto cleanup; 5875313bfe4SRoman Gushchin 5885313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup[0], 1)) 5895313bfe4SRoman Gushchin goto cleanup; 5905313bfe4SRoman Gushchin 5915313bfe4SRoman Gushchin /* 5925313bfe4SRoman Gushchin * Migrate from A (running) to B (frozen) 5935313bfe4SRoman Gushchin */ 5945313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[1], true)) 5955313bfe4SRoman Gushchin goto cleanup; 5965313bfe4SRoman Gushchin 5975313bfe4SRoman Gushchin if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true)) 5985313bfe4SRoman Gushchin goto cleanup; 5995313bfe4SRoman Gushchin 6005313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[0], false)) 6015313bfe4SRoman Gushchin goto cleanup; 6025313bfe4SRoman Gushchin 6035313bfe4SRoman Gushchin /* 6045313bfe4SRoman Gushchin * Migrate from B (frozen) to A (running) 6055313bfe4SRoman Gushchin */ 6065313bfe4SRoman Gushchin if (cg_enter_and_wait_for_frozen(cgroup[0], pid, false)) 6075313bfe4SRoman Gushchin goto cleanup; 6085313bfe4SRoman Gushchin 6095313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[1], true)) 6105313bfe4SRoman Gushchin goto cleanup; 6115313bfe4SRoman Gushchin 6125313bfe4SRoman Gushchin /* 6135313bfe4SRoman Gushchin * Migrate from A (frozen) to B (frozen) 6145313bfe4SRoman Gushchin */ 6155313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[0], true)) 6165313bfe4SRoman Gushchin goto cleanup; 6175313bfe4SRoman Gushchin 6185313bfe4SRoman Gushchin if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true)) 6195313bfe4SRoman Gushchin goto cleanup; 6205313bfe4SRoman Gushchin 6215313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[0], true)) 6225313bfe4SRoman Gushchin goto cleanup; 6235313bfe4SRoman Gushchin 6245313bfe4SRoman Gushchin ret = KSFT_PASS; 6255313bfe4SRoman Gushchin 6265313bfe4SRoman Gushchin cleanup: 6275313bfe4SRoman Gushchin if (cgroup[0]) 6285313bfe4SRoman Gushchin cg_destroy(cgroup[0]); 6295313bfe4SRoman Gushchin free(cgroup[0]); 6305313bfe4SRoman Gushchin if (cgroup[1]) 6315313bfe4SRoman Gushchin cg_destroy(cgroup[1]); 6325313bfe4SRoman Gushchin free(cgroup[1]); 6335313bfe4SRoman Gushchin return ret; 6345313bfe4SRoman Gushchin } 6355313bfe4SRoman Gushchin 6365313bfe4SRoman Gushchin /* 6375313bfe4SRoman Gushchin * The test checks that ptrace works with a tracing process in a frozen cgroup. 6385313bfe4SRoman Gushchin */ 6395313bfe4SRoman Gushchin static int test_cgfreezer_ptrace(const char *root) 6405313bfe4SRoman Gushchin { 6415313bfe4SRoman Gushchin int ret = KSFT_FAIL; 6425313bfe4SRoman Gushchin char *cgroup = NULL; 6435313bfe4SRoman Gushchin siginfo_t siginfo; 6445313bfe4SRoman Gushchin int pid; 6455313bfe4SRoman Gushchin 6465313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_test_ptrace"); 6475313bfe4SRoman Gushchin if (!cgroup) 6485313bfe4SRoman Gushchin goto cleanup; 6495313bfe4SRoman Gushchin 6505313bfe4SRoman Gushchin if (cg_create(cgroup)) 6515313bfe4SRoman Gushchin goto cleanup; 6525313bfe4SRoman Gushchin 6535313bfe4SRoman Gushchin pid = cg_run_nowait(cgroup, child_fn, NULL); 6545313bfe4SRoman Gushchin if (pid < 0) 6555313bfe4SRoman Gushchin goto cleanup; 6565313bfe4SRoman Gushchin 6575313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 1)) 6585313bfe4SRoman Gushchin goto cleanup; 6595313bfe4SRoman Gushchin 6605313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true)) 6615313bfe4SRoman Gushchin goto cleanup; 6625313bfe4SRoman Gushchin 6635313bfe4SRoman Gushchin if (ptrace(PTRACE_SEIZE, pid, NULL, NULL)) 6645313bfe4SRoman Gushchin goto cleanup; 6655313bfe4SRoman Gushchin 6665313bfe4SRoman Gushchin if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) 6675313bfe4SRoman Gushchin goto cleanup; 6685313bfe4SRoman Gushchin 6695313bfe4SRoman Gushchin waitpid(pid, NULL, 0); 6705313bfe4SRoman Gushchin 6715313bfe4SRoman Gushchin /* 6725313bfe4SRoman Gushchin * Cgroup has to remain frozen, however the test task 6735313bfe4SRoman Gushchin * is in traced state. 6745313bfe4SRoman Gushchin */ 6755313bfe4SRoman Gushchin if (cg_check_frozen(cgroup, true)) 6765313bfe4SRoman Gushchin goto cleanup; 6775313bfe4SRoman Gushchin 6785313bfe4SRoman Gushchin if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo)) 6795313bfe4SRoman Gushchin goto cleanup; 6805313bfe4SRoman Gushchin 6815313bfe4SRoman Gushchin if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) 6825313bfe4SRoman Gushchin goto cleanup; 6835313bfe4SRoman Gushchin 6845313bfe4SRoman Gushchin if (cg_check_frozen(cgroup, true)) 6855313bfe4SRoman Gushchin goto cleanup; 6865313bfe4SRoman Gushchin 6875313bfe4SRoman Gushchin ret = KSFT_PASS; 6885313bfe4SRoman Gushchin 6895313bfe4SRoman Gushchin cleanup: 6905313bfe4SRoman Gushchin if (cgroup) 6915313bfe4SRoman Gushchin cg_destroy(cgroup); 6925313bfe4SRoman Gushchin free(cgroup); 6935313bfe4SRoman Gushchin return ret; 6945313bfe4SRoman Gushchin } 6955313bfe4SRoman Gushchin 6965313bfe4SRoman Gushchin /* 6975313bfe4SRoman Gushchin * Check if the process is stopped. 6985313bfe4SRoman Gushchin */ 6995313bfe4SRoman Gushchin static int proc_check_stopped(int pid) 7005313bfe4SRoman Gushchin { 7015313bfe4SRoman Gushchin char buf[PAGE_SIZE]; 7025313bfe4SRoman Gushchin int len; 7035313bfe4SRoman Gushchin 70458c9f75bSMichal Koutný len = proc_read_text(pid, 0, "stat", buf, sizeof(buf)); 7055313bfe4SRoman Gushchin if (len == -1) { 7065313bfe4SRoman Gushchin debug("Can't get %d stat\n", pid); 7075313bfe4SRoman Gushchin return -1; 7085313bfe4SRoman Gushchin } 7095313bfe4SRoman Gushchin 7105313bfe4SRoman Gushchin if (strstr(buf, "(test_freezer) T ") == NULL) { 7115313bfe4SRoman Gushchin debug("Process %d in the unexpected state: %s\n", pid, buf); 7125313bfe4SRoman Gushchin return -1; 7135313bfe4SRoman Gushchin } 7145313bfe4SRoman Gushchin 7155313bfe4SRoman Gushchin return 0; 7165313bfe4SRoman Gushchin } 7175313bfe4SRoman Gushchin 7185313bfe4SRoman Gushchin /* 7195313bfe4SRoman Gushchin * Test that it's possible to freeze a cgroup with a stopped process. 7205313bfe4SRoman Gushchin */ 7215313bfe4SRoman Gushchin static int test_cgfreezer_stopped(const char *root) 7225313bfe4SRoman Gushchin { 7235313bfe4SRoman Gushchin int pid, ret = KSFT_FAIL; 7245313bfe4SRoman Gushchin char *cgroup = NULL; 7255313bfe4SRoman Gushchin 7265313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_test_stopped"); 7275313bfe4SRoman Gushchin if (!cgroup) 7285313bfe4SRoman Gushchin goto cleanup; 7295313bfe4SRoman Gushchin 7305313bfe4SRoman Gushchin if (cg_create(cgroup)) 7315313bfe4SRoman Gushchin goto cleanup; 7325313bfe4SRoman Gushchin 7335313bfe4SRoman Gushchin pid = cg_run_nowait(cgroup, child_fn, NULL); 7345313bfe4SRoman Gushchin 7355313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 1)) 7365313bfe4SRoman Gushchin goto cleanup; 7375313bfe4SRoman Gushchin 7385313bfe4SRoman Gushchin if (kill(pid, SIGSTOP)) 7395313bfe4SRoman Gushchin goto cleanup; 7405313bfe4SRoman Gushchin 7415313bfe4SRoman Gushchin if (cg_check_frozen(cgroup, false)) 7425313bfe4SRoman Gushchin goto cleanup; 7435313bfe4SRoman Gushchin 7445313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true)) 7455313bfe4SRoman Gushchin goto cleanup; 7465313bfe4SRoman Gushchin 7475313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, false)) 7485313bfe4SRoman Gushchin goto cleanup; 7495313bfe4SRoman Gushchin 7505313bfe4SRoman Gushchin if (proc_check_stopped(pid)) 7515313bfe4SRoman Gushchin goto cleanup; 7525313bfe4SRoman Gushchin 7535313bfe4SRoman Gushchin ret = KSFT_PASS; 7545313bfe4SRoman Gushchin 7555313bfe4SRoman Gushchin cleanup: 7565313bfe4SRoman Gushchin if (cgroup) 7575313bfe4SRoman Gushchin cg_destroy(cgroup); 7585313bfe4SRoman Gushchin free(cgroup); 7595313bfe4SRoman Gushchin return ret; 7605313bfe4SRoman Gushchin } 7615313bfe4SRoman Gushchin 7625313bfe4SRoman Gushchin /* 7635313bfe4SRoman Gushchin * Test that it's possible to freeze a cgroup with a ptraced process. 7645313bfe4SRoman Gushchin */ 7655313bfe4SRoman Gushchin static int test_cgfreezer_ptraced(const char *root) 7665313bfe4SRoman Gushchin { 7675313bfe4SRoman Gushchin int pid, ret = KSFT_FAIL; 7685313bfe4SRoman Gushchin char *cgroup = NULL; 7695313bfe4SRoman Gushchin siginfo_t siginfo; 7705313bfe4SRoman Gushchin 7715313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_test_ptraced"); 7725313bfe4SRoman Gushchin if (!cgroup) 7735313bfe4SRoman Gushchin goto cleanup; 7745313bfe4SRoman Gushchin 7755313bfe4SRoman Gushchin if (cg_create(cgroup)) 7765313bfe4SRoman Gushchin goto cleanup; 7775313bfe4SRoman Gushchin 7785313bfe4SRoman Gushchin pid = cg_run_nowait(cgroup, child_fn, NULL); 7795313bfe4SRoman Gushchin 7805313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 1)) 7815313bfe4SRoman Gushchin goto cleanup; 7825313bfe4SRoman Gushchin 7835313bfe4SRoman Gushchin if (ptrace(PTRACE_SEIZE, pid, NULL, NULL)) 7845313bfe4SRoman Gushchin goto cleanup; 7855313bfe4SRoman Gushchin 7865313bfe4SRoman Gushchin if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) 7875313bfe4SRoman Gushchin goto cleanup; 7885313bfe4SRoman Gushchin 7895313bfe4SRoman Gushchin waitpid(pid, NULL, 0); 7905313bfe4SRoman Gushchin 7915313bfe4SRoman Gushchin if (cg_check_frozen(cgroup, false)) 7925313bfe4SRoman Gushchin goto cleanup; 7935313bfe4SRoman Gushchin 7945313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true)) 7955313bfe4SRoman Gushchin goto cleanup; 7965313bfe4SRoman Gushchin 7975313bfe4SRoman Gushchin /* 7985313bfe4SRoman Gushchin * cg_check_frozen(cgroup, true) will fail here, 7995313bfe4SRoman Gushchin * because the task in in the TRACEd state. 8005313bfe4SRoman Gushchin */ 8015313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, false)) 8025313bfe4SRoman Gushchin goto cleanup; 8035313bfe4SRoman Gushchin 8045313bfe4SRoman Gushchin if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo)) 8055313bfe4SRoman Gushchin goto cleanup; 8065313bfe4SRoman Gushchin 8075313bfe4SRoman Gushchin if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) 8085313bfe4SRoman Gushchin goto cleanup; 8095313bfe4SRoman Gushchin 8105313bfe4SRoman Gushchin ret = KSFT_PASS; 8115313bfe4SRoman Gushchin 8125313bfe4SRoman Gushchin cleanup: 8135313bfe4SRoman Gushchin if (cgroup) 8145313bfe4SRoman Gushchin cg_destroy(cgroup); 8155313bfe4SRoman Gushchin free(cgroup); 8165313bfe4SRoman Gushchin return ret; 8175313bfe4SRoman Gushchin } 8185313bfe4SRoman Gushchin 8195313bfe4SRoman Gushchin static int vfork_fn(const char *cgroup, void *arg) 8205313bfe4SRoman Gushchin { 8215313bfe4SRoman Gushchin int pid = vfork(); 8225313bfe4SRoman Gushchin 8235313bfe4SRoman Gushchin if (pid == 0) 8245313bfe4SRoman Gushchin while (true) 8255313bfe4SRoman Gushchin sleep(1); 8265313bfe4SRoman Gushchin 8275313bfe4SRoman Gushchin return pid; 8285313bfe4SRoman Gushchin } 8295313bfe4SRoman Gushchin 8305313bfe4SRoman Gushchin /* 8315313bfe4SRoman Gushchin * Test that it's possible to freeze a cgroup with a process, 8325313bfe4SRoman Gushchin * which called vfork() and is waiting for a child. 8335313bfe4SRoman Gushchin */ 8345313bfe4SRoman Gushchin static int test_cgfreezer_vfork(const char *root) 8355313bfe4SRoman Gushchin { 8365313bfe4SRoman Gushchin int ret = KSFT_FAIL; 8375313bfe4SRoman Gushchin char *cgroup = NULL; 8385313bfe4SRoman Gushchin 8395313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_test_vfork"); 8405313bfe4SRoman Gushchin if (!cgroup) 8415313bfe4SRoman Gushchin goto cleanup; 8425313bfe4SRoman Gushchin 8435313bfe4SRoman Gushchin if (cg_create(cgroup)) 8445313bfe4SRoman Gushchin goto cleanup; 8455313bfe4SRoman Gushchin 8465313bfe4SRoman Gushchin cg_run_nowait(cgroup, vfork_fn, NULL); 8475313bfe4SRoman Gushchin 8485313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 2)) 8495313bfe4SRoman Gushchin goto cleanup; 8505313bfe4SRoman Gushchin 8515313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true)) 8525313bfe4SRoman Gushchin goto cleanup; 8535313bfe4SRoman Gushchin 8545313bfe4SRoman Gushchin ret = KSFT_PASS; 8555313bfe4SRoman Gushchin 8565313bfe4SRoman Gushchin cleanup: 8575313bfe4SRoman Gushchin if (cgroup) 8585313bfe4SRoman Gushchin cg_destroy(cgroup); 8595313bfe4SRoman Gushchin free(cgroup); 8605313bfe4SRoman Gushchin return ret; 8615313bfe4SRoman Gushchin } 8625313bfe4SRoman Gushchin 8635313bfe4SRoman Gushchin #define T(x) { x, #x } 8645313bfe4SRoman Gushchin struct cgfreezer_test { 8655313bfe4SRoman Gushchin int (*fn)(const char *root); 8665313bfe4SRoman Gushchin const char *name; 8675313bfe4SRoman Gushchin } tests[] = { 8685313bfe4SRoman Gushchin T(test_cgfreezer_simple), 8695313bfe4SRoman Gushchin T(test_cgfreezer_tree), 8705313bfe4SRoman Gushchin T(test_cgfreezer_forkbomb), 87144e9d308SRoman Gushchin T(test_cgfreezer_mkdir), 8725313bfe4SRoman Gushchin T(test_cgfreezer_rmdir), 8735313bfe4SRoman Gushchin T(test_cgfreezer_migrate), 8745313bfe4SRoman Gushchin T(test_cgfreezer_ptrace), 8755313bfe4SRoman Gushchin T(test_cgfreezer_stopped), 8765313bfe4SRoman Gushchin T(test_cgfreezer_ptraced), 8775313bfe4SRoman Gushchin T(test_cgfreezer_vfork), 8785313bfe4SRoman Gushchin }; 8795313bfe4SRoman Gushchin #undef T 8805313bfe4SRoman Gushchin 8815313bfe4SRoman Gushchin int main(int argc, char *argv[]) 8825313bfe4SRoman Gushchin { 8835313bfe4SRoman Gushchin char root[PATH_MAX]; 8845313bfe4SRoman Gushchin int i, ret = EXIT_SUCCESS; 8855313bfe4SRoman Gushchin 8865313bfe4SRoman Gushchin if (cg_find_unified_root(root, sizeof(root))) 8875313bfe4SRoman Gushchin ksft_exit_skip("cgroup v2 isn't mounted\n"); 8885313bfe4SRoman Gushchin for (i = 0; i < ARRAY_SIZE(tests); i++) { 8895313bfe4SRoman Gushchin switch (tests[i].fn(root)) { 8905313bfe4SRoman Gushchin case KSFT_PASS: 8915313bfe4SRoman Gushchin ksft_test_result_pass("%s\n", tests[i].name); 8925313bfe4SRoman Gushchin break; 8935313bfe4SRoman Gushchin case KSFT_SKIP: 8945313bfe4SRoman Gushchin ksft_test_result_skip("%s\n", tests[i].name); 8955313bfe4SRoman Gushchin break; 8965313bfe4SRoman Gushchin default: 8975313bfe4SRoman Gushchin ret = EXIT_FAILURE; 8985313bfe4SRoman Gushchin ksft_test_result_fail("%s\n", tests[i].name); 8995313bfe4SRoman Gushchin break; 9005313bfe4SRoman Gushchin } 9015313bfe4SRoman Gushchin } 9025313bfe4SRoman Gushchin 9035313bfe4SRoman Gushchin return ret; 9045313bfe4SRoman Gushchin } 905