1 // SPDX-License-Identifier: GPL-2.0
2 
3 #define _GNU_SOURCE
4 #include <linux/limits.h>
5 #include <stdio.h>
6 
7 #include "../kselftest.h"
8 #include "cgroup_util.h"
9 
10 /*
11  * This test creates two nested cgroups with and without enabling
12  * the cpu controller.
13  */
14 static int test_cpucg_subtree_control(const char *root)
15 {
16 	char *parent = NULL, *child = NULL, *parent2 = NULL, *child2 = NULL;
17 	int ret = KSFT_FAIL;
18 
19 	// Create two nested cgroups with the cpu controller enabled.
20 	parent = cg_name(root, "cpucg_test_0");
21 	if (!parent)
22 		goto cleanup;
23 
24 	if (cg_create(parent))
25 		goto cleanup;
26 
27 	if (cg_write(parent, "cgroup.subtree_control", "+cpu"))
28 		goto cleanup;
29 
30 	child = cg_name(parent, "cpucg_test_child");
31 	if (!child)
32 		goto cleanup;
33 
34 	if (cg_create(child))
35 		goto cleanup;
36 
37 	if (cg_read_strstr(child, "cgroup.controllers", "cpu"))
38 		goto cleanup;
39 
40 	// Create two nested cgroups without enabling the cpu controller.
41 	parent2 = cg_name(root, "cpucg_test_1");
42 	if (!parent2)
43 		goto cleanup;
44 
45 	if (cg_create(parent2))
46 		goto cleanup;
47 
48 	child2 = cg_name(parent2, "cpucg_test_child");
49 	if (!child2)
50 		goto cleanup;
51 
52 	if (cg_create(child2))
53 		goto cleanup;
54 
55 	if (!cg_read_strstr(child2, "cgroup.controllers", "cpu"))
56 		goto cleanup;
57 
58 	ret = KSFT_PASS;
59 
60 cleanup:
61 	cg_destroy(child);
62 	free(child);
63 	cg_destroy(child2);
64 	free(child2);
65 	cg_destroy(parent);
66 	free(parent);
67 	cg_destroy(parent2);
68 	free(parent2);
69 
70 	return ret;
71 }
72 
73 #define T(x) { x, #x }
74 struct cpucg_test {
75 	int (*fn)(const char *root);
76 	const char *name;
77 } tests[] = {
78 	T(test_cpucg_subtree_control),
79 };
80 #undef T
81 
82 int main(int argc, char *argv[])
83 {
84 	char root[PATH_MAX];
85 	int i, ret = EXIT_SUCCESS;
86 
87 	if (cg_find_unified_root(root, sizeof(root)))
88 		ksft_exit_skip("cgroup v2 isn't mounted\n");
89 
90 	if (cg_read_strstr(root, "cgroup.subtree_control", "cpu"))
91 		if (cg_write(root, "cgroup.subtree_control", "+cpu"))
92 			ksft_exit_skip("Failed to set cpu controller\n");
93 
94 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
95 		switch (tests[i].fn(root)) {
96 		case KSFT_PASS:
97 			ksft_test_result_pass("%s\n", tests[i].name);
98 			break;
99 		case KSFT_SKIP:
100 			ksft_test_result_skip("%s\n", tests[i].name);
101 			break;
102 		default:
103 			ret = EXIT_FAILURE;
104 			ksft_test_result_fail("%s\n", tests[i].name);
105 			break;
106 		}
107 	}
108 
109 	return ret;
110 }
111