Skip to content

Commit 9f34c56

Browse files
Werkovhtejun
authored andcommitted
selftests: cgroup: Add basic tests for pids controller
This commit adds (and wires in) new test program for checking basic pids controller functionality -- restricting tasks in a cgroup and correct event counting. Signed-off-by: Michal Koutný <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent 7055968 commit 9f34c56

File tree

3 files changed

+181
-0
lines changed

3 files changed

+181
-0
lines changed

tools/testing/selftests/cgroup/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ test_hugetlb_memcg
77
test_kill
88
test_kmem
99
test_memcontrol
10+
test_pids
1011
test_zswap
1112
wait_inotify

tools/testing/selftests/cgroup/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ TEST_GEN_PROGS += test_hugetlb_memcg
1515
TEST_GEN_PROGS += test_kill
1616
TEST_GEN_PROGS += test_kmem
1717
TEST_GEN_PROGS += test_memcontrol
18+
TEST_GEN_PROGS += test_pids
1819
TEST_GEN_PROGS += test_zswap
1920

2021
LOCAL_HDRS += $(selfdir)/clone3/clone3_selftests.h $(selfdir)/pidfd/pidfd.h
@@ -29,4 +30,5 @@ $(OUTPUT)/test_hugetlb_memcg: cgroup_util.c
2930
$(OUTPUT)/test_kill: cgroup_util.c
3031
$(OUTPUT)/test_kmem: cgroup_util.c
3132
$(OUTPUT)/test_memcontrol: cgroup_util.c
33+
$(OUTPUT)/test_pids: cgroup_util.c
3234
$(OUTPUT)/test_zswap: cgroup_util.c
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#define _GNU_SOURCE
3+
4+
#include <errno.h>
5+
#include <linux/limits.h>
6+
#include <signal.h>
7+
#include <string.h>
8+
#include <sys/stat.h>
9+
#include <sys/types.h>
10+
#include <unistd.h>
11+
12+
#include "../kselftest.h"
13+
#include "cgroup_util.h"
14+
15+
static int run_success(const char *cgroup, void *arg)
16+
{
17+
return 0;
18+
}
19+
20+
static int run_pause(const char *cgroup, void *arg)
21+
{
22+
return pause();
23+
}
24+
25+
/*
26+
* This test checks that pids.max prevents forking new children above the
27+
* specified limit in the cgroup.
28+
*/
29+
static int test_pids_max(const char *root)
30+
{
31+
int ret = KSFT_FAIL;
32+
char *cg_pids;
33+
int pid;
34+
35+
cg_pids = cg_name(root, "pids_test");
36+
if (!cg_pids)
37+
goto cleanup;
38+
39+
if (cg_create(cg_pids))
40+
goto cleanup;
41+
42+
if (cg_read_strcmp(cg_pids, "pids.max", "max\n"))
43+
goto cleanup;
44+
45+
if (cg_write(cg_pids, "pids.max", "2"))
46+
goto cleanup;
47+
48+
if (cg_enter_current(cg_pids))
49+
goto cleanup;
50+
51+
pid = cg_run_nowait(cg_pids, run_pause, NULL);
52+
if (pid < 0)
53+
goto cleanup;
54+
55+
if (cg_run_nowait(cg_pids, run_success, NULL) != -1 || errno != EAGAIN)
56+
goto cleanup;
57+
58+
if (kill(pid, SIGINT))
59+
goto cleanup;
60+
61+
ret = KSFT_PASS;
62+
63+
cleanup:
64+
cg_enter_current(root);
65+
cg_destroy(cg_pids);
66+
free(cg_pids);
67+
68+
return ret;
69+
}
70+
71+
/*
72+
* This test checks that pids.events are counted in cgroup associated with pids.max
73+
*/
74+
static int test_pids_events(const char *root)
75+
{
76+
int ret = KSFT_FAIL;
77+
char *cg_parent = NULL, *cg_child = NULL;
78+
int pid;
79+
80+
cg_parent = cg_name(root, "pids_parent");
81+
cg_child = cg_name(cg_parent, "pids_child");
82+
if (!cg_parent || !cg_child)
83+
goto cleanup;
84+
85+
if (cg_create(cg_parent))
86+
goto cleanup;
87+
if (cg_write(cg_parent, "cgroup.subtree_control", "+pids"))
88+
goto cleanup;
89+
if (cg_create(cg_child))
90+
goto cleanup;
91+
92+
if (cg_write(cg_parent, "pids.max", "2"))
93+
goto cleanup;
94+
95+
if (cg_read_strcmp(cg_child, "pids.max", "max\n"))
96+
goto cleanup;
97+
98+
if (cg_enter_current(cg_child))
99+
goto cleanup;
100+
101+
pid = cg_run_nowait(cg_child, run_pause, NULL);
102+
if (pid < 0)
103+
goto cleanup;
104+
105+
if (cg_run_nowait(cg_child, run_success, NULL) != -1 || errno != EAGAIN)
106+
goto cleanup;
107+
108+
if (kill(pid, SIGINT))
109+
goto cleanup;
110+
111+
if (cg_read_key_long(cg_child, "pids.events", "max ") != 0)
112+
goto cleanup;
113+
if (cg_read_key_long(cg_parent, "pids.events", "max ") != 1)
114+
goto cleanup;
115+
116+
117+
ret = KSFT_PASS;
118+
119+
cleanup:
120+
cg_enter_current(root);
121+
if (cg_child)
122+
cg_destroy(cg_child);
123+
if (cg_parent)
124+
cg_destroy(cg_parent);
125+
free(cg_child);
126+
free(cg_parent);
127+
128+
return ret;
129+
}
130+
131+
132+
133+
#define T(x) { x, #x }
134+
struct pids_test {
135+
int (*fn)(const char *root);
136+
const char *name;
137+
} tests[] = {
138+
T(test_pids_max),
139+
T(test_pids_events),
140+
};
141+
#undef T
142+
143+
int main(int argc, char **argv)
144+
{
145+
char root[PATH_MAX];
146+
147+
ksft_print_header();
148+
ksft_set_plan(ARRAY_SIZE(tests));
149+
if (cg_find_unified_root(root, sizeof(root), NULL))
150+
ksft_exit_skip("cgroup v2 isn't mounted\n");
151+
152+
/*
153+
* Check that pids controller is available:
154+
* pids is listed in cgroup.controllers
155+
*/
156+
if (cg_read_strstr(root, "cgroup.controllers", "pids"))
157+
ksft_exit_skip("pids controller isn't available\n");
158+
159+
if (cg_read_strstr(root, "cgroup.subtree_control", "pids"))
160+
if (cg_write(root, "cgroup.subtree_control", "+pids"))
161+
ksft_exit_skip("Failed to set pids controller\n");
162+
163+
for (int i = 0; i < ARRAY_SIZE(tests); i++) {
164+
switch (tests[i].fn(root)) {
165+
case KSFT_PASS:
166+
ksft_test_result_pass("%s\n", tests[i].name);
167+
break;
168+
case KSFT_SKIP:
169+
ksft_test_result_skip("%s\n", tests[i].name);
170+
break;
171+
default:
172+
ksft_test_result_fail("%s\n", tests[i].name);
173+
break;
174+
}
175+
}
176+
177+
ksft_finished();
178+
}

0 commit comments

Comments
 (0)