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 <stdlib.h>
115313bfe4SRoman Gushchin #include <string.h>
125313bfe4SRoman Gushchin #include <sys/wait.h>
135313bfe4SRoman Gushchin
145313bfe4SRoman Gushchin #include "../kselftest.h"
155313bfe4SRoman Gushchin #include "cgroup_util.h"
165313bfe4SRoman Gushchin
175313bfe4SRoman Gushchin #define DEBUG
185313bfe4SRoman Gushchin #ifdef DEBUG
195313bfe4SRoman Gushchin #define debug(args...) fprintf(stderr, args)
205313bfe4SRoman Gushchin #else
215313bfe4SRoman Gushchin #define debug(args...)
225313bfe4SRoman Gushchin #endif
235313bfe4SRoman Gushchin
245313bfe4SRoman Gushchin /*
255313bfe4SRoman Gushchin * Check if the cgroup is frozen by looking at the cgroup.events::frozen value.
265313bfe4SRoman Gushchin */
cg_check_frozen(const char * cgroup,bool frozen)275313bfe4SRoman Gushchin static int cg_check_frozen(const char *cgroup, bool frozen)
285313bfe4SRoman Gushchin {
295313bfe4SRoman Gushchin if (frozen) {
305313bfe4SRoman Gushchin if (cg_read_strstr(cgroup, "cgroup.events", "frozen 1") != 0) {
315313bfe4SRoman Gushchin debug("Cgroup %s isn't frozen\n", cgroup);
325313bfe4SRoman Gushchin return -1;
335313bfe4SRoman Gushchin }
345313bfe4SRoman Gushchin } else {
355313bfe4SRoman Gushchin /*
365313bfe4SRoman Gushchin * Check the cgroup.events::frozen value.
375313bfe4SRoman Gushchin */
385313bfe4SRoman Gushchin if (cg_read_strstr(cgroup, "cgroup.events", "frozen 0") != 0) {
395313bfe4SRoman Gushchin debug("Cgroup %s is frozen\n", cgroup);
405313bfe4SRoman Gushchin return -1;
415313bfe4SRoman Gushchin }
425313bfe4SRoman Gushchin }
435313bfe4SRoman Gushchin
445313bfe4SRoman Gushchin return 0;
455313bfe4SRoman Gushchin }
465313bfe4SRoman Gushchin
475313bfe4SRoman Gushchin /*
485313bfe4SRoman Gushchin * Freeze the given cgroup.
495313bfe4SRoman Gushchin */
cg_freeze_nowait(const char * cgroup,bool freeze)505313bfe4SRoman Gushchin static int cg_freeze_nowait(const char *cgroup, bool freeze)
515313bfe4SRoman Gushchin {
525313bfe4SRoman Gushchin return cg_write(cgroup, "cgroup.freeze", freeze ? "1" : "0");
535313bfe4SRoman Gushchin }
545313bfe4SRoman Gushchin
555313bfe4SRoman Gushchin /*
565313bfe4SRoman Gushchin * Attach a task to the given cgroup and wait for a cgroup frozen event.
575313bfe4SRoman Gushchin * All transient events (e.g. populated) are ignored.
585313bfe4SRoman Gushchin */
cg_enter_and_wait_for_frozen(const char * cgroup,int pid,bool frozen)595313bfe4SRoman Gushchin static int cg_enter_and_wait_for_frozen(const char *cgroup, int pid,
605313bfe4SRoman Gushchin bool frozen)
615313bfe4SRoman Gushchin {
625313bfe4SRoman Gushchin int fd, ret = -1;
635313bfe4SRoman Gushchin int attempts;
645313bfe4SRoman Gushchin
655313bfe4SRoman Gushchin fd = cg_prepare_for_wait(cgroup);
665313bfe4SRoman Gushchin if (fd < 0)
675313bfe4SRoman Gushchin return fd;
685313bfe4SRoman Gushchin
695313bfe4SRoman Gushchin ret = cg_enter(cgroup, pid);
705313bfe4SRoman Gushchin if (ret)
715313bfe4SRoman Gushchin goto out;
725313bfe4SRoman Gushchin
735313bfe4SRoman Gushchin for (attempts = 0; attempts < 10; attempts++) {
745313bfe4SRoman Gushchin ret = cg_wait_for(fd);
755313bfe4SRoman Gushchin if (ret)
765313bfe4SRoman Gushchin break;
775313bfe4SRoman Gushchin
785313bfe4SRoman Gushchin ret = cg_check_frozen(cgroup, frozen);
795313bfe4SRoman Gushchin if (ret)
805313bfe4SRoman Gushchin continue;
815313bfe4SRoman Gushchin }
825313bfe4SRoman Gushchin
835313bfe4SRoman Gushchin out:
845313bfe4SRoman Gushchin close(fd);
855313bfe4SRoman Gushchin return ret;
865313bfe4SRoman Gushchin }
875313bfe4SRoman Gushchin
885313bfe4SRoman Gushchin /*
895313bfe4SRoman Gushchin * Freeze the given cgroup and wait for the inotify signal.
905313bfe4SRoman Gushchin * If there are no events in 10 seconds, treat this as an error.
915313bfe4SRoman Gushchin * Then check that the cgroup is in the desired state.
925313bfe4SRoman Gushchin */
cg_freeze_wait(const char * cgroup,bool freeze)935313bfe4SRoman Gushchin static int cg_freeze_wait(const char *cgroup, bool freeze)
945313bfe4SRoman Gushchin {
955313bfe4SRoman Gushchin int fd, ret = -1;
965313bfe4SRoman Gushchin
975313bfe4SRoman Gushchin fd = cg_prepare_for_wait(cgroup);
985313bfe4SRoman Gushchin if (fd < 0)
995313bfe4SRoman Gushchin return fd;
1005313bfe4SRoman Gushchin
1015313bfe4SRoman Gushchin ret = cg_freeze_nowait(cgroup, freeze);
1025313bfe4SRoman Gushchin if (ret) {
1035313bfe4SRoman Gushchin debug("Error: cg_freeze_nowait() failed\n");
1045313bfe4SRoman Gushchin goto out;
1055313bfe4SRoman Gushchin }
1065313bfe4SRoman Gushchin
1075313bfe4SRoman Gushchin ret = cg_wait_for(fd);
1085313bfe4SRoman Gushchin if (ret)
1095313bfe4SRoman Gushchin goto out;
1105313bfe4SRoman Gushchin
1115313bfe4SRoman Gushchin ret = cg_check_frozen(cgroup, freeze);
1125313bfe4SRoman Gushchin out:
1135313bfe4SRoman Gushchin close(fd);
1145313bfe4SRoman Gushchin return ret;
1155313bfe4SRoman Gushchin }
1165313bfe4SRoman Gushchin
1175313bfe4SRoman Gushchin /*
1185313bfe4SRoman Gushchin * A simple process running in a sleep loop until being
1195313bfe4SRoman Gushchin * re-parented.
1205313bfe4SRoman Gushchin */
child_fn(const char * cgroup,void * arg)1215313bfe4SRoman Gushchin static int child_fn(const char *cgroup, void *arg)
1225313bfe4SRoman Gushchin {
1235313bfe4SRoman Gushchin int ppid = getppid();
1245313bfe4SRoman Gushchin
1255313bfe4SRoman Gushchin while (getppid() == ppid)
1265313bfe4SRoman Gushchin usleep(1000);
1275313bfe4SRoman Gushchin
1285313bfe4SRoman Gushchin return getppid() == ppid;
1295313bfe4SRoman Gushchin }
1305313bfe4SRoman Gushchin
1315313bfe4SRoman Gushchin /*
1325313bfe4SRoman Gushchin * A simple test for the cgroup freezer: populated the cgroup with 100
1335313bfe4SRoman Gushchin * running processes and freeze it. Then unfreeze it. Then it kills all
1345313bfe4SRoman Gushchin * processes and destroys the cgroup.
1355313bfe4SRoman Gushchin */
test_cgfreezer_simple(const char * root)1365313bfe4SRoman Gushchin static int test_cgfreezer_simple(const char *root)
1375313bfe4SRoman Gushchin {
1385313bfe4SRoman Gushchin int ret = KSFT_FAIL;
1395313bfe4SRoman Gushchin char *cgroup = NULL;
1405313bfe4SRoman Gushchin int i;
1415313bfe4SRoman Gushchin
1425313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_test_simple");
1435313bfe4SRoman Gushchin if (!cgroup)
1445313bfe4SRoman Gushchin goto cleanup;
1455313bfe4SRoman Gushchin
1465313bfe4SRoman Gushchin if (cg_create(cgroup))
1475313bfe4SRoman Gushchin goto cleanup;
1485313bfe4SRoman Gushchin
1495313bfe4SRoman Gushchin for (i = 0; i < 100; i++)
1505313bfe4SRoman Gushchin cg_run_nowait(cgroup, child_fn, NULL);
1515313bfe4SRoman Gushchin
1525313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 100))
1535313bfe4SRoman Gushchin goto cleanup;
1545313bfe4SRoman Gushchin
1555313bfe4SRoman Gushchin if (cg_check_frozen(cgroup, false))
1565313bfe4SRoman Gushchin goto cleanup;
1575313bfe4SRoman Gushchin
1585313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true))
1595313bfe4SRoman Gushchin goto cleanup;
1605313bfe4SRoman Gushchin
1615313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, false))
1625313bfe4SRoman Gushchin goto cleanup;
1635313bfe4SRoman Gushchin
1645313bfe4SRoman Gushchin ret = KSFT_PASS;
1655313bfe4SRoman Gushchin
1665313bfe4SRoman Gushchin cleanup:
1675313bfe4SRoman Gushchin if (cgroup)
1685313bfe4SRoman Gushchin cg_destroy(cgroup);
1695313bfe4SRoman Gushchin free(cgroup);
1705313bfe4SRoman Gushchin return ret;
1715313bfe4SRoman Gushchin }
1725313bfe4SRoman Gushchin
1735313bfe4SRoman Gushchin /*
1745313bfe4SRoman Gushchin * The test creates the following hierarchy:
1755313bfe4SRoman Gushchin * A
1765313bfe4SRoman Gushchin * / / \ \
1775313bfe4SRoman Gushchin * B E I K
1785313bfe4SRoman Gushchin * /\ |
1795313bfe4SRoman Gushchin * C D F
1805313bfe4SRoman Gushchin * |
1815313bfe4SRoman Gushchin * G
1825313bfe4SRoman Gushchin * |
1835313bfe4SRoman Gushchin * H
1845313bfe4SRoman Gushchin *
1855313bfe4SRoman Gushchin * with a process in C, H and 3 processes in K.
1865313bfe4SRoman Gushchin * Then it tries to freeze and unfreeze the whole tree.
1875313bfe4SRoman Gushchin */
test_cgfreezer_tree(const char * root)1885313bfe4SRoman Gushchin static int test_cgfreezer_tree(const char *root)
1895313bfe4SRoman Gushchin {
1905313bfe4SRoman Gushchin char *cgroup[10] = {0};
1915313bfe4SRoman Gushchin int ret = KSFT_FAIL;
1925313bfe4SRoman Gushchin int i;
1935313bfe4SRoman Gushchin
1945313bfe4SRoman Gushchin cgroup[0] = cg_name(root, "cg_test_tree_A");
1955313bfe4SRoman Gushchin if (!cgroup[0])
1965313bfe4SRoman Gushchin goto cleanup;
1975313bfe4SRoman Gushchin
1985313bfe4SRoman Gushchin cgroup[1] = cg_name(cgroup[0], "B");
1995313bfe4SRoman Gushchin if (!cgroup[1])
2005313bfe4SRoman Gushchin goto cleanup;
2015313bfe4SRoman Gushchin
2025313bfe4SRoman Gushchin cgroup[2] = cg_name(cgroup[1], "C");
2035313bfe4SRoman Gushchin if (!cgroup[2])
2045313bfe4SRoman Gushchin goto cleanup;
2055313bfe4SRoman Gushchin
2065313bfe4SRoman Gushchin cgroup[3] = cg_name(cgroup[1], "D");
2075313bfe4SRoman Gushchin if (!cgroup[3])
2085313bfe4SRoman Gushchin goto cleanup;
2095313bfe4SRoman Gushchin
2105313bfe4SRoman Gushchin cgroup[4] = cg_name(cgroup[0], "E");
2115313bfe4SRoman Gushchin if (!cgroup[4])
2125313bfe4SRoman Gushchin goto cleanup;
2135313bfe4SRoman Gushchin
2145313bfe4SRoman Gushchin cgroup[5] = cg_name(cgroup[4], "F");
2155313bfe4SRoman Gushchin if (!cgroup[5])
2165313bfe4SRoman Gushchin goto cleanup;
2175313bfe4SRoman Gushchin
2185313bfe4SRoman Gushchin cgroup[6] = cg_name(cgroup[5], "G");
2195313bfe4SRoman Gushchin if (!cgroup[6])
2205313bfe4SRoman Gushchin goto cleanup;
2215313bfe4SRoman Gushchin
2225313bfe4SRoman Gushchin cgroup[7] = cg_name(cgroup[6], "H");
2235313bfe4SRoman Gushchin if (!cgroup[7])
2245313bfe4SRoman Gushchin goto cleanup;
2255313bfe4SRoman Gushchin
2265313bfe4SRoman Gushchin cgroup[8] = cg_name(cgroup[0], "I");
2275313bfe4SRoman Gushchin if (!cgroup[8])
2285313bfe4SRoman Gushchin goto cleanup;
2295313bfe4SRoman Gushchin
2305313bfe4SRoman Gushchin cgroup[9] = cg_name(cgroup[0], "K");
2315313bfe4SRoman Gushchin if (!cgroup[9])
2325313bfe4SRoman Gushchin goto cleanup;
2335313bfe4SRoman Gushchin
2345313bfe4SRoman Gushchin for (i = 0; i < 10; i++)
2355313bfe4SRoman Gushchin if (cg_create(cgroup[i]))
2365313bfe4SRoman Gushchin goto cleanup;
2375313bfe4SRoman Gushchin
2385313bfe4SRoman Gushchin cg_run_nowait(cgroup[2], child_fn, NULL);
2395313bfe4SRoman Gushchin cg_run_nowait(cgroup[7], child_fn, NULL);
2405313bfe4SRoman Gushchin cg_run_nowait(cgroup[9], child_fn, NULL);
2415313bfe4SRoman Gushchin cg_run_nowait(cgroup[9], child_fn, NULL);
2425313bfe4SRoman Gushchin cg_run_nowait(cgroup[9], child_fn, NULL);
2435313bfe4SRoman Gushchin
2445313bfe4SRoman Gushchin /*
2455313bfe4SRoman Gushchin * Wait until all child processes will enter
2465313bfe4SRoman Gushchin * corresponding cgroups.
2475313bfe4SRoman Gushchin */
2485313bfe4SRoman Gushchin
2495313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup[2], 1) ||
2505313bfe4SRoman Gushchin cg_wait_for_proc_count(cgroup[7], 1) ||
2515313bfe4SRoman Gushchin cg_wait_for_proc_count(cgroup[9], 3))
2525313bfe4SRoman Gushchin goto cleanup;
2535313bfe4SRoman Gushchin
2545313bfe4SRoman Gushchin /*
2555313bfe4SRoman Gushchin * Freeze B.
2565313bfe4SRoman Gushchin */
2575313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[1], true))
2585313bfe4SRoman Gushchin goto cleanup;
2595313bfe4SRoman Gushchin
2605313bfe4SRoman Gushchin /*
2615313bfe4SRoman Gushchin * Freeze F.
2625313bfe4SRoman Gushchin */
2635313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[5], true))
2645313bfe4SRoman Gushchin goto cleanup;
2655313bfe4SRoman Gushchin
2665313bfe4SRoman Gushchin /*
2675313bfe4SRoman Gushchin * Freeze G.
2685313bfe4SRoman Gushchin */
2695313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[6], true))
2705313bfe4SRoman Gushchin goto cleanup;
2715313bfe4SRoman Gushchin
2725313bfe4SRoman Gushchin /*
2735313bfe4SRoman Gushchin * Check that A and E are not frozen.
2745313bfe4SRoman Gushchin */
2755313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[0], false))
2765313bfe4SRoman Gushchin goto cleanup;
2775313bfe4SRoman Gushchin
2785313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[4], false))
2795313bfe4SRoman Gushchin goto cleanup;
2805313bfe4SRoman Gushchin
2815313bfe4SRoman Gushchin /*
2825313bfe4SRoman Gushchin * Freeze A. Check that A, B and E are frozen.
2835313bfe4SRoman Gushchin */
2845313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[0], true))
2855313bfe4SRoman Gushchin goto cleanup;
2865313bfe4SRoman Gushchin
2875313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[1], true))
2885313bfe4SRoman Gushchin goto cleanup;
2895313bfe4SRoman Gushchin
2905313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[4], true))
2915313bfe4SRoman Gushchin goto cleanup;
2925313bfe4SRoman Gushchin
2935313bfe4SRoman Gushchin /*
2945313bfe4SRoman Gushchin * Unfreeze B, F and G
2955313bfe4SRoman Gushchin */
2965313bfe4SRoman Gushchin if (cg_freeze_nowait(cgroup[1], false))
2975313bfe4SRoman Gushchin goto cleanup;
2985313bfe4SRoman Gushchin
2995313bfe4SRoman Gushchin if (cg_freeze_nowait(cgroup[5], false))
3005313bfe4SRoman Gushchin goto cleanup;
3015313bfe4SRoman Gushchin
3025313bfe4SRoman Gushchin if (cg_freeze_nowait(cgroup[6], false))
3035313bfe4SRoman Gushchin goto cleanup;
3045313bfe4SRoman Gushchin
3055313bfe4SRoman Gushchin /*
3065313bfe4SRoman Gushchin * Check that C and H are still frozen.
3075313bfe4SRoman Gushchin */
3085313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[2], true))
3095313bfe4SRoman Gushchin goto cleanup;
3105313bfe4SRoman Gushchin
3115313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[7], true))
3125313bfe4SRoman Gushchin goto cleanup;
3135313bfe4SRoman Gushchin
3145313bfe4SRoman Gushchin /*
3155313bfe4SRoman Gushchin * Unfreeze A. Check that A, C and K are not frozen.
3165313bfe4SRoman Gushchin */
3175313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[0], false))
3185313bfe4SRoman Gushchin goto cleanup;
3195313bfe4SRoman Gushchin
3205313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[2], false))
3215313bfe4SRoman Gushchin goto cleanup;
3225313bfe4SRoman Gushchin
3235313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[9], false))
3245313bfe4SRoman Gushchin goto cleanup;
3255313bfe4SRoman Gushchin
3265313bfe4SRoman Gushchin ret = KSFT_PASS;
3275313bfe4SRoman Gushchin
3285313bfe4SRoman Gushchin cleanup:
3295313bfe4SRoman Gushchin for (i = 9; i >= 0 && cgroup[i]; i--) {
3305313bfe4SRoman Gushchin cg_destroy(cgroup[i]);
3315313bfe4SRoman Gushchin free(cgroup[i]);
3325313bfe4SRoman Gushchin }
3335313bfe4SRoman Gushchin
3345313bfe4SRoman Gushchin return ret;
3355313bfe4SRoman Gushchin }
3365313bfe4SRoman Gushchin
3375313bfe4SRoman Gushchin /*
3385313bfe4SRoman Gushchin * A fork bomb emulator.
3395313bfe4SRoman Gushchin */
forkbomb_fn(const char * cgroup,void * arg)3405313bfe4SRoman Gushchin static int forkbomb_fn(const char *cgroup, void *arg)
3415313bfe4SRoman Gushchin {
3425313bfe4SRoman Gushchin int ppid;
3435313bfe4SRoman Gushchin
3445313bfe4SRoman Gushchin fork();
3455313bfe4SRoman Gushchin fork();
3465313bfe4SRoman Gushchin
3475313bfe4SRoman Gushchin ppid = getppid();
3485313bfe4SRoman Gushchin
3495313bfe4SRoman Gushchin while (getppid() == ppid)
3505313bfe4SRoman Gushchin usleep(1000);
3515313bfe4SRoman Gushchin
3525313bfe4SRoman Gushchin return getppid() == ppid;
3535313bfe4SRoman Gushchin }
3545313bfe4SRoman Gushchin
3555313bfe4SRoman Gushchin /*
3565313bfe4SRoman Gushchin * The test runs a fork bomb in a cgroup and tries to freeze it.
3575313bfe4SRoman Gushchin * Then it kills all processes and checks that cgroup isn't populated
3585313bfe4SRoman Gushchin * anymore.
3595313bfe4SRoman Gushchin */
test_cgfreezer_forkbomb(const char * root)3605313bfe4SRoman Gushchin static int test_cgfreezer_forkbomb(const char *root)
3615313bfe4SRoman Gushchin {
3625313bfe4SRoman Gushchin int ret = KSFT_FAIL;
3635313bfe4SRoman Gushchin char *cgroup = NULL;
3645313bfe4SRoman Gushchin
3655313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_forkbomb_test");
3665313bfe4SRoman Gushchin if (!cgroup)
3675313bfe4SRoman Gushchin goto cleanup;
3685313bfe4SRoman Gushchin
3695313bfe4SRoman Gushchin if (cg_create(cgroup))
3705313bfe4SRoman Gushchin goto cleanup;
3715313bfe4SRoman Gushchin
3725313bfe4SRoman Gushchin cg_run_nowait(cgroup, forkbomb_fn, NULL);
3735313bfe4SRoman Gushchin
3745313bfe4SRoman Gushchin usleep(100000);
3755313bfe4SRoman Gushchin
3765313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true))
3775313bfe4SRoman Gushchin goto cleanup;
3785313bfe4SRoman Gushchin
3795313bfe4SRoman Gushchin if (cg_killall(cgroup))
3805313bfe4SRoman Gushchin goto cleanup;
3815313bfe4SRoman Gushchin
3825313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 0))
3835313bfe4SRoman Gushchin goto cleanup;
3845313bfe4SRoman Gushchin
3855313bfe4SRoman Gushchin ret = KSFT_PASS;
3865313bfe4SRoman Gushchin
3875313bfe4SRoman Gushchin cleanup:
3885313bfe4SRoman Gushchin if (cgroup)
3895313bfe4SRoman Gushchin cg_destroy(cgroup);
3905313bfe4SRoman Gushchin free(cgroup);
3915313bfe4SRoman Gushchin return ret;
3925313bfe4SRoman Gushchin }
3935313bfe4SRoman Gushchin
3945313bfe4SRoman Gushchin /*
39544e9d308SRoman Gushchin * The test creates a cgroups and freezes it. Then it creates a child cgroup
39644e9d308SRoman Gushchin * and populates it with a task. After that it checks that the child cgroup
39744e9d308SRoman Gushchin * is frozen and the parent cgroup remains frozen too.
39844e9d308SRoman Gushchin */
test_cgfreezer_mkdir(const char * root)39944e9d308SRoman Gushchin static int test_cgfreezer_mkdir(const char *root)
40044e9d308SRoman Gushchin {
40144e9d308SRoman Gushchin int ret = KSFT_FAIL;
40244e9d308SRoman Gushchin char *parent, *child = NULL;
40344e9d308SRoman Gushchin int pid;
40444e9d308SRoman Gushchin
40544e9d308SRoman Gushchin parent = cg_name(root, "cg_test_mkdir_A");
40644e9d308SRoman Gushchin if (!parent)
40744e9d308SRoman Gushchin goto cleanup;
40844e9d308SRoman Gushchin
40944e9d308SRoman Gushchin child = cg_name(parent, "cg_test_mkdir_B");
41044e9d308SRoman Gushchin if (!child)
41144e9d308SRoman Gushchin goto cleanup;
41244e9d308SRoman Gushchin
41344e9d308SRoman Gushchin if (cg_create(parent))
41444e9d308SRoman Gushchin goto cleanup;
41544e9d308SRoman Gushchin
41644e9d308SRoman Gushchin if (cg_freeze_wait(parent, true))
41744e9d308SRoman Gushchin goto cleanup;
41844e9d308SRoman Gushchin
41944e9d308SRoman Gushchin if (cg_create(child))
42044e9d308SRoman Gushchin goto cleanup;
42144e9d308SRoman Gushchin
42244e9d308SRoman Gushchin pid = cg_run_nowait(child, child_fn, NULL);
42344e9d308SRoman Gushchin if (pid < 0)
42444e9d308SRoman Gushchin goto cleanup;
42544e9d308SRoman Gushchin
42644e9d308SRoman Gushchin if (cg_wait_for_proc_count(child, 1))
42744e9d308SRoman Gushchin goto cleanup;
42844e9d308SRoman Gushchin
42944e9d308SRoman Gushchin if (cg_check_frozen(child, true))
43044e9d308SRoman Gushchin goto cleanup;
43144e9d308SRoman Gushchin
43244e9d308SRoman Gushchin if (cg_check_frozen(parent, true))
43344e9d308SRoman Gushchin goto cleanup;
43444e9d308SRoman Gushchin
43544e9d308SRoman Gushchin ret = KSFT_PASS;
43644e9d308SRoman Gushchin
43744e9d308SRoman Gushchin cleanup:
43844e9d308SRoman Gushchin if (child)
43944e9d308SRoman Gushchin cg_destroy(child);
44044e9d308SRoman Gushchin free(child);
44144e9d308SRoman Gushchin if (parent)
44244e9d308SRoman Gushchin cg_destroy(parent);
44344e9d308SRoman Gushchin free(parent);
44444e9d308SRoman Gushchin return ret;
44544e9d308SRoman Gushchin }
44644e9d308SRoman Gushchin
44744e9d308SRoman Gushchin /*
4485313bfe4SRoman Gushchin * The test creates two nested cgroups, freezes the parent
4495313bfe4SRoman Gushchin * and removes the child. Then it checks that the parent cgroup
4505313bfe4SRoman Gushchin * remains frozen and it's possible to create a new child
4515313bfe4SRoman Gushchin * without unfreezing. The new child is frozen too.
4525313bfe4SRoman Gushchin */
test_cgfreezer_rmdir(const char * root)4535313bfe4SRoman Gushchin static int test_cgfreezer_rmdir(const char *root)
4545313bfe4SRoman Gushchin {
4555313bfe4SRoman Gushchin int ret = KSFT_FAIL;
4565313bfe4SRoman Gushchin char *parent, *child = NULL;
4575313bfe4SRoman Gushchin
4585313bfe4SRoman Gushchin parent = cg_name(root, "cg_test_rmdir_A");
4595313bfe4SRoman Gushchin if (!parent)
4605313bfe4SRoman Gushchin goto cleanup;
4615313bfe4SRoman Gushchin
4625313bfe4SRoman Gushchin child = cg_name(parent, "cg_test_rmdir_B");
4635313bfe4SRoman Gushchin if (!child)
4645313bfe4SRoman Gushchin goto cleanup;
4655313bfe4SRoman Gushchin
4665313bfe4SRoman Gushchin if (cg_create(parent))
4675313bfe4SRoman Gushchin goto cleanup;
4685313bfe4SRoman Gushchin
4695313bfe4SRoman Gushchin if (cg_create(child))
4705313bfe4SRoman Gushchin goto cleanup;
4715313bfe4SRoman Gushchin
4725313bfe4SRoman Gushchin if (cg_freeze_wait(parent, true))
4735313bfe4SRoman Gushchin goto cleanup;
4745313bfe4SRoman Gushchin
4755313bfe4SRoman Gushchin if (cg_destroy(child))
4765313bfe4SRoman Gushchin goto cleanup;
4775313bfe4SRoman Gushchin
4785313bfe4SRoman Gushchin if (cg_check_frozen(parent, true))
4795313bfe4SRoman Gushchin goto cleanup;
4805313bfe4SRoman Gushchin
4815313bfe4SRoman Gushchin if (cg_create(child))
4825313bfe4SRoman Gushchin goto cleanup;
4835313bfe4SRoman Gushchin
4845313bfe4SRoman Gushchin if (cg_check_frozen(child, true))
4855313bfe4SRoman Gushchin goto cleanup;
4865313bfe4SRoman Gushchin
4875313bfe4SRoman Gushchin ret = KSFT_PASS;
4885313bfe4SRoman Gushchin
4895313bfe4SRoman Gushchin cleanup:
4905313bfe4SRoman Gushchin if (child)
4915313bfe4SRoman Gushchin cg_destroy(child);
4925313bfe4SRoman Gushchin free(child);
4935313bfe4SRoman Gushchin if (parent)
4945313bfe4SRoman Gushchin cg_destroy(parent);
4955313bfe4SRoman Gushchin free(parent);
4965313bfe4SRoman Gushchin return ret;
4975313bfe4SRoman Gushchin }
4985313bfe4SRoman Gushchin
4995313bfe4SRoman Gushchin /*
5005313bfe4SRoman Gushchin * The test creates two cgroups: A and B, runs a process in A
5015313bfe4SRoman Gushchin * and performs several migrations:
5025313bfe4SRoman Gushchin * 1) A (running) -> B (frozen)
5035313bfe4SRoman Gushchin * 2) B (frozen) -> A (running)
5045313bfe4SRoman Gushchin * 3) A (frozen) -> B (frozen)
5055313bfe4SRoman Gushchin *
5065313bfe4SRoman Gushchin * On each step it checks the actual state of both cgroups.
5075313bfe4SRoman Gushchin */
test_cgfreezer_migrate(const char * root)5085313bfe4SRoman Gushchin static int test_cgfreezer_migrate(const char *root)
5095313bfe4SRoman Gushchin {
5105313bfe4SRoman Gushchin int ret = KSFT_FAIL;
5115313bfe4SRoman Gushchin char *cgroup[2] = {0};
5125313bfe4SRoman Gushchin int pid;
5135313bfe4SRoman Gushchin
5145313bfe4SRoman Gushchin cgroup[0] = cg_name(root, "cg_test_migrate_A");
5155313bfe4SRoman Gushchin if (!cgroup[0])
5165313bfe4SRoman Gushchin goto cleanup;
5175313bfe4SRoman Gushchin
5185313bfe4SRoman Gushchin cgroup[1] = cg_name(root, "cg_test_migrate_B");
5195313bfe4SRoman Gushchin if (!cgroup[1])
5205313bfe4SRoman Gushchin goto cleanup;
5215313bfe4SRoman Gushchin
5225313bfe4SRoman Gushchin if (cg_create(cgroup[0]))
5235313bfe4SRoman Gushchin goto cleanup;
5245313bfe4SRoman Gushchin
5255313bfe4SRoman Gushchin if (cg_create(cgroup[1]))
5265313bfe4SRoman Gushchin goto cleanup;
5275313bfe4SRoman Gushchin
5285313bfe4SRoman Gushchin pid = cg_run_nowait(cgroup[0], child_fn, NULL);
5295313bfe4SRoman Gushchin if (pid < 0)
5305313bfe4SRoman Gushchin goto cleanup;
5315313bfe4SRoman Gushchin
5325313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup[0], 1))
5335313bfe4SRoman Gushchin goto cleanup;
5345313bfe4SRoman Gushchin
5355313bfe4SRoman Gushchin /*
5365313bfe4SRoman Gushchin * Migrate from A (running) to B (frozen)
5375313bfe4SRoman Gushchin */
5385313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[1], true))
5395313bfe4SRoman Gushchin goto cleanup;
5405313bfe4SRoman Gushchin
5415313bfe4SRoman Gushchin if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true))
5425313bfe4SRoman Gushchin goto cleanup;
5435313bfe4SRoman Gushchin
5445313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[0], false))
5455313bfe4SRoman Gushchin goto cleanup;
5465313bfe4SRoman Gushchin
5475313bfe4SRoman Gushchin /*
5485313bfe4SRoman Gushchin * Migrate from B (frozen) to A (running)
5495313bfe4SRoman Gushchin */
5505313bfe4SRoman Gushchin if (cg_enter_and_wait_for_frozen(cgroup[0], pid, false))
5515313bfe4SRoman Gushchin goto cleanup;
5525313bfe4SRoman Gushchin
5535313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[1], true))
5545313bfe4SRoman Gushchin goto cleanup;
5555313bfe4SRoman Gushchin
5565313bfe4SRoman Gushchin /*
5575313bfe4SRoman Gushchin * Migrate from A (frozen) to B (frozen)
5585313bfe4SRoman Gushchin */
5595313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup[0], true))
5605313bfe4SRoman Gushchin goto cleanup;
5615313bfe4SRoman Gushchin
5625313bfe4SRoman Gushchin if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true))
5635313bfe4SRoman Gushchin goto cleanup;
5645313bfe4SRoman Gushchin
5655313bfe4SRoman Gushchin if (cg_check_frozen(cgroup[0], true))
5665313bfe4SRoman Gushchin goto cleanup;
5675313bfe4SRoman Gushchin
5685313bfe4SRoman Gushchin ret = KSFT_PASS;
5695313bfe4SRoman Gushchin
5705313bfe4SRoman Gushchin cleanup:
5715313bfe4SRoman Gushchin if (cgroup[0])
5725313bfe4SRoman Gushchin cg_destroy(cgroup[0]);
5735313bfe4SRoman Gushchin free(cgroup[0]);
5745313bfe4SRoman Gushchin if (cgroup[1])
5755313bfe4SRoman Gushchin cg_destroy(cgroup[1]);
5765313bfe4SRoman Gushchin free(cgroup[1]);
5775313bfe4SRoman Gushchin return ret;
5785313bfe4SRoman Gushchin }
5795313bfe4SRoman Gushchin
5805313bfe4SRoman Gushchin /*
5815313bfe4SRoman Gushchin * The test checks that ptrace works with a tracing process in a frozen cgroup.
5825313bfe4SRoman Gushchin */
test_cgfreezer_ptrace(const char * root)5835313bfe4SRoman Gushchin static int test_cgfreezer_ptrace(const char *root)
5845313bfe4SRoman Gushchin {
5855313bfe4SRoman Gushchin int ret = KSFT_FAIL;
5865313bfe4SRoman Gushchin char *cgroup = NULL;
5875313bfe4SRoman Gushchin siginfo_t siginfo;
5885313bfe4SRoman Gushchin int pid;
5895313bfe4SRoman Gushchin
5905313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_test_ptrace");
5915313bfe4SRoman Gushchin if (!cgroup)
5925313bfe4SRoman Gushchin goto cleanup;
5935313bfe4SRoman Gushchin
5945313bfe4SRoman Gushchin if (cg_create(cgroup))
5955313bfe4SRoman Gushchin goto cleanup;
5965313bfe4SRoman Gushchin
5975313bfe4SRoman Gushchin pid = cg_run_nowait(cgroup, child_fn, NULL);
5985313bfe4SRoman Gushchin if (pid < 0)
5995313bfe4SRoman Gushchin goto cleanup;
6005313bfe4SRoman Gushchin
6015313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 1))
6025313bfe4SRoman Gushchin goto cleanup;
6035313bfe4SRoman Gushchin
6045313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true))
6055313bfe4SRoman Gushchin goto cleanup;
6065313bfe4SRoman Gushchin
6075313bfe4SRoman Gushchin if (ptrace(PTRACE_SEIZE, pid, NULL, NULL))
6085313bfe4SRoman Gushchin goto cleanup;
6095313bfe4SRoman Gushchin
6105313bfe4SRoman Gushchin if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL))
6115313bfe4SRoman Gushchin goto cleanup;
6125313bfe4SRoman Gushchin
6135313bfe4SRoman Gushchin waitpid(pid, NULL, 0);
6145313bfe4SRoman Gushchin
6155313bfe4SRoman Gushchin /*
6165313bfe4SRoman Gushchin * Cgroup has to remain frozen, however the test task
6175313bfe4SRoman Gushchin * is in traced state.
6185313bfe4SRoman Gushchin */
6195313bfe4SRoman Gushchin if (cg_check_frozen(cgroup, true))
6205313bfe4SRoman Gushchin goto cleanup;
6215313bfe4SRoman Gushchin
6225313bfe4SRoman Gushchin if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo))
6235313bfe4SRoman Gushchin goto cleanup;
6245313bfe4SRoman Gushchin
6255313bfe4SRoman Gushchin if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
6265313bfe4SRoman Gushchin goto cleanup;
6275313bfe4SRoman Gushchin
6285313bfe4SRoman Gushchin if (cg_check_frozen(cgroup, true))
6295313bfe4SRoman Gushchin goto cleanup;
6305313bfe4SRoman Gushchin
6315313bfe4SRoman Gushchin ret = KSFT_PASS;
6325313bfe4SRoman Gushchin
6335313bfe4SRoman Gushchin cleanup:
6345313bfe4SRoman Gushchin if (cgroup)
6355313bfe4SRoman Gushchin cg_destroy(cgroup);
6365313bfe4SRoman Gushchin free(cgroup);
6375313bfe4SRoman Gushchin return ret;
6385313bfe4SRoman Gushchin }
6395313bfe4SRoman Gushchin
6405313bfe4SRoman Gushchin /*
6415313bfe4SRoman Gushchin * Check if the process is stopped.
6425313bfe4SRoman Gushchin */
proc_check_stopped(int pid)6435313bfe4SRoman Gushchin static int proc_check_stopped(int pid)
6445313bfe4SRoman Gushchin {
6455313bfe4SRoman Gushchin char buf[PAGE_SIZE];
6465313bfe4SRoman Gushchin int len;
6475313bfe4SRoman Gushchin
64858c9f75bSMichal Koutný len = proc_read_text(pid, 0, "stat", buf, sizeof(buf));
6495313bfe4SRoman Gushchin if (len == -1) {
6505313bfe4SRoman Gushchin debug("Can't get %d stat\n", pid);
6515313bfe4SRoman Gushchin return -1;
6525313bfe4SRoman Gushchin }
6535313bfe4SRoman Gushchin
6545313bfe4SRoman Gushchin if (strstr(buf, "(test_freezer) T ") == NULL) {
6555313bfe4SRoman Gushchin debug("Process %d in the unexpected state: %s\n", pid, buf);
6565313bfe4SRoman Gushchin return -1;
6575313bfe4SRoman Gushchin }
6585313bfe4SRoman Gushchin
6595313bfe4SRoman Gushchin return 0;
6605313bfe4SRoman Gushchin }
6615313bfe4SRoman Gushchin
6625313bfe4SRoman Gushchin /*
6635313bfe4SRoman Gushchin * Test that it's possible to freeze a cgroup with a stopped process.
6645313bfe4SRoman Gushchin */
test_cgfreezer_stopped(const char * root)6655313bfe4SRoman Gushchin static int test_cgfreezer_stopped(const char *root)
6665313bfe4SRoman Gushchin {
6675313bfe4SRoman Gushchin int pid, ret = KSFT_FAIL;
6685313bfe4SRoman Gushchin char *cgroup = NULL;
6695313bfe4SRoman Gushchin
6705313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_test_stopped");
6715313bfe4SRoman Gushchin if (!cgroup)
6725313bfe4SRoman Gushchin goto cleanup;
6735313bfe4SRoman Gushchin
6745313bfe4SRoman Gushchin if (cg_create(cgroup))
6755313bfe4SRoman Gushchin goto cleanup;
6765313bfe4SRoman Gushchin
6775313bfe4SRoman Gushchin pid = cg_run_nowait(cgroup, child_fn, NULL);
6785313bfe4SRoman Gushchin
6795313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 1))
6805313bfe4SRoman Gushchin goto cleanup;
6815313bfe4SRoman Gushchin
6825313bfe4SRoman Gushchin if (kill(pid, SIGSTOP))
6835313bfe4SRoman Gushchin goto cleanup;
6845313bfe4SRoman Gushchin
6855313bfe4SRoman Gushchin if (cg_check_frozen(cgroup, false))
6865313bfe4SRoman Gushchin goto cleanup;
6875313bfe4SRoman Gushchin
6885313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true))
6895313bfe4SRoman Gushchin goto cleanup;
6905313bfe4SRoman Gushchin
6915313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, false))
6925313bfe4SRoman Gushchin goto cleanup;
6935313bfe4SRoman Gushchin
6945313bfe4SRoman Gushchin if (proc_check_stopped(pid))
6955313bfe4SRoman Gushchin goto cleanup;
6965313bfe4SRoman Gushchin
6975313bfe4SRoman Gushchin ret = KSFT_PASS;
6985313bfe4SRoman Gushchin
6995313bfe4SRoman Gushchin cleanup:
7005313bfe4SRoman Gushchin if (cgroup)
7015313bfe4SRoman Gushchin cg_destroy(cgroup);
7025313bfe4SRoman Gushchin free(cgroup);
7035313bfe4SRoman Gushchin return ret;
7045313bfe4SRoman Gushchin }
7055313bfe4SRoman Gushchin
7065313bfe4SRoman Gushchin /*
7075313bfe4SRoman Gushchin * Test that it's possible to freeze a cgroup with a ptraced process.
7085313bfe4SRoman Gushchin */
test_cgfreezer_ptraced(const char * root)7095313bfe4SRoman Gushchin static int test_cgfreezer_ptraced(const char *root)
7105313bfe4SRoman Gushchin {
7115313bfe4SRoman Gushchin int pid, ret = KSFT_FAIL;
7125313bfe4SRoman Gushchin char *cgroup = NULL;
7135313bfe4SRoman Gushchin siginfo_t siginfo;
7145313bfe4SRoman Gushchin
7155313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_test_ptraced");
7165313bfe4SRoman Gushchin if (!cgroup)
7175313bfe4SRoman Gushchin goto cleanup;
7185313bfe4SRoman Gushchin
7195313bfe4SRoman Gushchin if (cg_create(cgroup))
7205313bfe4SRoman Gushchin goto cleanup;
7215313bfe4SRoman Gushchin
7225313bfe4SRoman Gushchin pid = cg_run_nowait(cgroup, child_fn, NULL);
7235313bfe4SRoman Gushchin
7245313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 1))
7255313bfe4SRoman Gushchin goto cleanup;
7265313bfe4SRoman Gushchin
7275313bfe4SRoman Gushchin if (ptrace(PTRACE_SEIZE, pid, NULL, NULL))
7285313bfe4SRoman Gushchin goto cleanup;
7295313bfe4SRoman Gushchin
7305313bfe4SRoman Gushchin if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL))
7315313bfe4SRoman Gushchin goto cleanup;
7325313bfe4SRoman Gushchin
7335313bfe4SRoman Gushchin waitpid(pid, NULL, 0);
7345313bfe4SRoman Gushchin
7355313bfe4SRoman Gushchin if (cg_check_frozen(cgroup, false))
7365313bfe4SRoman Gushchin goto cleanup;
7375313bfe4SRoman Gushchin
7385313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true))
7395313bfe4SRoman Gushchin goto cleanup;
7405313bfe4SRoman Gushchin
7415313bfe4SRoman Gushchin /*
7425313bfe4SRoman Gushchin * cg_check_frozen(cgroup, true) will fail here,
7435313bfe4SRoman Gushchin * because the task in in the TRACEd state.
7445313bfe4SRoman Gushchin */
7455313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, false))
7465313bfe4SRoman Gushchin goto cleanup;
7475313bfe4SRoman Gushchin
7485313bfe4SRoman Gushchin if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo))
7495313bfe4SRoman Gushchin goto cleanup;
7505313bfe4SRoman Gushchin
7515313bfe4SRoman Gushchin if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
7525313bfe4SRoman Gushchin goto cleanup;
7535313bfe4SRoman Gushchin
7545313bfe4SRoman Gushchin ret = KSFT_PASS;
7555313bfe4SRoman Gushchin
7565313bfe4SRoman Gushchin cleanup:
7575313bfe4SRoman Gushchin if (cgroup)
7585313bfe4SRoman Gushchin cg_destroy(cgroup);
7595313bfe4SRoman Gushchin free(cgroup);
7605313bfe4SRoman Gushchin return ret;
7615313bfe4SRoman Gushchin }
7625313bfe4SRoman Gushchin
vfork_fn(const char * cgroup,void * arg)7635313bfe4SRoman Gushchin static int vfork_fn(const char *cgroup, void *arg)
7645313bfe4SRoman Gushchin {
7655313bfe4SRoman Gushchin int pid = vfork();
7665313bfe4SRoman Gushchin
7675313bfe4SRoman Gushchin if (pid == 0)
7685313bfe4SRoman Gushchin while (true)
7695313bfe4SRoman Gushchin sleep(1);
7705313bfe4SRoman Gushchin
7715313bfe4SRoman Gushchin return pid;
7725313bfe4SRoman Gushchin }
7735313bfe4SRoman Gushchin
7745313bfe4SRoman Gushchin /*
7755313bfe4SRoman Gushchin * Test that it's possible to freeze a cgroup with a process,
7765313bfe4SRoman Gushchin * which called vfork() and is waiting for a child.
7775313bfe4SRoman Gushchin */
test_cgfreezer_vfork(const char * root)7785313bfe4SRoman Gushchin static int test_cgfreezer_vfork(const char *root)
7795313bfe4SRoman Gushchin {
7805313bfe4SRoman Gushchin int ret = KSFT_FAIL;
7815313bfe4SRoman Gushchin char *cgroup = NULL;
7825313bfe4SRoman Gushchin
7835313bfe4SRoman Gushchin cgroup = cg_name(root, "cg_test_vfork");
7845313bfe4SRoman Gushchin if (!cgroup)
7855313bfe4SRoman Gushchin goto cleanup;
7865313bfe4SRoman Gushchin
7875313bfe4SRoman Gushchin if (cg_create(cgroup))
7885313bfe4SRoman Gushchin goto cleanup;
7895313bfe4SRoman Gushchin
7905313bfe4SRoman Gushchin cg_run_nowait(cgroup, vfork_fn, NULL);
7915313bfe4SRoman Gushchin
7925313bfe4SRoman Gushchin if (cg_wait_for_proc_count(cgroup, 2))
7935313bfe4SRoman Gushchin goto cleanup;
7945313bfe4SRoman Gushchin
7955313bfe4SRoman Gushchin if (cg_freeze_wait(cgroup, true))
7965313bfe4SRoman Gushchin goto cleanup;
7975313bfe4SRoman Gushchin
7985313bfe4SRoman Gushchin ret = KSFT_PASS;
7995313bfe4SRoman Gushchin
8005313bfe4SRoman Gushchin cleanup:
8015313bfe4SRoman Gushchin if (cgroup)
8025313bfe4SRoman Gushchin cg_destroy(cgroup);
8035313bfe4SRoman Gushchin free(cgroup);
8045313bfe4SRoman Gushchin return ret;
8055313bfe4SRoman Gushchin }
8065313bfe4SRoman Gushchin
8075313bfe4SRoman Gushchin #define T(x) { x, #x }
8085313bfe4SRoman Gushchin struct cgfreezer_test {
8095313bfe4SRoman Gushchin int (*fn)(const char *root);
8105313bfe4SRoman Gushchin const char *name;
8115313bfe4SRoman Gushchin } tests[] = {
8125313bfe4SRoman Gushchin T(test_cgfreezer_simple),
8135313bfe4SRoman Gushchin T(test_cgfreezer_tree),
8145313bfe4SRoman Gushchin T(test_cgfreezer_forkbomb),
81544e9d308SRoman Gushchin T(test_cgfreezer_mkdir),
8165313bfe4SRoman Gushchin T(test_cgfreezer_rmdir),
8175313bfe4SRoman Gushchin T(test_cgfreezer_migrate),
8185313bfe4SRoman Gushchin T(test_cgfreezer_ptrace),
8195313bfe4SRoman Gushchin T(test_cgfreezer_stopped),
8205313bfe4SRoman Gushchin T(test_cgfreezer_ptraced),
8215313bfe4SRoman Gushchin T(test_cgfreezer_vfork),
8225313bfe4SRoman Gushchin };
8235313bfe4SRoman Gushchin #undef T
8245313bfe4SRoman Gushchin
main(int argc,char * argv[])8255313bfe4SRoman Gushchin int main(int argc, char *argv[])
8265313bfe4SRoman Gushchin {
8275313bfe4SRoman Gushchin char root[PATH_MAX];
8285313bfe4SRoman Gushchin int i, ret = EXIT_SUCCESS;
8295313bfe4SRoman Gushchin
830*c81b6d64STianchen Ding if (cg_find_unified_root(root, sizeof(root), NULL))
8315313bfe4SRoman Gushchin ksft_exit_skip("cgroup v2 isn't mounted\n");
8325313bfe4SRoman Gushchin for (i = 0; i < ARRAY_SIZE(tests); i++) {
8335313bfe4SRoman Gushchin switch (tests[i].fn(root)) {
8345313bfe4SRoman Gushchin case KSFT_PASS:
8355313bfe4SRoman Gushchin ksft_test_result_pass("%s\n", tests[i].name);
8365313bfe4SRoman Gushchin break;
8375313bfe4SRoman Gushchin case KSFT_SKIP:
8385313bfe4SRoman Gushchin ksft_test_result_skip("%s\n", tests[i].name);
8395313bfe4SRoman Gushchin break;
8405313bfe4SRoman Gushchin default:
8415313bfe4SRoman Gushchin ret = EXIT_FAILURE;
8425313bfe4SRoman Gushchin ksft_test_result_fail("%s\n", tests[i].name);
8435313bfe4SRoman Gushchin break;
8445313bfe4SRoman Gushchin }
8455313bfe4SRoman Gushchin }
8465313bfe4SRoman Gushchin
8475313bfe4SRoman Gushchin return ret;
8485313bfe4SRoman Gushchin }
849