• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2012 Christian Brauner <brauner-AT-kernel.org>
4  * Copyright (c) 2023 SUSE LLC <wegao@suse.com>
5  */
6 
7 /*\
8  * [Description]
9  *
10  * This test is copied from kselftest
11  * tools/testing/selftests/cgroup/test_kill.c.
12  *
13  * Only simple test implemented within current case, the other cases such
14  * as test_cgkill_tree and test_cgkill_forkbomb can be created later.
15  *
16  */
17 
18 #include <sys/wait.h>
19 
20 #include "lapi/syscalls.h"
21 #include "tst_test.h"
22 
23 #define MAX_PID_NUM 100
24 #define PID_NUM MIN(MAX_PID_NUM, (tst_ncpus_available() + 1))
25 #define BUF_LEN (20 * PID_NUM)
26 
27 static int *data_ptr;
28 static char *buf;
29 static struct tst_cg_group *cg_child_test_simple;
30 
wait_for_pid(pid_t pid)31 static int wait_for_pid(pid_t pid)
32 {
33 	int status, ret;
34 
35 again:
36 	ret = waitpid(pid, &status, 0);
37 	if (ret == -1) {
38 		if (errno == EINTR)
39 			goto again;
40 
41 		return -1;
42 	}
43 
44 	if (WIFSIGNALED(status))
45 		return 0;
46 
47 	return -1;
48 }
49 
cg_run_nowait(const struct tst_cg_group * const cg)50 static int cg_run_nowait(const struct tst_cg_group *const cg)
51 {
52 	int pid;
53 
54 	pid = SAFE_FORK();
55 	if (pid == 0) {
56 		SAFE_CG_PRINTF(cg, "cgroup.procs", "%d", getpid());
57 		if (tst_atomic_inc(data_ptr) == PID_NUM)
58 			TST_CHECKPOINT_WAKE(0);
59 		pause();
60 	}
61 
62 	return pid;
63 }
64 
cg_count_procs(const struct tst_cg_group * cg)65 static int cg_count_procs(const struct tst_cg_group *cg)
66 {
67 	char *ptr;
68 
69 	int nr = 0;
70 
71 	SAFE_CG_READ(cg, "cgroup.procs", buf, BUF_LEN);
72 
73 	for (ptr = buf; *ptr; ptr++)
74 		if (*ptr == '\n')
75 			nr++;
76 
77 	return nr;
78 }
79 
run(void)80 static void run(void)
81 {
82 	pid_t pids[MAX_PID_NUM];
83 	int i;
84 	*data_ptr = 0;
85 
86 	cg_child_test_simple = tst_cg_group_mk(tst_cg, "cg_test_simple");
87 
88 	if (!SAFE_CG_HAS(cg_child_test_simple, "cgroup.kill")) {
89 		cg_child_test_simple = tst_cg_group_rm(cg_child_test_simple);
90 		tst_brk(TCONF, "cgroup.kill is not supported on your distribution");
91 	}
92 
93 	memset(buf, 0, BUF_LEN);
94 
95 	for (i = 0; i < PID_NUM; i++)
96 		pids[i] = cg_run_nowait(cg_child_test_simple);
97 
98 	TST_CHECKPOINT_WAIT(0);
99 	TST_EXP_VAL(cg_count_procs(cg_child_test_simple), PID_NUM);
100 	SAFE_CG_PRINTF(cg_child_test_simple, "cgroup.kill", "%d", 1);
101 
102 	for (i = 0; i < PID_NUM; i++)
103 		TST_EXP_PASS_SILENT(wait_for_pid(pids[i]));
104 
105 	TST_EXP_VAL(cg_count_procs(cg_child_test_simple), 0);
106 	cg_child_test_simple = tst_cg_group_rm(cg_child_test_simple);
107 }
108 
setup(void)109 static void setup(void)
110 {
111 	buf = tst_alloc(BUF_LEN);
112 	data_ptr = SAFE_MMAP(NULL, sizeof(uintptr_t), PROT_READ | PROT_WRITE,
113 						 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
114 }
115 
cleanup(void)116 static void cleanup(void)
117 {
118 	if (data_ptr)
119 		SAFE_MUNMAP(data_ptr, sizeof(uintptr_t));
120 }
121 
122 static struct tst_test test = {
123 	.test_all = run,
124 	.setup = setup,
125 	.cleanup = cleanup,
126 	.forks_child = 1,
127 	.max_runtime = 20,
128 	.needs_cgroup_ctrls = (const char *const []){ "base", NULL },
129 	.needs_cgroup_ver = TST_CG_V2,
130 	.needs_checkpoints = 1,
131 };
132