xref: /aosp_15_r20/external/ltp/lib/tst_cgroup.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2020 Red Hat, Inc.
4*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2020 Li Wang <[email protected]>
5*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2020-2021 SUSE LLC <[email protected]>
6*49cdfc7eSAndroid Build Coastguard Worker  */
7*49cdfc7eSAndroid Build Coastguard Worker 
8*49cdfc7eSAndroid Build Coastguard Worker #define TST_NO_DEFAULT_MAIN
9*49cdfc7eSAndroid Build Coastguard Worker 
10*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
11*49cdfc7eSAndroid Build Coastguard Worker #include <stddef.h>
12*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
13*49cdfc7eSAndroid Build Coastguard Worker #include <mntent.h>
14*49cdfc7eSAndroid Build Coastguard Worker 
15*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
16*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/fcntl.h"
17*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/mount.h"
18*49cdfc7eSAndroid Build Coastguard Worker #include "tst_safe_file_at.h"
19*49cdfc7eSAndroid Build Coastguard Worker 
20*49cdfc7eSAndroid Build Coastguard Worker struct cgroup_root;
21*49cdfc7eSAndroid Build Coastguard Worker 
22*49cdfc7eSAndroid Build Coastguard Worker /* A node in a single CGroup hierarchy. It exists mainly for
23*49cdfc7eSAndroid Build Coastguard Worker  * convenience so that we do not have to traverse the CGroup structure
24*49cdfc7eSAndroid Build Coastguard Worker  * for frequent operations.
25*49cdfc7eSAndroid Build Coastguard Worker  *
26*49cdfc7eSAndroid Build Coastguard Worker  * This is actually a single-linked list not a tree. We only need to
27*49cdfc7eSAndroid Build Coastguard Worker  * traverse from leaf towards root.
28*49cdfc7eSAndroid Build Coastguard Worker  */
29*49cdfc7eSAndroid Build Coastguard Worker struct cgroup_dir {
30*49cdfc7eSAndroid Build Coastguard Worker 	const char *dir_name;
31*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_dir *dir_parent;
32*49cdfc7eSAndroid Build Coastguard Worker 
33*49cdfc7eSAndroid Build Coastguard Worker 	/* Shortcut to root */
34*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_root *dir_root;
35*49cdfc7eSAndroid Build Coastguard Worker 
36*49cdfc7eSAndroid Build Coastguard Worker 	/* Subsystems (controllers) bit field. Only controllers which
37*49cdfc7eSAndroid Build Coastguard Worker 	 * were required and configured for this node are added to
38*49cdfc7eSAndroid Build Coastguard Worker 	 * this field. So it may be different from root->css_field.
39*49cdfc7eSAndroid Build Coastguard Worker 	 */
40*49cdfc7eSAndroid Build Coastguard Worker 	uint32_t ctrl_field;
41*49cdfc7eSAndroid Build Coastguard Worker 
42*49cdfc7eSAndroid Build Coastguard Worker 	/* In general we avoid having sprintfs everywhere and use
43*49cdfc7eSAndroid Build Coastguard Worker 	 * openat, linkat, etc.
44*49cdfc7eSAndroid Build Coastguard Worker 	 */
45*49cdfc7eSAndroid Build Coastguard Worker 	int dir_fd;
46*49cdfc7eSAndroid Build Coastguard Worker 
47*49cdfc7eSAndroid Build Coastguard Worker 	int we_created_it:1;
48*49cdfc7eSAndroid Build Coastguard Worker };
49*49cdfc7eSAndroid Build Coastguard Worker 
50*49cdfc7eSAndroid Build Coastguard Worker /* The root of a CGroup hierarchy/tree */
51*49cdfc7eSAndroid Build Coastguard Worker struct cgroup_root {
52*49cdfc7eSAndroid Build Coastguard Worker 	enum tst_cg_ver ver;
53*49cdfc7eSAndroid Build Coastguard Worker 	/* A mount path */
54*49cdfc7eSAndroid Build Coastguard Worker 	char mnt_path[PATH_MAX];
55*49cdfc7eSAndroid Build Coastguard Worker 	/* Subsystems (controllers) bit field. Includes all
56*49cdfc7eSAndroid Build Coastguard Worker 	 * controllers found while scanning this root.
57*49cdfc7eSAndroid Build Coastguard Worker 	 */
58*49cdfc7eSAndroid Build Coastguard Worker 	uint32_t ctrl_field;
59*49cdfc7eSAndroid Build Coastguard Worker 
60*49cdfc7eSAndroid Build Coastguard Worker 	/* CGroup hierarchy: mnt -> ltp -> {drain, test -> ??? } We
61*49cdfc7eSAndroid Build Coastguard Worker 	 * keep a flat reference to ltp, drain and test for
62*49cdfc7eSAndroid Build Coastguard Worker 	 * convenience.
63*49cdfc7eSAndroid Build Coastguard Worker 	 */
64*49cdfc7eSAndroid Build Coastguard Worker 
65*49cdfc7eSAndroid Build Coastguard Worker 	/* Mount directory */
66*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir mnt_dir;
67*49cdfc7eSAndroid Build Coastguard Worker 	/* LTP CGroup directory, contains drain and test dirs */
68*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir ltp_dir;
69*49cdfc7eSAndroid Build Coastguard Worker 	/* Drain CGroup, see cgroup_cleanup */
70*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir drain_dir;
71*49cdfc7eSAndroid Build Coastguard Worker 	/* CGroup for current test. Which may have children. */
72*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir test_dir;
73*49cdfc7eSAndroid Build Coastguard Worker 
74*49cdfc7eSAndroid Build Coastguard Worker 	int nsdelegate:1;
75*49cdfc7eSAndroid Build Coastguard Worker 
76*49cdfc7eSAndroid Build Coastguard Worker 	int we_mounted_it:1;
77*49cdfc7eSAndroid Build Coastguard Worker 	/* cpuset is in compatability mode */
78*49cdfc7eSAndroid Build Coastguard Worker 	int no_cpuset_prefix:1;
79*49cdfc7eSAndroid Build Coastguard Worker };
80*49cdfc7eSAndroid Build Coastguard Worker 
81*49cdfc7eSAndroid Build Coastguard Worker /* Controller sub-systems */
82*49cdfc7eSAndroid Build Coastguard Worker enum cgroup_ctrl_indx {
83*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_MEMORY = 1,
84*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_CPU,
85*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_CPUSET,
86*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_IO,
87*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_PIDS,
88*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_HUGETLB,
89*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_CPUACCT,
90*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_DEVICES,
91*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_FREEZER,
92*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_NETCLS,
93*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_NETPRIO,
94*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_BLKIO,
95*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_MISC,
96*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_PERFEVENT,
97*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_DEBUG,
98*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_RDMA,
99*49cdfc7eSAndroid Build Coastguard Worker 	CTRL_BASE
100*49cdfc7eSAndroid Build Coastguard Worker };
101*49cdfc7eSAndroid Build Coastguard Worker #define CTRLS_MAX CTRL_BASE
102*49cdfc7eSAndroid Build Coastguard Worker 
103*49cdfc7eSAndroid Build Coastguard Worker /* At most we can have one cgroup V1 tree for each controller and one
104*49cdfc7eSAndroid Build Coastguard Worker  * (empty) v2 tree.
105*49cdfc7eSAndroid Build Coastguard Worker  */
106*49cdfc7eSAndroid Build Coastguard Worker #define ROOTS_MAX (CTRLS_MAX + 1)
107*49cdfc7eSAndroid Build Coastguard Worker 
108*49cdfc7eSAndroid Build Coastguard Worker /* Describes a controller file or knob
109*49cdfc7eSAndroid Build Coastguard Worker  *
110*49cdfc7eSAndroid Build Coastguard Worker  * The primary purpose of this is to map V2 names to V1
111*49cdfc7eSAndroid Build Coastguard Worker  * names.
112*49cdfc7eSAndroid Build Coastguard Worker  */
113*49cdfc7eSAndroid Build Coastguard Worker struct cgroup_file {
114*49cdfc7eSAndroid Build Coastguard Worker 	/* Canonical name. Is the V2 name unless an item is V1 only */
115*49cdfc7eSAndroid Build Coastguard Worker 	const char *const file_name;
116*49cdfc7eSAndroid Build Coastguard Worker 	/* V1 name or NULL if item is V2 only */
117*49cdfc7eSAndroid Build Coastguard Worker 	const char *const file_name_v1;
118*49cdfc7eSAndroid Build Coastguard Worker 
119*49cdfc7eSAndroid Build Coastguard Worker 	/* The controller this item belongs to or zero for
120*49cdfc7eSAndroid Build Coastguard Worker 	 * 'cgroup.<item>'.
121*49cdfc7eSAndroid Build Coastguard Worker 	 */
122*49cdfc7eSAndroid Build Coastguard Worker 	const enum cgroup_ctrl_indx ctrl_indx;
123*49cdfc7eSAndroid Build Coastguard Worker };
124*49cdfc7eSAndroid Build Coastguard Worker 
125*49cdfc7eSAndroid Build Coastguard Worker /* Describes a Controller or subsystem
126*49cdfc7eSAndroid Build Coastguard Worker  *
127*49cdfc7eSAndroid Build Coastguard Worker  * Internally the kernel seems to call controllers subsystems and uses
128*49cdfc7eSAndroid Build Coastguard Worker  * the abbreviations subsys and css.
129*49cdfc7eSAndroid Build Coastguard Worker  */
130*49cdfc7eSAndroid Build Coastguard Worker struct cgroup_ctrl {
131*49cdfc7eSAndroid Build Coastguard Worker 	/* Userland name of the controller (e.g. 'memory' not 'memcg') */
132*49cdfc7eSAndroid Build Coastguard Worker 	const char *const ctrl_name;
133*49cdfc7eSAndroid Build Coastguard Worker 	/* List of files belonging to this controller */
134*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_file *const files;
135*49cdfc7eSAndroid Build Coastguard Worker 	/* Our index for the controller */
136*49cdfc7eSAndroid Build Coastguard Worker 	const enum cgroup_ctrl_indx ctrl_indx;
137*49cdfc7eSAndroid Build Coastguard Worker 
138*49cdfc7eSAndroid Build Coastguard Worker 	/* Runtime; hierarchy the controller is attached to */
139*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_root *ctrl_root;
140*49cdfc7eSAndroid Build Coastguard Worker 	/* Runtime; whether we required the controller */
141*49cdfc7eSAndroid Build Coastguard Worker 	int we_require_it:1;
142*49cdfc7eSAndroid Build Coastguard Worker };
143*49cdfc7eSAndroid Build Coastguard Worker 
144*49cdfc7eSAndroid Build Coastguard Worker struct tst_cg_group {
145*49cdfc7eSAndroid Build Coastguard Worker 	char group_name[NAME_MAX + 1];
146*49cdfc7eSAndroid Build Coastguard Worker 	/* Maps controller ID to the tree which contains it. The V2
147*49cdfc7eSAndroid Build Coastguard Worker 	 * tree is at zero even if it contains no controllers.
148*49cdfc7eSAndroid Build Coastguard Worker 	 */
149*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir *dirs_by_ctrl[ROOTS_MAX];
150*49cdfc7eSAndroid Build Coastguard Worker 	/* NULL terminated list of trees */
151*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir *dirs[ROOTS_MAX + 1];
152*49cdfc7eSAndroid Build Coastguard Worker };
153*49cdfc7eSAndroid Build Coastguard Worker 
154*49cdfc7eSAndroid Build Coastguard Worker /* If controllers are required via the tst_test struct then this is
155*49cdfc7eSAndroid Build Coastguard Worker  * populated with the test's CGroup.
156*49cdfc7eSAndroid Build Coastguard Worker  */
157*49cdfc7eSAndroid Build Coastguard Worker static struct tst_cg_group test_group;
158*49cdfc7eSAndroid Build Coastguard Worker static struct tst_cg_group drain_group;
159*49cdfc7eSAndroid Build Coastguard Worker const struct tst_cg_group *const tst_cg = &test_group;
160*49cdfc7eSAndroid Build Coastguard Worker const struct tst_cg_group *const tst_cg_drain = &drain_group;
161*49cdfc7eSAndroid Build Coastguard Worker 
162*49cdfc7eSAndroid Build Coastguard Worker /* Always use first item for unified hierarchy */
163*49cdfc7eSAndroid Build Coastguard Worker static struct cgroup_root roots[ROOTS_MAX + 1];
164*49cdfc7eSAndroid Build Coastguard Worker 
165*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file cgroup_ctrl_files[] = {
166*49cdfc7eSAndroid Build Coastguard Worker 	/* procs exists on V1, however it was read-only until kernel v3.0. */
167*49cdfc7eSAndroid Build Coastguard Worker 	{ "cgroup.procs", "tasks", 0 },
168*49cdfc7eSAndroid Build Coastguard Worker 	{ "cgroup.controllers", NULL, 0 },
169*49cdfc7eSAndroid Build Coastguard Worker 	{ "cgroup.subtree_control", NULL, 0 },
170*49cdfc7eSAndroid Build Coastguard Worker 	{ "cgroup.clone_children", "cgroup.clone_children", 0 },
171*49cdfc7eSAndroid Build Coastguard Worker 	{ "cgroup.kill", NULL, 0 },
172*49cdfc7eSAndroid Build Coastguard Worker 	{ }
173*49cdfc7eSAndroid Build Coastguard Worker };
174*49cdfc7eSAndroid Build Coastguard Worker 
175*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file memory_ctrl_files[] = {
176*49cdfc7eSAndroid Build Coastguard Worker 	{ "memory.current", "memory.usage_in_bytes", CTRL_MEMORY },
177*49cdfc7eSAndroid Build Coastguard Worker 	{ "memory.events", NULL, CTRL_MEMORY },
178*49cdfc7eSAndroid Build Coastguard Worker 	{ "memory.low", NULL, CTRL_MEMORY },
179*49cdfc7eSAndroid Build Coastguard Worker 	{ "memory.min", NULL, CTRL_MEMORY },
180*49cdfc7eSAndroid Build Coastguard Worker 	{ "memory.max", "memory.limit_in_bytes", CTRL_MEMORY },
181*49cdfc7eSAndroid Build Coastguard Worker 	{ "memory.stat", "memory.stat", CTRL_MEMORY },
182*49cdfc7eSAndroid Build Coastguard Worker 	{ "memory.swappiness", "memory.swappiness", CTRL_MEMORY },
183*49cdfc7eSAndroid Build Coastguard Worker 	{ "memory.swap.current", "memory.memsw.usage_in_bytes", CTRL_MEMORY },
184*49cdfc7eSAndroid Build Coastguard Worker 	{ "memory.swap.max", "memory.memsw.limit_in_bytes", CTRL_MEMORY },
185*49cdfc7eSAndroid Build Coastguard Worker 	{ "memory.kmem.usage_in_bytes", "memory.kmem.usage_in_bytes", CTRL_MEMORY },
186*49cdfc7eSAndroid Build Coastguard Worker 	{ "memory.kmem.limit_in_bytes", "memory.kmem.limit_in_bytes", CTRL_MEMORY },
187*49cdfc7eSAndroid Build Coastguard Worker 	{ }
188*49cdfc7eSAndroid Build Coastguard Worker };
189*49cdfc7eSAndroid Build Coastguard Worker 
190*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file cpu_ctrl_files[] = {
191*49cdfc7eSAndroid Build Coastguard Worker 	/* The V1 quota and period files were combined in the V2 max
192*49cdfc7eSAndroid Build Coastguard Worker 	 * file. The quota is in the first column and if we just print
193*49cdfc7eSAndroid Build Coastguard Worker 	 * a single value to the file, it will be treated as the
194*49cdfc7eSAndroid Build Coastguard Worker 	 * quota. To get or set the period we need to branch on the
195*49cdfc7eSAndroid Build Coastguard Worker 	 * API version.
196*49cdfc7eSAndroid Build Coastguard Worker 	 */
197*49cdfc7eSAndroid Build Coastguard Worker 	{ "cpu.max", "cpu.cfs_quota_us", CTRL_CPU },
198*49cdfc7eSAndroid Build Coastguard Worker 	{ "cpu.cfs_period_us", "cpu.cfs_period_us", CTRL_CPU },
199*49cdfc7eSAndroid Build Coastguard Worker 	{ }
200*49cdfc7eSAndroid Build Coastguard Worker };
201*49cdfc7eSAndroid Build Coastguard Worker 
202*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file cpuset_ctrl_files[] = {
203*49cdfc7eSAndroid Build Coastguard Worker 	{ "cpuset.cpus", "cpuset.cpus", CTRL_CPUSET },
204*49cdfc7eSAndroid Build Coastguard Worker 	{ "cpuset.mems", "cpuset.mems", CTRL_CPUSET },
205*49cdfc7eSAndroid Build Coastguard Worker 	{ "cpuset.memory_migrate", "cpuset.memory_migrate", CTRL_CPUSET },
206*49cdfc7eSAndroid Build Coastguard Worker 	{ }
207*49cdfc7eSAndroid Build Coastguard Worker };
208*49cdfc7eSAndroid Build Coastguard Worker 
209*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file io_ctrl_files[] = {
210*49cdfc7eSAndroid Build Coastguard Worker 	{ "io.stat", NULL, CTRL_IO },
211*49cdfc7eSAndroid Build Coastguard Worker 	{ }
212*49cdfc7eSAndroid Build Coastguard Worker };
213*49cdfc7eSAndroid Build Coastguard Worker 
214*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file pids_ctrl_files[] = {
215*49cdfc7eSAndroid Build Coastguard Worker 	{ "pids.max", "pids.max", CTRL_PIDS },
216*49cdfc7eSAndroid Build Coastguard Worker 	{ "pids.current", "pids.current", CTRL_PIDS },
217*49cdfc7eSAndroid Build Coastguard Worker 	{ }
218*49cdfc7eSAndroid Build Coastguard Worker };
219*49cdfc7eSAndroid Build Coastguard Worker 
220*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file hugetlb_ctrl_files[] = {
221*49cdfc7eSAndroid Build Coastguard Worker 	{ }
222*49cdfc7eSAndroid Build Coastguard Worker };
223*49cdfc7eSAndroid Build Coastguard Worker 
224*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file cpuacct_ctrl_files[] = {
225*49cdfc7eSAndroid Build Coastguard Worker 	{ }
226*49cdfc7eSAndroid Build Coastguard Worker };
227*49cdfc7eSAndroid Build Coastguard Worker 
228*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file devices_ctrl_files[] = {
229*49cdfc7eSAndroid Build Coastguard Worker 	{ }
230*49cdfc7eSAndroid Build Coastguard Worker };
231*49cdfc7eSAndroid Build Coastguard Worker 
232*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file freezer_ctrl_files[] = {
233*49cdfc7eSAndroid Build Coastguard Worker 	{ }
234*49cdfc7eSAndroid Build Coastguard Worker };
235*49cdfc7eSAndroid Build Coastguard Worker 
236*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file net_cls_ctrl_files[] = {
237*49cdfc7eSAndroid Build Coastguard Worker 	{ }
238*49cdfc7eSAndroid Build Coastguard Worker };
239*49cdfc7eSAndroid Build Coastguard Worker 
240*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file net_prio_ctrl_files[] = {
241*49cdfc7eSAndroid Build Coastguard Worker 	{ }
242*49cdfc7eSAndroid Build Coastguard Worker };
243*49cdfc7eSAndroid Build Coastguard Worker 
244*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file blkio_ctrl_files[] = {
245*49cdfc7eSAndroid Build Coastguard Worker 	{ }
246*49cdfc7eSAndroid Build Coastguard Worker };
247*49cdfc7eSAndroid Build Coastguard Worker 
248*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file misc_ctrl_files[] = {
249*49cdfc7eSAndroid Build Coastguard Worker 	{ }
250*49cdfc7eSAndroid Build Coastguard Worker };
251*49cdfc7eSAndroid Build Coastguard Worker 
252*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file perf_event_ctrl_files[] = {
253*49cdfc7eSAndroid Build Coastguard Worker 	{ }
254*49cdfc7eSAndroid Build Coastguard Worker };
255*49cdfc7eSAndroid Build Coastguard Worker 
256*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file debug_ctrl_files[] = {
257*49cdfc7eSAndroid Build Coastguard Worker 	{ }
258*49cdfc7eSAndroid Build Coastguard Worker };
259*49cdfc7eSAndroid Build Coastguard Worker 
260*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file rdma_ctrl_files[] = {
261*49cdfc7eSAndroid Build Coastguard Worker 	{ }
262*49cdfc7eSAndroid Build Coastguard Worker };
263*49cdfc7eSAndroid Build Coastguard Worker 
264*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file base_ctrl_files[] = {
265*49cdfc7eSAndroid Build Coastguard Worker 	{ }
266*49cdfc7eSAndroid Build Coastguard Worker };
267*49cdfc7eSAndroid Build Coastguard Worker 
268*49cdfc7eSAndroid Build Coastguard Worker #define CTRL_NAME_MAX 31
269*49cdfc7eSAndroid Build Coastguard Worker #define CGROUP_CTRL_MEMBER(x, y)[y] = { .ctrl_name = #x, .files = \
270*49cdfc7eSAndroid Build Coastguard Worker 	x ## _ctrl_files, .ctrl_indx = y, NULL, 0 }
271*49cdfc7eSAndroid Build Coastguard Worker 
272*49cdfc7eSAndroid Build Coastguard Worker /* Lookup tree for item names. */
273*49cdfc7eSAndroid Build Coastguard Worker static struct cgroup_ctrl controllers[] = {
274*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(cgroup, 0),
275*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(memory, CTRL_MEMORY),
276*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(cpu, CTRL_CPU),
277*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(cpuset, CTRL_CPUSET),
278*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(io, CTRL_IO),
279*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(pids, CTRL_PIDS),
280*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(hugetlb, CTRL_HUGETLB),
281*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(cpuacct, CTRL_CPUACCT),
282*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(devices, CTRL_DEVICES),
283*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(freezer, CTRL_FREEZER),
284*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(net_cls, CTRL_NETCLS),
285*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(net_prio, CTRL_NETPRIO),
286*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(blkio, CTRL_BLKIO),
287*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(misc, CTRL_MISC),
288*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(perf_event, CTRL_PERFEVENT),
289*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(debug, CTRL_DEBUG),
290*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(rdma, CTRL_RDMA),
291*49cdfc7eSAndroid Build Coastguard Worker 	CGROUP_CTRL_MEMBER(base, CTRL_BASE),
292*49cdfc7eSAndroid Build Coastguard Worker 	{ }
293*49cdfc7eSAndroid Build Coastguard Worker };
294*49cdfc7eSAndroid Build Coastguard Worker 
295*49cdfc7eSAndroid Build Coastguard Worker /* We should probably allow these to be set in environment
296*49cdfc7eSAndroid Build Coastguard Worker  * variables
297*49cdfc7eSAndroid Build Coastguard Worker  */
298*49cdfc7eSAndroid Build Coastguard Worker static const char *cgroup_ltp_dir = "ltp";
299*49cdfc7eSAndroid Build Coastguard Worker static const char *cgroup_ltp_drain_dir = "drain";
300*49cdfc7eSAndroid Build Coastguard Worker static char cgroup_test_dir[NAME_MAX + 1];
301*49cdfc7eSAndroid Build Coastguard Worker static const char *cgroup_mount_ltp_prefix = "cgroup_";
302*49cdfc7eSAndroid Build Coastguard Worker static const char *cgroup_v2_ltp_mount = "unified";
303*49cdfc7eSAndroid Build Coastguard Worker 
304*49cdfc7eSAndroid Build Coastguard Worker #define first_root				\
305*49cdfc7eSAndroid Build Coastguard Worker 	(roots[0].ver ? roots : roots + 1)
306*49cdfc7eSAndroid Build Coastguard Worker #define for_each_root(r)			\
307*49cdfc7eSAndroid Build Coastguard Worker 	for ((r) = first_root; (r)->ver; (r)++)
308*49cdfc7eSAndroid Build Coastguard Worker #define for_each_v1_root(r)			\
309*49cdfc7eSAndroid Build Coastguard Worker 	for ((r) = roots + 1; (r)->ver; (r)++)
310*49cdfc7eSAndroid Build Coastguard Worker #define for_each_ctrl(ctrl)			\
311*49cdfc7eSAndroid Build Coastguard Worker 	for ((ctrl) = controllers; (ctrl)->ctrl_name; (ctrl)++)
312*49cdfc7eSAndroid Build Coastguard Worker 
313*49cdfc7eSAndroid Build Coastguard Worker /* In all cases except one, this only loops once.
314*49cdfc7eSAndroid Build Coastguard Worker  *
315*49cdfc7eSAndroid Build Coastguard Worker  * If (ctrl) == 0 and multiple V1 (and a V2) hierarchies are mounted,
316*49cdfc7eSAndroid Build Coastguard Worker  * then we need to loop over multiple directories. For example if we
317*49cdfc7eSAndroid Build Coastguard Worker  * need to write to "tasks"/"cgroup.procs" which exists for each
318*49cdfc7eSAndroid Build Coastguard Worker  * hierarchy.
319*49cdfc7eSAndroid Build Coastguard Worker  */
320*49cdfc7eSAndroid Build Coastguard Worker #define for_each_dir(cg, ctrl, t)					\
321*49cdfc7eSAndroid Build Coastguard Worker 	for ((t) = (ctrl) ? (cg)->dirs_by_ctrl + (ctrl) : (cg)->dirs;	\
322*49cdfc7eSAndroid Build Coastguard Worker 	     *(t);							\
323*49cdfc7eSAndroid Build Coastguard Worker 	     (t) = (ctrl) ? (cg)->dirs + ROOTS_MAX : (t) + 1)
324*49cdfc7eSAndroid Build Coastguard Worker 
325*49cdfc7eSAndroid Build Coastguard Worker __attribute__ ((nonnull))
has_ctrl(const uint32_t ctrl_field,const struct cgroup_ctrl * const ctrl)326*49cdfc7eSAndroid Build Coastguard Worker static int has_ctrl(const uint32_t ctrl_field,
327*49cdfc7eSAndroid Build Coastguard Worker 		    const struct cgroup_ctrl *const ctrl)
328*49cdfc7eSAndroid Build Coastguard Worker {
329*49cdfc7eSAndroid Build Coastguard Worker 	return !!(ctrl_field & (1 << ctrl->ctrl_indx));
330*49cdfc7eSAndroid Build Coastguard Worker }
331*49cdfc7eSAndroid Build Coastguard Worker 
332*49cdfc7eSAndroid Build Coastguard Worker __attribute__ ((nonnull))
add_ctrl(uint32_t * const ctrl_field,const struct cgroup_ctrl * const ctrl)333*49cdfc7eSAndroid Build Coastguard Worker static void add_ctrl(uint32_t *const ctrl_field,
334*49cdfc7eSAndroid Build Coastguard Worker 		     const struct cgroup_ctrl *const ctrl)
335*49cdfc7eSAndroid Build Coastguard Worker {
336*49cdfc7eSAndroid Build Coastguard Worker 	*ctrl_field |= 1 << ctrl->ctrl_indx;
337*49cdfc7eSAndroid Build Coastguard Worker }
338*49cdfc7eSAndroid Build Coastguard Worker 
cgroup_v2_mounted(void)339*49cdfc7eSAndroid Build Coastguard Worker static int cgroup_v2_mounted(void)
340*49cdfc7eSAndroid Build Coastguard Worker {
341*49cdfc7eSAndroid Build Coastguard Worker 	return !!roots[0].ver;
342*49cdfc7eSAndroid Build Coastguard Worker }
343*49cdfc7eSAndroid Build Coastguard Worker 
cgroup_v1_mounted(void)344*49cdfc7eSAndroid Build Coastguard Worker static int cgroup_v1_mounted(void)
345*49cdfc7eSAndroid Build Coastguard Worker {
346*49cdfc7eSAndroid Build Coastguard Worker 	return !!roots[1].ver;
347*49cdfc7eSAndroid Build Coastguard Worker }
348*49cdfc7eSAndroid Build Coastguard Worker 
cgroup_v2_nsdelegate(void)349*49cdfc7eSAndroid Build Coastguard Worker static int cgroup_v2_nsdelegate(void)
350*49cdfc7eSAndroid Build Coastguard Worker {
351*49cdfc7eSAndroid Build Coastguard Worker 	return !!roots[0].nsdelegate;
352*49cdfc7eSAndroid Build Coastguard Worker }
353*49cdfc7eSAndroid Build Coastguard Worker 
cgroup_mounted(void)354*49cdfc7eSAndroid Build Coastguard Worker static int cgroup_mounted(void)
355*49cdfc7eSAndroid Build Coastguard Worker {
356*49cdfc7eSAndroid Build Coastguard Worker 	return cgroup_v2_mounted() || cgroup_v1_mounted();
357*49cdfc7eSAndroid Build Coastguard Worker }
358*49cdfc7eSAndroid Build Coastguard Worker 
359*49cdfc7eSAndroid Build Coastguard Worker __attribute__ ((nonnull, warn_unused_result))
cgroup_ctrl_on_v2(const struct cgroup_ctrl * const ctrl)360*49cdfc7eSAndroid Build Coastguard Worker static int cgroup_ctrl_on_v2(const struct cgroup_ctrl *const ctrl)
361*49cdfc7eSAndroid Build Coastguard Worker {
362*49cdfc7eSAndroid Build Coastguard Worker 	return ctrl->ctrl_root && ctrl->ctrl_root->ver == TST_CG_V2;
363*49cdfc7eSAndroid Build Coastguard Worker }
364*49cdfc7eSAndroid Build Coastguard Worker 
365*49cdfc7eSAndroid Build Coastguard Worker __attribute__ ((nonnull))
cgroup_dir_mk(const struct cgroup_dir * const parent,const char * const dir_name,struct cgroup_dir * const new)366*49cdfc7eSAndroid Build Coastguard Worker static void cgroup_dir_mk(const struct cgroup_dir *const parent,
367*49cdfc7eSAndroid Build Coastguard Worker 			  const char *const dir_name,
368*49cdfc7eSAndroid Build Coastguard Worker 			  struct cgroup_dir *const new)
369*49cdfc7eSAndroid Build Coastguard Worker {
370*49cdfc7eSAndroid Build Coastguard Worker 	const char *dpath;
371*49cdfc7eSAndroid Build Coastguard Worker 	mode_t old_umask = umask(0);
372*49cdfc7eSAndroid Build Coastguard Worker 
373*49cdfc7eSAndroid Build Coastguard Worker 	new->dir_root = parent->dir_root;
374*49cdfc7eSAndroid Build Coastguard Worker 	new->dir_name = dir_name;
375*49cdfc7eSAndroid Build Coastguard Worker 	new->dir_parent = parent;
376*49cdfc7eSAndroid Build Coastguard Worker 	new->ctrl_field = parent->ctrl_field;
377*49cdfc7eSAndroid Build Coastguard Worker 	new->we_created_it = 0;
378*49cdfc7eSAndroid Build Coastguard Worker 
379*49cdfc7eSAndroid Build Coastguard Worker 	if (!mkdirat(parent->dir_fd, dir_name, 0777)) {
380*49cdfc7eSAndroid Build Coastguard Worker 		new->we_created_it = 1;
381*49cdfc7eSAndroid Build Coastguard Worker 		goto opendir;
382*49cdfc7eSAndroid Build Coastguard Worker 	}
383*49cdfc7eSAndroid Build Coastguard Worker 
384*49cdfc7eSAndroid Build Coastguard Worker 	if (errno == EEXIST)
385*49cdfc7eSAndroid Build Coastguard Worker 		goto opendir;
386*49cdfc7eSAndroid Build Coastguard Worker 
387*49cdfc7eSAndroid Build Coastguard Worker 	dpath = tst_decode_fd(parent->dir_fd);
388*49cdfc7eSAndroid Build Coastguard Worker 
389*49cdfc7eSAndroid Build Coastguard Worker 	if (errno == EACCES) {
390*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TCONF | TERRNO,
391*49cdfc7eSAndroid Build Coastguard Worker 			"Lack permission to make '%s/%s'; premake it or run as root",
392*49cdfc7eSAndroid Build Coastguard Worker 			dpath, dir_name);
393*49cdfc7eSAndroid Build Coastguard Worker 	} else if (errno == EROFS) {
394*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TCONF | TERRNO, "'%s/%s' must not be read-only",
395*49cdfc7eSAndroid Build Coastguard Worker 			dpath, dir_name);
396*49cdfc7eSAndroid Build Coastguard Worker 	} else {
397*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TERRNO,
398*49cdfc7eSAndroid Build Coastguard Worker 			"mkdirat(%d<%s>, '%s', 0777)",
399*49cdfc7eSAndroid Build Coastguard Worker 			parent->dir_fd, dpath, dir_name);
400*49cdfc7eSAndroid Build Coastguard Worker 	}
401*49cdfc7eSAndroid Build Coastguard Worker 
402*49cdfc7eSAndroid Build Coastguard Worker opendir:
403*49cdfc7eSAndroid Build Coastguard Worker 	new->dir_fd = SAFE_OPENAT(parent->dir_fd, dir_name,
404*49cdfc7eSAndroid Build Coastguard Worker 				  O_PATH | O_DIRECTORY);
405*49cdfc7eSAndroid Build Coastguard Worker 	umask(old_umask);
406*49cdfc7eSAndroid Build Coastguard Worker }
407*49cdfc7eSAndroid Build Coastguard Worker 
408*49cdfc7eSAndroid Build Coastguard Worker #define PATH_MAX_STRLEN 4095
409*49cdfc7eSAndroid Build Coastguard Worker #define CONFIG_HEADER "ctrl_name ver we_require_it mnt_path we_mounted_it ltp_dir.we_created_it test_dir.dir_name"
410*49cdfc7eSAndroid Build Coastguard Worker #define CONFIG_FORMAT "%" TST_TO_STR(CTRL_NAME_MAX) "s\t%d\t%d\t%" TST_TO_STR(PATH_MAX_STRLEN) "s\t%d\t%d\t%" TST_TO_STR(NAME_MAX) "s"
411*49cdfc7eSAndroid Build Coastguard Worker /* Prints out the state associated with each controller to be consumed by
412*49cdfc7eSAndroid Build Coastguard Worker  * tst_cg_load_config.
413*49cdfc7eSAndroid Build Coastguard Worker  *
414*49cdfc7eSAndroid Build Coastguard Worker  * The config keeps track of the minimal state needed for tst_cg_cleanup
415*49cdfc7eSAndroid Build Coastguard Worker  * to cleanup mounts and directories made by tst_cg_require.
416*49cdfc7eSAndroid Build Coastguard Worker  */
tst_cg_print_config(void)417*49cdfc7eSAndroid Build Coastguard Worker void tst_cg_print_config(void)
418*49cdfc7eSAndroid Build Coastguard Worker {
419*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_ctrl *ctrl;
420*49cdfc7eSAndroid Build Coastguard Worker 
421*49cdfc7eSAndroid Build Coastguard Worker 	printf("%s\n", CONFIG_HEADER);
422*49cdfc7eSAndroid Build Coastguard Worker 
423*49cdfc7eSAndroid Build Coastguard Worker 	for_each_ctrl(ctrl) {
424*49cdfc7eSAndroid Build Coastguard Worker 		struct cgroup_root *root = ctrl->ctrl_root;
425*49cdfc7eSAndroid Build Coastguard Worker 
426*49cdfc7eSAndroid Build Coastguard Worker 		if (!root)
427*49cdfc7eSAndroid Build Coastguard Worker 			continue;
428*49cdfc7eSAndroid Build Coastguard Worker 
429*49cdfc7eSAndroid Build Coastguard Worker 		printf("%s\t%d\t%d\t%s\t%d\t%d\t%s\n",
430*49cdfc7eSAndroid Build Coastguard Worker 			ctrl->ctrl_name,
431*49cdfc7eSAndroid Build Coastguard Worker 			root->ver,
432*49cdfc7eSAndroid Build Coastguard Worker 			ctrl->we_require_it,
433*49cdfc7eSAndroid Build Coastguard Worker 			root->mnt_path,
434*49cdfc7eSAndroid Build Coastguard Worker 			root->we_mounted_it,
435*49cdfc7eSAndroid Build Coastguard Worker 			root->ltp_dir.we_created_it,
436*49cdfc7eSAndroid Build Coastguard Worker 			root->test_dir.dir_name ? root->test_dir.dir_name : "NULL");
437*49cdfc7eSAndroid Build Coastguard Worker 	}
438*49cdfc7eSAndroid Build Coastguard Worker }
439*49cdfc7eSAndroid Build Coastguard Worker 
440*49cdfc7eSAndroid Build Coastguard Worker __attribute__ ((nonnull, warn_unused_result))
cgroup_find_ctrl(const char * const ctrl_name,unsigned int strict)441*49cdfc7eSAndroid Build Coastguard Worker static struct cgroup_ctrl *cgroup_find_ctrl(const char *const ctrl_name,
442*49cdfc7eSAndroid Build Coastguard Worker 					    unsigned int strict)
443*49cdfc7eSAndroid Build Coastguard Worker {
444*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_ctrl *ctrl;
445*49cdfc7eSAndroid Build Coastguard Worker 	int l = 0;
446*49cdfc7eSAndroid Build Coastguard Worker 	char c = ctrl_name[l];
447*49cdfc7eSAndroid Build Coastguard Worker 
448*49cdfc7eSAndroid Build Coastguard Worker 	while (c == '_' || (c >= 'a' && c <= 'z'))
449*49cdfc7eSAndroid Build Coastguard Worker 		c = ctrl_name[++l];
450*49cdfc7eSAndroid Build Coastguard Worker 
451*49cdfc7eSAndroid Build Coastguard Worker 	if (l > 32 && strict)
452*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TWARN, "Subsys name len greater than max known value of MAX_CGROUP_TYPE_NAMELEN: %d > 32", l);
453*49cdfc7eSAndroid Build Coastguard Worker 
454*49cdfc7eSAndroid Build Coastguard Worker 	if (!(c == '\n' || c == '\0')) {
455*49cdfc7eSAndroid Build Coastguard Worker 		if (!strict)
456*49cdfc7eSAndroid Build Coastguard Worker 			return NULL;
457*49cdfc7eSAndroid Build Coastguard Worker 
458*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "Unexpected char in %s: %c", ctrl_name, c);
459*49cdfc7eSAndroid Build Coastguard Worker 	}
460*49cdfc7eSAndroid Build Coastguard Worker 
461*49cdfc7eSAndroid Build Coastguard Worker 	for_each_ctrl(ctrl) {
462*49cdfc7eSAndroid Build Coastguard Worker 		if (!strncmp(ctrl_name, ctrl->ctrl_name, l))
463*49cdfc7eSAndroid Build Coastguard Worker 			return ctrl;
464*49cdfc7eSAndroid Build Coastguard Worker 	}
465*49cdfc7eSAndroid Build Coastguard Worker 
466*49cdfc7eSAndroid Build Coastguard Worker 	return NULL;
467*49cdfc7eSAndroid Build Coastguard Worker }
468*49cdfc7eSAndroid Build Coastguard Worker 
cgroup_find_root(const char * const mnt_path)469*49cdfc7eSAndroid Build Coastguard Worker static struct cgroup_root *cgroup_find_root(const char *const mnt_path)
470*49cdfc7eSAndroid Build Coastguard Worker {
471*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_root *root;
472*49cdfc7eSAndroid Build Coastguard Worker 
473*49cdfc7eSAndroid Build Coastguard Worker 	for_each_root(root) {
474*49cdfc7eSAndroid Build Coastguard Worker 		if (!strcmp(root->mnt_path, mnt_path))
475*49cdfc7eSAndroid Build Coastguard Worker 			return root;
476*49cdfc7eSAndroid Build Coastguard Worker 	}
477*49cdfc7eSAndroid Build Coastguard Worker 
478*49cdfc7eSAndroid Build Coastguard Worker 	return NULL;
479*49cdfc7eSAndroid Build Coastguard Worker }
480*49cdfc7eSAndroid Build Coastguard Worker 
cgroup_parse_config_line(const char * const config_entry)481*49cdfc7eSAndroid Build Coastguard Worker static void cgroup_parse_config_line(const char *const config_entry)
482*49cdfc7eSAndroid Build Coastguard Worker {
483*49cdfc7eSAndroid Build Coastguard Worker 	char ctrl_name[CTRL_NAME_MAX + 1], mnt_path[PATH_MAX_STRLEN + 1], test_dir_name[NAME_MAX + 1];
484*49cdfc7eSAndroid Build Coastguard Worker 	int ver, we_require_it, we_mounted_it, ltp_dir_we_created_it, vars_read;
485*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_root *root;
486*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_ctrl *ctrl;
487*49cdfc7eSAndroid Build Coastguard Worker 
488*49cdfc7eSAndroid Build Coastguard Worker 	vars_read = sscanf(config_entry, CONFIG_FORMAT,
489*49cdfc7eSAndroid Build Coastguard Worker 		ctrl_name, &ver, &we_require_it, mnt_path, &we_mounted_it,
490*49cdfc7eSAndroid Build Coastguard Worker 		&ltp_dir_we_created_it, test_dir_name);
491*49cdfc7eSAndroid Build Coastguard Worker 
492*49cdfc7eSAndroid Build Coastguard Worker 	if (vars_read != 7)
493*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "Incorrect number of vars read from config. Config possibly malformed?");
494*49cdfc7eSAndroid Build Coastguard Worker 
495*49cdfc7eSAndroid Build Coastguard Worker 	ctrl = cgroup_find_ctrl(ctrl_name, 1);
496*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctrl)
497*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "Could not find ctrl from config. Ctrls changing between calls?");
498*49cdfc7eSAndroid Build Coastguard Worker 
499*49cdfc7eSAndroid Build Coastguard Worker 	ctrl->we_require_it = we_require_it;
500*49cdfc7eSAndroid Build Coastguard Worker 
501*49cdfc7eSAndroid Build Coastguard Worker 	root = cgroup_find_root(mnt_path);
502*49cdfc7eSAndroid Build Coastguard Worker 	if (!root)
503*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "Could not find root from config. Config possibly malformed?");
504*49cdfc7eSAndroid Build Coastguard Worker 
505*49cdfc7eSAndroid Build Coastguard Worker 	if (we_mounted_it)
506*49cdfc7eSAndroid Build Coastguard Worker 		root->we_mounted_it = 1;
507*49cdfc7eSAndroid Build Coastguard Worker 
508*49cdfc7eSAndroid Build Coastguard Worker 	if (!root->ltp_dir.dir_name) {
509*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_dir_mk(&root->mnt_dir, cgroup_ltp_dir, &root->ltp_dir);
510*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_dir_mk(&root->ltp_dir, cgroup_ltp_drain_dir, &root->drain_dir);
511*49cdfc7eSAndroid Build Coastguard Worker 		if (ltp_dir_we_created_it) {
512*49cdfc7eSAndroid Build Coastguard Worker 			root->ltp_dir.we_created_it = 1;
513*49cdfc7eSAndroid Build Coastguard Worker 			root->drain_dir.we_created_it = 1;
514*49cdfc7eSAndroid Build Coastguard Worker 		}
515*49cdfc7eSAndroid Build Coastguard Worker 	}
516*49cdfc7eSAndroid Build Coastguard Worker 
517*49cdfc7eSAndroid Build Coastguard Worker 	if (!root->test_dir.dir_name && strcmp(test_dir_name, "NULL")) {
518*49cdfc7eSAndroid Build Coastguard Worker 		strncpy(cgroup_test_dir, test_dir_name, NAME_MAX + 1);
519*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_dir_mk(&root->ltp_dir, cgroup_test_dir, &root->test_dir);
520*49cdfc7eSAndroid Build Coastguard Worker 		root->test_dir.we_created_it = 1;
521*49cdfc7eSAndroid Build Coastguard Worker 	}
522*49cdfc7eSAndroid Build Coastguard Worker }
523*49cdfc7eSAndroid Build Coastguard Worker 
524*49cdfc7eSAndroid Build Coastguard Worker /* Load the test state config provided by tst_cg_print_config
525*49cdfc7eSAndroid Build Coastguard Worker  *
526*49cdfc7eSAndroid Build Coastguard Worker  * This will reload some internal tst_cgroup state given by the config
527*49cdfc7eSAndroid Build Coastguard Worker  * that might otherwise have been lost between calls or between different
528*49cdfc7eSAndroid Build Coastguard Worker  * processes. In particular this is used by testcases/lib/tst_cgctl to
529*49cdfc7eSAndroid Build Coastguard Worker  * provide access to this C api to shell scripts.
530*49cdfc7eSAndroid Build Coastguard Worker  *
531*49cdfc7eSAndroid Build Coastguard Worker  * The config keeps track of the minimal state needed for tst_cg_cleanup
532*49cdfc7eSAndroid Build Coastguard Worker  * to cleanup mounts and directories created by tst_cg_require.
533*49cdfc7eSAndroid Build Coastguard Worker  */
tst_cg_load_config(const char * const config)534*49cdfc7eSAndroid Build Coastguard Worker void tst_cg_load_config(const char *const config)
535*49cdfc7eSAndroid Build Coastguard Worker {
536*49cdfc7eSAndroid Build Coastguard Worker 	char temp_config[BUFSIZ];
537*49cdfc7eSAndroid Build Coastguard Worker 	char *line;
538*49cdfc7eSAndroid Build Coastguard Worker 	const size_t config_len = strlen(config) + 1;
539*49cdfc7eSAndroid Build Coastguard Worker 
540*49cdfc7eSAndroid Build Coastguard Worker 	if (config_len >= BUFSIZ)
541*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "Config has exceeded buffer size?");
542*49cdfc7eSAndroid Build Coastguard Worker 
543*49cdfc7eSAndroid Build Coastguard Worker 	memcpy(temp_config, config, config_len);
544*49cdfc7eSAndroid Build Coastguard Worker 	temp_config[config_len] = '\0';
545*49cdfc7eSAndroid Build Coastguard Worker 
546*49cdfc7eSAndroid Build Coastguard Worker 	line = strtok(temp_config, "\n");
547*49cdfc7eSAndroid Build Coastguard Worker 	/* Make sure to consume the header. */
548*49cdfc7eSAndroid Build Coastguard Worker 	for (line = strtok(NULL, "\n"); line; line = strtok(NULL, "\n"))
549*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_parse_config_line(line);
550*49cdfc7eSAndroid Build Coastguard Worker }
551*49cdfc7eSAndroid Build Coastguard Worker 
552*49cdfc7eSAndroid Build Coastguard Worker /* Determine if a mounted cgroup hierarchy is unique and record it if so.
553*49cdfc7eSAndroid Build Coastguard Worker  *
554*49cdfc7eSAndroid Build Coastguard Worker  * For CGroups V2 this is very simple as there is only one
555*49cdfc7eSAndroid Build Coastguard Worker  * hierarchy. We just record which controllers are available and check
556*49cdfc7eSAndroid Build Coastguard Worker  * if this matches what we read from any previous mount points.
557*49cdfc7eSAndroid Build Coastguard Worker  *
558*49cdfc7eSAndroid Build Coastguard Worker  * For V1 the set of controllers S is partitioned into sets {P_1, P_2,
559*49cdfc7eSAndroid Build Coastguard Worker  * ..., P_n} with one or more controllers in each partion. Each
560*49cdfc7eSAndroid Build Coastguard Worker  * partition P_n can be mounted multiple times, but the same
561*49cdfc7eSAndroid Build Coastguard Worker  * controller can not appear in more than one partition. Usually each
562*49cdfc7eSAndroid Build Coastguard Worker  * partition contains a single controller, but, for example, cpu and
563*49cdfc7eSAndroid Build Coastguard Worker  * cpuacct are often mounted together in the same partiion.
564*49cdfc7eSAndroid Build Coastguard Worker  *
565*49cdfc7eSAndroid Build Coastguard Worker  * Each controller partition has its own hierarchy (root) which we
566*49cdfc7eSAndroid Build Coastguard Worker  * must track and update independently.
567*49cdfc7eSAndroid Build Coastguard Worker  */
568*49cdfc7eSAndroid Build Coastguard Worker __attribute__ ((nonnull))
cgroup_root_scan(const char * const mnt_type,const char * const mnt_dir,char * const mnt_opts)569*49cdfc7eSAndroid Build Coastguard Worker static void cgroup_root_scan(const char *const mnt_type,
570*49cdfc7eSAndroid Build Coastguard Worker 			     const char *const mnt_dir,
571*49cdfc7eSAndroid Build Coastguard Worker 			     char *const mnt_opts)
572*49cdfc7eSAndroid Build Coastguard Worker {
573*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_root *root = roots;
574*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_ctrl *const_ctrl;
575*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_ctrl *ctrl;
576*49cdfc7eSAndroid Build Coastguard Worker 	uint32_t ctrl_field = 0;
577*49cdfc7eSAndroid Build Coastguard Worker 	int no_prefix = 0;
578*49cdfc7eSAndroid Build Coastguard Worker 	int nsdelegate = 0;
579*49cdfc7eSAndroid Build Coastguard Worker 	char buf[BUFSIZ];
580*49cdfc7eSAndroid Build Coastguard Worker 	char *tok;
581*49cdfc7eSAndroid Build Coastguard Worker 	const int mnt_dfd = SAFE_OPEN(mnt_dir, O_PATH | O_DIRECTORY);
582*49cdfc7eSAndroid Build Coastguard Worker 
583*49cdfc7eSAndroid Build Coastguard Worker 	if (!strcmp(mnt_type, "cgroup"))
584*49cdfc7eSAndroid Build Coastguard Worker 		goto v1;
585*49cdfc7eSAndroid Build Coastguard Worker 
586*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FILE_READAT(mnt_dfd, "cgroup.controllers", buf, sizeof(buf));
587*49cdfc7eSAndroid Build Coastguard Worker 
588*49cdfc7eSAndroid Build Coastguard Worker 	for (tok = strtok(buf, " "); tok; tok = strtok(NULL, " ")) {
589*49cdfc7eSAndroid Build Coastguard Worker 		const_ctrl = cgroup_find_ctrl(tok, 1);
590*49cdfc7eSAndroid Build Coastguard Worker 		if (const_ctrl)
591*49cdfc7eSAndroid Build Coastguard Worker 			add_ctrl(&ctrl_field, const_ctrl);
592*49cdfc7eSAndroid Build Coastguard Worker 	}
593*49cdfc7eSAndroid Build Coastguard Worker 	for (tok = strtok(mnt_opts, ","); tok; tok = strtok(NULL, ",")) {
594*49cdfc7eSAndroid Build Coastguard Worker 		nsdelegate |= !strcmp("nsdelegate", tok);
595*49cdfc7eSAndroid Build Coastguard Worker 	}
596*49cdfc7eSAndroid Build Coastguard Worker 
597*49cdfc7eSAndroid Build Coastguard Worker 	if (root->ver && ctrl_field == root->ctrl_field)
598*49cdfc7eSAndroid Build Coastguard Worker 		goto discard;
599*49cdfc7eSAndroid Build Coastguard Worker 
600*49cdfc7eSAndroid Build Coastguard Worker 	if (root->ctrl_field)
601*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "Available V2 controllers are changing between scans?");
602*49cdfc7eSAndroid Build Coastguard Worker 
603*49cdfc7eSAndroid Build Coastguard Worker 	root->ver = TST_CG_V2;
604*49cdfc7eSAndroid Build Coastguard Worker 
605*49cdfc7eSAndroid Build Coastguard Worker 	goto backref;
606*49cdfc7eSAndroid Build Coastguard Worker 
607*49cdfc7eSAndroid Build Coastguard Worker v1:
608*49cdfc7eSAndroid Build Coastguard Worker 	for (tok = strtok(mnt_opts, ","); tok; tok = strtok(NULL, ",")) {
609*49cdfc7eSAndroid Build Coastguard Worker 		const_ctrl = cgroup_find_ctrl(tok, 0);
610*49cdfc7eSAndroid Build Coastguard Worker 		if (const_ctrl)
611*49cdfc7eSAndroid Build Coastguard Worker 			add_ctrl(&ctrl_field, const_ctrl);
612*49cdfc7eSAndroid Build Coastguard Worker 
613*49cdfc7eSAndroid Build Coastguard Worker 		no_prefix |= !strcmp("noprefix", tok);
614*49cdfc7eSAndroid Build Coastguard Worker 	}
615*49cdfc7eSAndroid Build Coastguard Worker 
616*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctrl_field)
617*49cdfc7eSAndroid Build Coastguard Worker 		goto discard;
618*49cdfc7eSAndroid Build Coastguard Worker 
619*49cdfc7eSAndroid Build Coastguard Worker 	for_each_v1_root(root) {
620*49cdfc7eSAndroid Build Coastguard Worker 		if (!(ctrl_field & root->ctrl_field))
621*49cdfc7eSAndroid Build Coastguard Worker 			continue;
622*49cdfc7eSAndroid Build Coastguard Worker 
623*49cdfc7eSAndroid Build Coastguard Worker 		if (ctrl_field == root->ctrl_field)
624*49cdfc7eSAndroid Build Coastguard Worker 			goto discard;
625*49cdfc7eSAndroid Build Coastguard Worker 
626*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK,
627*49cdfc7eSAndroid Build Coastguard Worker 			"The intersection of two distinct sets of mounted controllers should be null? "
628*49cdfc7eSAndroid Build Coastguard Worker 			"Check '%s' and '%s'", root->mnt_path, mnt_dir);
629*49cdfc7eSAndroid Build Coastguard Worker 	}
630*49cdfc7eSAndroid Build Coastguard Worker 
631*49cdfc7eSAndroid Build Coastguard Worker 	if (root >= roots + ROOTS_MAX) {
632*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK,
633*49cdfc7eSAndroid Build Coastguard Worker 			"Unique controller mounts have exceeded our limit %d?",
634*49cdfc7eSAndroid Build Coastguard Worker 			ROOTS_MAX);
635*49cdfc7eSAndroid Build Coastguard Worker 	}
636*49cdfc7eSAndroid Build Coastguard Worker 
637*49cdfc7eSAndroid Build Coastguard Worker 	root->ver = TST_CG_V1;
638*49cdfc7eSAndroid Build Coastguard Worker 
639*49cdfc7eSAndroid Build Coastguard Worker backref:
640*49cdfc7eSAndroid Build Coastguard Worker 	strcpy(root->mnt_path, mnt_dir);
641*49cdfc7eSAndroid Build Coastguard Worker 	root->mnt_dir.dir_root = root;
642*49cdfc7eSAndroid Build Coastguard Worker 	root->mnt_dir.dir_name = root->mnt_path;
643*49cdfc7eSAndroid Build Coastguard Worker 	root->mnt_dir.dir_fd = mnt_dfd;
644*49cdfc7eSAndroid Build Coastguard Worker 	root->ctrl_field = ctrl_field;
645*49cdfc7eSAndroid Build Coastguard Worker 	root->no_cpuset_prefix = no_prefix;
646*49cdfc7eSAndroid Build Coastguard Worker 	root->nsdelegate = nsdelegate;
647*49cdfc7eSAndroid Build Coastguard Worker 
648*49cdfc7eSAndroid Build Coastguard Worker 	for_each_ctrl(ctrl) {
649*49cdfc7eSAndroid Build Coastguard Worker 		if (has_ctrl(root->ctrl_field, ctrl))
650*49cdfc7eSAndroid Build Coastguard Worker 			ctrl->ctrl_root = root;
651*49cdfc7eSAndroid Build Coastguard Worker 	}
652*49cdfc7eSAndroid Build Coastguard Worker 
653*49cdfc7eSAndroid Build Coastguard Worker 	return;
654*49cdfc7eSAndroid Build Coastguard Worker 
655*49cdfc7eSAndroid Build Coastguard Worker discard:
656*49cdfc7eSAndroid Build Coastguard Worker 	close(mnt_dfd);
657*49cdfc7eSAndroid Build Coastguard Worker }
658*49cdfc7eSAndroid Build Coastguard Worker 
tst_cg_scan(void)659*49cdfc7eSAndroid Build Coastguard Worker void tst_cg_scan(void)
660*49cdfc7eSAndroid Build Coastguard Worker {
661*49cdfc7eSAndroid Build Coastguard Worker 	struct mntent *mnt;
662*49cdfc7eSAndroid Build Coastguard Worker 	FILE *f = setmntent("/proc/self/mounts", "r");
663*49cdfc7eSAndroid Build Coastguard Worker 
664*49cdfc7eSAndroid Build Coastguard Worker 	if (!f) {
665*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TERRNO, "Can't open /proc/self/mounts");
666*49cdfc7eSAndroid Build Coastguard Worker 		return;
667*49cdfc7eSAndroid Build Coastguard Worker 	}
668*49cdfc7eSAndroid Build Coastguard Worker 
669*49cdfc7eSAndroid Build Coastguard Worker 	mnt = getmntent(f);
670*49cdfc7eSAndroid Build Coastguard Worker 	if (!mnt) {
671*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TERRNO, "Can't read mounts or no mounts?");
672*49cdfc7eSAndroid Build Coastguard Worker 		return;
673*49cdfc7eSAndroid Build Coastguard Worker 	}
674*49cdfc7eSAndroid Build Coastguard Worker 
675*49cdfc7eSAndroid Build Coastguard Worker 	do {
676*49cdfc7eSAndroid Build Coastguard Worker 		if (strncmp(mnt->mnt_type, "cgroup", 6))
677*49cdfc7eSAndroid Build Coastguard Worker 			continue;
678*49cdfc7eSAndroid Build Coastguard Worker 
679*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_root_scan(mnt->mnt_type, mnt->mnt_dir, mnt->mnt_opts);
680*49cdfc7eSAndroid Build Coastguard Worker 	} while ((mnt = getmntent(f)));
681*49cdfc7eSAndroid Build Coastguard Worker }
682*49cdfc7eSAndroid Build Coastguard Worker 
cgroup_mount_v2(void)683*49cdfc7eSAndroid Build Coastguard Worker static void cgroup_mount_v2(void)
684*49cdfc7eSAndroid Build Coastguard Worker {
685*49cdfc7eSAndroid Build Coastguard Worker 	int ret;
686*49cdfc7eSAndroid Build Coastguard Worker 	char mnt_path[PATH_MAX];
687*49cdfc7eSAndroid Build Coastguard Worker 	const char *tmpdir = tst_get_tmpdir_root();
688*49cdfc7eSAndroid Build Coastguard Worker 
689*49cdfc7eSAndroid Build Coastguard Worker 	sprintf(mnt_path, "%s/%s%s",
690*49cdfc7eSAndroid Build Coastguard Worker 		tmpdir, cgroup_mount_ltp_prefix, cgroup_v2_ltp_mount);
691*49cdfc7eSAndroid Build Coastguard Worker 
692*49cdfc7eSAndroid Build Coastguard Worker 	if (!mkdir(mnt_path, 0777)) {
693*49cdfc7eSAndroid Build Coastguard Worker 		roots[0].mnt_dir.we_created_it = 1;
694*49cdfc7eSAndroid Build Coastguard Worker 		goto mount;
695*49cdfc7eSAndroid Build Coastguard Worker 	}
696*49cdfc7eSAndroid Build Coastguard Worker 
697*49cdfc7eSAndroid Build Coastguard Worker 	if (errno == EEXIST)
698*49cdfc7eSAndroid Build Coastguard Worker 		goto mount;
699*49cdfc7eSAndroid Build Coastguard Worker 
700*49cdfc7eSAndroid Build Coastguard Worker 	if (errno == EACCES) {
701*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO | TERRNO,
702*49cdfc7eSAndroid Build Coastguard Worker 			"Lack permission to make %s, premake it or run as root",
703*49cdfc7eSAndroid Build Coastguard Worker 			mnt_path);
704*49cdfc7eSAndroid Build Coastguard Worker 		return;
705*49cdfc7eSAndroid Build Coastguard Worker 	}
706*49cdfc7eSAndroid Build Coastguard Worker 
707*49cdfc7eSAndroid Build Coastguard Worker 	tst_brk(TBROK | TERRNO, "mkdir(%s, 0777)", mnt_path);
708*49cdfc7eSAndroid Build Coastguard Worker 	return;
709*49cdfc7eSAndroid Build Coastguard Worker 
710*49cdfc7eSAndroid Build Coastguard Worker mount:
711*49cdfc7eSAndroid Build Coastguard Worker 	ret = mount("cgroup2", mnt_path, "cgroup2",
712*49cdfc7eSAndroid Build Coastguard Worker 		    0, "memory_recursiveprot");
713*49cdfc7eSAndroid Build Coastguard Worker 
714*49cdfc7eSAndroid Build Coastguard Worker 	if (ret && errno == EINVAL)
715*49cdfc7eSAndroid Build Coastguard Worker 		ret = mount("cgroup2", mnt_path, "cgroup2", 0, NULL);
716*49cdfc7eSAndroid Build Coastguard Worker 
717*49cdfc7eSAndroid Build Coastguard Worker 	if (!ret) {
718*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "Mounted V2 CGroups on %s", mnt_path);
719*49cdfc7eSAndroid Build Coastguard Worker 		tst_cg_scan();
720*49cdfc7eSAndroid Build Coastguard Worker 		roots[0].we_mounted_it = 1;
721*49cdfc7eSAndroid Build Coastguard Worker 		return;
722*49cdfc7eSAndroid Build Coastguard Worker 	}
723*49cdfc7eSAndroid Build Coastguard Worker 
724*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO | TERRNO, "Could not mount V2 CGroups on %s", mnt_path);
725*49cdfc7eSAndroid Build Coastguard Worker 
726*49cdfc7eSAndroid Build Coastguard Worker 	if (roots[0].mnt_dir.we_created_it) {
727*49cdfc7eSAndroid Build Coastguard Worker 		roots[0].mnt_dir.we_created_it = 0;
728*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_RMDIR(mnt_path);
729*49cdfc7eSAndroid Build Coastguard Worker 	}
730*49cdfc7eSAndroid Build Coastguard Worker }
731*49cdfc7eSAndroid Build Coastguard Worker 
732*49cdfc7eSAndroid Build Coastguard Worker __attribute__ ((nonnull))
cgroup_mount_v1(struct cgroup_ctrl * const ctrl)733*49cdfc7eSAndroid Build Coastguard Worker static void cgroup_mount_v1(struct cgroup_ctrl *const ctrl)
734*49cdfc7eSAndroid Build Coastguard Worker {
735*49cdfc7eSAndroid Build Coastguard Worker 	char mnt_path[PATH_MAX];
736*49cdfc7eSAndroid Build Coastguard Worker 	int made_dir = 0;
737*49cdfc7eSAndroid Build Coastguard Worker 	const char *tmpdir = tst_get_tmpdir_root();
738*49cdfc7eSAndroid Build Coastguard Worker 
739*49cdfc7eSAndroid Build Coastguard Worker 	if (ctrl->ctrl_indx == CTRL_BLKIO && controllers[CTRL_IO].ctrl_root) {
740*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TCONF,
741*49cdfc7eSAndroid Build Coastguard Worker 			"IO controller found on V2 root, skipping blkio mount that would unmount IO controller");
742*49cdfc7eSAndroid Build Coastguard Worker 		return;
743*49cdfc7eSAndroid Build Coastguard Worker 	}
744*49cdfc7eSAndroid Build Coastguard Worker 
745*49cdfc7eSAndroid Build Coastguard Worker 	sprintf(mnt_path, "%s/%s%s",
746*49cdfc7eSAndroid Build Coastguard Worker 		tmpdir, cgroup_mount_ltp_prefix, ctrl->ctrl_name);
747*49cdfc7eSAndroid Build Coastguard Worker 
748*49cdfc7eSAndroid Build Coastguard Worker 	if (!mkdir(mnt_path, 0777)) {
749*49cdfc7eSAndroid Build Coastguard Worker 		made_dir = 1;
750*49cdfc7eSAndroid Build Coastguard Worker 		goto mount;
751*49cdfc7eSAndroid Build Coastguard Worker 	}
752*49cdfc7eSAndroid Build Coastguard Worker 
753*49cdfc7eSAndroid Build Coastguard Worker 	if (errno == EEXIST)
754*49cdfc7eSAndroid Build Coastguard Worker 		goto mount;
755*49cdfc7eSAndroid Build Coastguard Worker 
756*49cdfc7eSAndroid Build Coastguard Worker 	if (errno == EACCES) {
757*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO | TERRNO,
758*49cdfc7eSAndroid Build Coastguard Worker 			"Lack permission to make %s, premake it or run as root",
759*49cdfc7eSAndroid Build Coastguard Worker 			mnt_path);
760*49cdfc7eSAndroid Build Coastguard Worker 		return;
761*49cdfc7eSAndroid Build Coastguard Worker 	}
762*49cdfc7eSAndroid Build Coastguard Worker 
763*49cdfc7eSAndroid Build Coastguard Worker 	tst_brk(TBROK | TERRNO, "mkdir(%s, 0777)", mnt_path);
764*49cdfc7eSAndroid Build Coastguard Worker 	return;
765*49cdfc7eSAndroid Build Coastguard Worker 
766*49cdfc7eSAndroid Build Coastguard Worker mount:
767*49cdfc7eSAndroid Build Coastguard Worker 	if (mount(ctrl->ctrl_name, mnt_path, "cgroup", 0, ctrl->ctrl_name)) {
768*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO | TERRNO,
769*49cdfc7eSAndroid Build Coastguard Worker 			"Could not mount V1 CGroup on %s", mnt_path);
770*49cdfc7eSAndroid Build Coastguard Worker 
771*49cdfc7eSAndroid Build Coastguard Worker 		if (made_dir)
772*49cdfc7eSAndroid Build Coastguard Worker 			SAFE_RMDIR(mnt_path);
773*49cdfc7eSAndroid Build Coastguard Worker 		return;
774*49cdfc7eSAndroid Build Coastguard Worker 	}
775*49cdfc7eSAndroid Build Coastguard Worker 
776*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "Mounted V1 %s CGroup on %s", ctrl->ctrl_name, mnt_path);
777*49cdfc7eSAndroid Build Coastguard Worker 	tst_cg_scan();
778*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctrl->ctrl_root)
779*49cdfc7eSAndroid Build Coastguard Worker 		return;
780*49cdfc7eSAndroid Build Coastguard Worker 
781*49cdfc7eSAndroid Build Coastguard Worker 	ctrl->ctrl_root->we_mounted_it = 1;
782*49cdfc7eSAndroid Build Coastguard Worker 	ctrl->ctrl_root->mnt_dir.we_created_it = made_dir;
783*49cdfc7eSAndroid Build Coastguard Worker 
784*49cdfc7eSAndroid Build Coastguard Worker 	if (ctrl->ctrl_indx == CTRL_MEMORY) {
785*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_FILE_PRINTFAT(ctrl->ctrl_root->mnt_dir.dir_fd,
786*49cdfc7eSAndroid Build Coastguard Worker 				   "memory.use_hierarchy", "%d", 1);
787*49cdfc7eSAndroid Build Coastguard Worker 	}
788*49cdfc7eSAndroid Build Coastguard Worker }
789*49cdfc7eSAndroid Build Coastguard Worker 
790*49cdfc7eSAndroid Build Coastguard Worker __attribute__ ((nonnull))
cgroup_copy_cpuset(const struct cgroup_root * const root)791*49cdfc7eSAndroid Build Coastguard Worker static void cgroup_copy_cpuset(const struct cgroup_root *const root)
792*49cdfc7eSAndroid Build Coastguard Worker {
793*49cdfc7eSAndroid Build Coastguard Worker 	char knob_val[BUFSIZ];
794*49cdfc7eSAndroid Build Coastguard Worker 	int i;
795*49cdfc7eSAndroid Build Coastguard Worker 	const char *const n0[] = {"mems", "cpus"};
796*49cdfc7eSAndroid Build Coastguard Worker 	const char *const n1[] = {"cpuset.mems", "cpuset.cpus"};
797*49cdfc7eSAndroid Build Coastguard Worker 	const char *const *const fname = root->no_cpuset_prefix ? n0 : n1;
798*49cdfc7eSAndroid Build Coastguard Worker 
799*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < 2; i++) {
800*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_FILE_READAT(root->mnt_dir.dir_fd,
801*49cdfc7eSAndroid Build Coastguard Worker 				 fname[i], knob_val, sizeof(knob_val));
802*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_FILE_PRINTFAT(root->ltp_dir.dir_fd,
803*49cdfc7eSAndroid Build Coastguard Worker 				   fname[i], "%s", knob_val);
804*49cdfc7eSAndroid Build Coastguard Worker 	}
805*49cdfc7eSAndroid Build Coastguard Worker }
806*49cdfc7eSAndroid Build Coastguard Worker 
807*49cdfc7eSAndroid Build Coastguard Worker /* Ensure the specified controller is available.
808*49cdfc7eSAndroid Build Coastguard Worker  *
809*49cdfc7eSAndroid Build Coastguard Worker  * First we check if the specified controller has a known mount point,
810*49cdfc7eSAndroid Build Coastguard Worker  * if not then we scan the system. If we find it then we goto ensuring
811*49cdfc7eSAndroid Build Coastguard Worker  * the LTP group exists in the hierarchy the controller is using.
812*49cdfc7eSAndroid Build Coastguard Worker  *
813*49cdfc7eSAndroid Build Coastguard Worker  * If we can't find the controller, then we try to create it. First we
814*49cdfc7eSAndroid Build Coastguard Worker  * check if the V2 hierarchy/tree is mounted. If it isn't then we try
815*49cdfc7eSAndroid Build Coastguard Worker  * mounting it and look for the controller. If it is already mounted
816*49cdfc7eSAndroid Build Coastguard Worker  * then we know the controller is not available on V2 on this system.
817*49cdfc7eSAndroid Build Coastguard Worker  *
818*49cdfc7eSAndroid Build Coastguard Worker  * If we can't mount V2 or the controller is not on V2, then we try
819*49cdfc7eSAndroid Build Coastguard Worker  * mounting it on its own V1 tree.
820*49cdfc7eSAndroid Build Coastguard Worker  *
821*49cdfc7eSAndroid Build Coastguard Worker  * Once we have mounted the controller somehow, we create a hierarchy
822*49cdfc7eSAndroid Build Coastguard Worker  * of cgroups. If we are on V2 we first need to enable the controller
823*49cdfc7eSAndroid Build Coastguard Worker  * for all children of root. Then we create hierarchy described in
824*49cdfc7eSAndroid Build Coastguard Worker  * tst_cgroup.h.
825*49cdfc7eSAndroid Build Coastguard Worker  *
826*49cdfc7eSAndroid Build Coastguard Worker  * If we are using V1 cpuset then we copy the available mems and cpus
827*49cdfc7eSAndroid Build Coastguard Worker  * from root to the ltp group and set clone_children on the ltp group
828*49cdfc7eSAndroid Build Coastguard Worker  * to distribute these settings to the test cgroups. This means the
829*49cdfc7eSAndroid Build Coastguard Worker  * test author does not have to copy these settings before using the
830*49cdfc7eSAndroid Build Coastguard Worker  * cpuset.
831*49cdfc7eSAndroid Build Coastguard Worker  *
832*49cdfc7eSAndroid Build Coastguard Worker  */
tst_cg_require(const char * const ctrl_name,const struct tst_cg_opts * options)833*49cdfc7eSAndroid Build Coastguard Worker void tst_cg_require(const char *const ctrl_name,
834*49cdfc7eSAndroid Build Coastguard Worker 			const struct tst_cg_opts *options)
835*49cdfc7eSAndroid Build Coastguard Worker {
836*49cdfc7eSAndroid Build Coastguard Worker 	const char *const cgsc = "cgroup.subtree_control";
837*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_ctrl *const ctrl = cgroup_find_ctrl(ctrl_name, 1);
838*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_root *root;
839*49cdfc7eSAndroid Build Coastguard Worker 	int base = !strcmp(ctrl->ctrl_name, "base");
840*49cdfc7eSAndroid Build Coastguard Worker 
841*49cdfc7eSAndroid Build Coastguard Worker 	if (base && options->needs_ver != TST_CG_V2)
842*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TCONF, "Base control only support needs_ver TST_CG_V2!");
843*49cdfc7eSAndroid Build Coastguard Worker 
844*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctrl) {
845*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "'%s' controller is unknown to LTP", ctrl_name);
846*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "Calling %s in cleanup?", __func__);
847*49cdfc7eSAndroid Build Coastguard Worker 		return;
848*49cdfc7eSAndroid Build Coastguard Worker 	}
849*49cdfc7eSAndroid Build Coastguard Worker 
850*49cdfc7eSAndroid Build Coastguard Worker 	if (ctrl->we_require_it)
851*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TWARN, "Duplicate %s(%s, )", __func__, ctrl->ctrl_name);
852*49cdfc7eSAndroid Build Coastguard Worker 
853*49cdfc7eSAndroid Build Coastguard Worker 	ctrl->we_require_it = 1;
854*49cdfc7eSAndroid Build Coastguard Worker 
855*49cdfc7eSAndroid Build Coastguard Worker 	if (ctrl->ctrl_root)
856*49cdfc7eSAndroid Build Coastguard Worker 		goto mkdirs;
857*49cdfc7eSAndroid Build Coastguard Worker 
858*49cdfc7eSAndroid Build Coastguard Worker 	tst_cg_scan();
859*49cdfc7eSAndroid Build Coastguard Worker 
860*49cdfc7eSAndroid Build Coastguard Worker 	if (ctrl->ctrl_root)
861*49cdfc7eSAndroid Build Coastguard Worker 		goto mkdirs;
862*49cdfc7eSAndroid Build Coastguard Worker 
863*49cdfc7eSAndroid Build Coastguard Worker 	if (!cgroup_v2_mounted() && options->needs_ver != TST_CG_V1)
864*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_mount_v2();
865*49cdfc7eSAndroid Build Coastguard Worker 
866*49cdfc7eSAndroid Build Coastguard Worker 	if (ctrl->ctrl_root)
867*49cdfc7eSAndroid Build Coastguard Worker 		goto mkdirs;
868*49cdfc7eSAndroid Build Coastguard Worker 
869*49cdfc7eSAndroid Build Coastguard Worker 	if (options->needs_ver != TST_CG_V2)
870*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_mount_v1(ctrl);
871*49cdfc7eSAndroid Build Coastguard Worker 
872*49cdfc7eSAndroid Build Coastguard Worker 	if (base)
873*49cdfc7eSAndroid Build Coastguard Worker 		ctrl->ctrl_root = roots;
874*49cdfc7eSAndroid Build Coastguard Worker 
875*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctrl->ctrl_root) {
876*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TCONF,
877*49cdfc7eSAndroid Build Coastguard Worker 			"'%s' controller required, but not available",
878*49cdfc7eSAndroid Build Coastguard Worker 			ctrl->ctrl_name);
879*49cdfc7eSAndroid Build Coastguard Worker 		return;
880*49cdfc7eSAndroid Build Coastguard Worker 	}
881*49cdfc7eSAndroid Build Coastguard Worker 
882*49cdfc7eSAndroid Build Coastguard Worker mkdirs:
883*49cdfc7eSAndroid Build Coastguard Worker 	root = ctrl->ctrl_root;
884*49cdfc7eSAndroid Build Coastguard Worker 
885*49cdfc7eSAndroid Build Coastguard Worker 	if (options->needs_nsdelegate && cgroup_v2_mounted() && !cgroup_v2_nsdelegate())
886*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TCONF, "Requires cgroup2 to be mounted with nsdelegate");
887*49cdfc7eSAndroid Build Coastguard Worker 
888*49cdfc7eSAndroid Build Coastguard Worker 	add_ctrl(&root->mnt_dir.ctrl_field, ctrl);
889*49cdfc7eSAndroid Build Coastguard Worker 
890*49cdfc7eSAndroid Build Coastguard Worker 	if (cgroup_ctrl_on_v2(ctrl) && options->needs_ver == TST_CG_V1) {
891*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TCONF,
892*49cdfc7eSAndroid Build Coastguard Worker 			"V1 '%s' controller required, but it's mounted on V2",
893*49cdfc7eSAndroid Build Coastguard Worker 			ctrl->ctrl_name);
894*49cdfc7eSAndroid Build Coastguard Worker 	}
895*49cdfc7eSAndroid Build Coastguard Worker 	if (!cgroup_ctrl_on_v2(ctrl) && options->needs_ver == TST_CG_V2) {
896*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TCONF,
897*49cdfc7eSAndroid Build Coastguard Worker 			"V2 '%s' controller required, but it's mounted on V1",
898*49cdfc7eSAndroid Build Coastguard Worker 			ctrl->ctrl_name);
899*49cdfc7eSAndroid Build Coastguard Worker 	}
900*49cdfc7eSAndroid Build Coastguard Worker 
901*49cdfc7eSAndroid Build Coastguard Worker 	if (cgroup_ctrl_on_v2(ctrl) && !base) {
902*49cdfc7eSAndroid Build Coastguard Worker 		if (root->we_mounted_it) {
903*49cdfc7eSAndroid Build Coastguard Worker 			SAFE_FILE_PRINTFAT(root->mnt_dir.dir_fd,
904*49cdfc7eSAndroid Build Coastguard Worker 					   cgsc, "+%s", ctrl->ctrl_name);
905*49cdfc7eSAndroid Build Coastguard Worker 		} else {
906*49cdfc7eSAndroid Build Coastguard Worker 			tst_file_printfat(root->mnt_dir.dir_fd,
907*49cdfc7eSAndroid Build Coastguard Worker 					  cgsc, "+%s", ctrl->ctrl_name);
908*49cdfc7eSAndroid Build Coastguard Worker 		}
909*49cdfc7eSAndroid Build Coastguard Worker 	}
910*49cdfc7eSAndroid Build Coastguard Worker 
911*49cdfc7eSAndroid Build Coastguard Worker 	if (!root->ltp_dir.dir_fd)
912*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_dir_mk(&root->mnt_dir, cgroup_ltp_dir, &root->ltp_dir);
913*49cdfc7eSAndroid Build Coastguard Worker 	else
914*49cdfc7eSAndroid Build Coastguard Worker 		root->ltp_dir.ctrl_field |= root->mnt_dir.ctrl_field;
915*49cdfc7eSAndroid Build Coastguard Worker 
916*49cdfc7eSAndroid Build Coastguard Worker 	if (!base) {
917*49cdfc7eSAndroid Build Coastguard Worker 		if (cgroup_ctrl_on_v2(ctrl)) {
918*49cdfc7eSAndroid Build Coastguard Worker 			SAFE_FILE_PRINTFAT(root->ltp_dir.dir_fd,
919*49cdfc7eSAndroid Build Coastguard Worker 					cgsc, "+%s", ctrl->ctrl_name);
920*49cdfc7eSAndroid Build Coastguard Worker 		} else {
921*49cdfc7eSAndroid Build Coastguard Worker 			SAFE_FILE_PRINTFAT(root->ltp_dir.dir_fd,
922*49cdfc7eSAndroid Build Coastguard Worker 					"cgroup.clone_children", "%d", 1);
923*49cdfc7eSAndroid Build Coastguard Worker 
924*49cdfc7eSAndroid Build Coastguard Worker 			if (ctrl->ctrl_indx == CTRL_CPUSET)
925*49cdfc7eSAndroid Build Coastguard Worker 				cgroup_copy_cpuset(root);
926*49cdfc7eSAndroid Build Coastguard Worker 		}
927*49cdfc7eSAndroid Build Coastguard Worker 	}
928*49cdfc7eSAndroid Build Coastguard Worker 
929*49cdfc7eSAndroid Build Coastguard Worker 	cgroup_dir_mk(&root->ltp_dir, cgroup_ltp_drain_dir, &root->drain_dir);
930*49cdfc7eSAndroid Build Coastguard Worker 
931*49cdfc7eSAndroid Build Coastguard Worker 	if (options->test_pid)
932*49cdfc7eSAndroid Build Coastguard Worker 		sprintf(cgroup_test_dir, "test-%d", options->test_pid);
933*49cdfc7eSAndroid Build Coastguard Worker 	else
934*49cdfc7eSAndroid Build Coastguard Worker 		sprintf(cgroup_test_dir, "test-%d", getpid());
935*49cdfc7eSAndroid Build Coastguard Worker 
936*49cdfc7eSAndroid Build Coastguard Worker 	cgroup_dir_mk(&root->ltp_dir, cgroup_test_dir, &root->test_dir);
937*49cdfc7eSAndroid Build Coastguard Worker }
938*49cdfc7eSAndroid Build Coastguard Worker 
cgroup_drain(const enum tst_cg_ver ver,const int source_dfd,const int dest_dfd)939*49cdfc7eSAndroid Build Coastguard Worker static void cgroup_drain(const enum tst_cg_ver ver,
940*49cdfc7eSAndroid Build Coastguard Worker 			 const int source_dfd, const int dest_dfd)
941*49cdfc7eSAndroid Build Coastguard Worker {
942*49cdfc7eSAndroid Build Coastguard Worker 	char pid_list[BUFSIZ];
943*49cdfc7eSAndroid Build Coastguard Worker 	char *tok;
944*49cdfc7eSAndroid Build Coastguard Worker 	const char *const file_name =
945*49cdfc7eSAndroid Build Coastguard Worker 		ver == TST_CG_V1 ? "tasks" : "cgroup.procs";
946*49cdfc7eSAndroid Build Coastguard Worker 	int fd;
947*49cdfc7eSAndroid Build Coastguard Worker 	ssize_t ret;
948*49cdfc7eSAndroid Build Coastguard Worker 
949*49cdfc7eSAndroid Build Coastguard Worker 	ret = SAFE_FILE_READAT(source_dfd, file_name,
950*49cdfc7eSAndroid Build Coastguard Worker 			       pid_list, sizeof(pid_list));
951*49cdfc7eSAndroid Build Coastguard Worker 	if (ret < 0)
952*49cdfc7eSAndroid Build Coastguard Worker 		return;
953*49cdfc7eSAndroid Build Coastguard Worker 
954*49cdfc7eSAndroid Build Coastguard Worker 	fd = SAFE_OPENAT(dest_dfd, file_name, O_WRONLY);
955*49cdfc7eSAndroid Build Coastguard Worker 	if (fd < 0)
956*49cdfc7eSAndroid Build Coastguard Worker 		return;
957*49cdfc7eSAndroid Build Coastguard Worker 
958*49cdfc7eSAndroid Build Coastguard Worker 	for (tok = strtok(pid_list, "\n"); tok; tok = strtok(NULL, "\n")) {
959*49cdfc7eSAndroid Build Coastguard Worker 		ret = dprintf(fd, "%s", tok);
960*49cdfc7eSAndroid Build Coastguard Worker 
961*49cdfc7eSAndroid Build Coastguard Worker 		if (ret < (ssize_t)strlen(tok))
962*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK | TERRNO, "Failed to drain %s", tok);
963*49cdfc7eSAndroid Build Coastguard Worker 	}
964*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_CLOSE(fd);
965*49cdfc7eSAndroid Build Coastguard Worker }
966*49cdfc7eSAndroid Build Coastguard Worker 
967*49cdfc7eSAndroid Build Coastguard Worker __attribute__ ((nonnull))
close_path_fds(struct cgroup_root * const root)968*49cdfc7eSAndroid Build Coastguard Worker static void close_path_fds(struct cgroup_root *const root)
969*49cdfc7eSAndroid Build Coastguard Worker {
970*49cdfc7eSAndroid Build Coastguard Worker 	if (root->test_dir.dir_fd > 0)
971*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(root->test_dir.dir_fd);
972*49cdfc7eSAndroid Build Coastguard Worker 	if (root->ltp_dir.dir_fd > 0)
973*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(root->ltp_dir.dir_fd);
974*49cdfc7eSAndroid Build Coastguard Worker 	if (root->drain_dir.dir_fd > 0)
975*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(root->drain_dir.dir_fd);
976*49cdfc7eSAndroid Build Coastguard Worker 	if (root->mnt_dir.dir_fd > 0)
977*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(root->mnt_dir.dir_fd);
978*49cdfc7eSAndroid Build Coastguard Worker }
979*49cdfc7eSAndroid Build Coastguard Worker 
980*49cdfc7eSAndroid Build Coastguard Worker /* Maybe remove CGroups used during testing and clear our data
981*49cdfc7eSAndroid Build Coastguard Worker  *
982*49cdfc7eSAndroid Build Coastguard Worker  * This will never remove CGroups we did not create to allow tests to
983*49cdfc7eSAndroid Build Coastguard Worker  * be run in parallel.
984*49cdfc7eSAndroid Build Coastguard Worker  *
985*49cdfc7eSAndroid Build Coastguard Worker  * Each test process is given its own unique CGroup. Unless we want to
986*49cdfc7eSAndroid Build Coastguard Worker  * stress test the CGroup system. We should at least remove these
987*49cdfc7eSAndroid Build Coastguard Worker  * unique per test CGroups.
988*49cdfc7eSAndroid Build Coastguard Worker  *
989*49cdfc7eSAndroid Build Coastguard Worker  * We probably also want to remove the LTP parent CGroup, although
990*49cdfc7eSAndroid Build Coastguard Worker  * this may have been created by the system manager or another test
991*49cdfc7eSAndroid Build Coastguard Worker  * (see notes on parallel testing).
992*49cdfc7eSAndroid Build Coastguard Worker  *
993*49cdfc7eSAndroid Build Coastguard Worker  * On systems with no initial CGroup setup we may try to destroy the
994*49cdfc7eSAndroid Build Coastguard Worker  * CGroup roots we mounted so that they can be recreated by another
995*49cdfc7eSAndroid Build Coastguard Worker  * test. Note that successfully unmounting a CGroup root does not
996*49cdfc7eSAndroid Build Coastguard Worker  * necessarily indicate that it was destroyed.
997*49cdfc7eSAndroid Build Coastguard Worker  *
998*49cdfc7eSAndroid Build Coastguard Worker  * The ltp/drain CGroup is required for cleaning up test CGroups when
999*49cdfc7eSAndroid Build Coastguard Worker  * we can not move them to the root CGroup. CGroups can only be
1000*49cdfc7eSAndroid Build Coastguard Worker  * removed when they have no members and only leaf or root CGroups may
1001*49cdfc7eSAndroid Build Coastguard Worker  * have processes within them. As test processes create and destroy
1002*49cdfc7eSAndroid Build Coastguard Worker  * their own CGroups they must move themselves either to root or
1003*49cdfc7eSAndroid Build Coastguard Worker  * another leaf CGroup. So we move them to drain while destroying the
1004*49cdfc7eSAndroid Build Coastguard Worker  * unique test CGroup.
1005*49cdfc7eSAndroid Build Coastguard Worker  *
1006*49cdfc7eSAndroid Build Coastguard Worker  * If we have access to root and created the LTP CGroup we then move
1007*49cdfc7eSAndroid Build Coastguard Worker  * the test process to root and destroy the drain and LTP
1008*49cdfc7eSAndroid Build Coastguard Worker  * CGroups. Otherwise we just leave the test process to die in the
1009*49cdfc7eSAndroid Build Coastguard Worker  * drain, much like many a unwanted terrapin.
1010*49cdfc7eSAndroid Build Coastguard Worker  *
1011*49cdfc7eSAndroid Build Coastguard Worker  * Finally we clear any data we have collected on CGroups. This will
1012*49cdfc7eSAndroid Build Coastguard Worker  * happen regardless of whether anything was removed.
1013*49cdfc7eSAndroid Build Coastguard Worker  */
tst_cg_cleanup(void)1014*49cdfc7eSAndroid Build Coastguard Worker void tst_cg_cleanup(void)
1015*49cdfc7eSAndroid Build Coastguard Worker {
1016*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_root *root;
1017*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_ctrl *ctrl;
1018*49cdfc7eSAndroid Build Coastguard Worker 
1019*49cdfc7eSAndroid Build Coastguard Worker 	if (!cgroup_mounted())
1020*49cdfc7eSAndroid Build Coastguard Worker 		goto clear_data;
1021*49cdfc7eSAndroid Build Coastguard Worker 
1022*49cdfc7eSAndroid Build Coastguard Worker 	for_each_root(root) {
1023*49cdfc7eSAndroid Build Coastguard Worker 		if (!root->test_dir.dir_name)
1024*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1025*49cdfc7eSAndroid Build Coastguard Worker 
1026*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_drain(root->ver,
1027*49cdfc7eSAndroid Build Coastguard Worker 			     root->test_dir.dir_fd, root->drain_dir.dir_fd);
1028*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_UNLINKAT(root->ltp_dir.dir_fd, root->test_dir.dir_name,
1029*49cdfc7eSAndroid Build Coastguard Worker 			      AT_REMOVEDIR);
1030*49cdfc7eSAndroid Build Coastguard Worker 	}
1031*49cdfc7eSAndroid Build Coastguard Worker 
1032*49cdfc7eSAndroid Build Coastguard Worker 	for_each_root(root) {
1033*49cdfc7eSAndroid Build Coastguard Worker 		if (!root->ltp_dir.we_created_it)
1034*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1035*49cdfc7eSAndroid Build Coastguard Worker 
1036*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_drain(root->ver,
1037*49cdfc7eSAndroid Build Coastguard Worker 			     root->drain_dir.dir_fd, root->mnt_dir.dir_fd);
1038*49cdfc7eSAndroid Build Coastguard Worker 
1039*49cdfc7eSAndroid Build Coastguard Worker 		if (root->drain_dir.dir_name) {
1040*49cdfc7eSAndroid Build Coastguard Worker 			SAFE_UNLINKAT(root->ltp_dir.dir_fd,
1041*49cdfc7eSAndroid Build Coastguard Worker 				      root->drain_dir.dir_name, AT_REMOVEDIR);
1042*49cdfc7eSAndroid Build Coastguard Worker 		}
1043*49cdfc7eSAndroid Build Coastguard Worker 
1044*49cdfc7eSAndroid Build Coastguard Worker 		if (root->ltp_dir.dir_name) {
1045*49cdfc7eSAndroid Build Coastguard Worker 			SAFE_UNLINKAT(root->mnt_dir.dir_fd,
1046*49cdfc7eSAndroid Build Coastguard Worker 				      root->ltp_dir.dir_name, AT_REMOVEDIR);
1047*49cdfc7eSAndroid Build Coastguard Worker 		}
1048*49cdfc7eSAndroid Build Coastguard Worker 	}
1049*49cdfc7eSAndroid Build Coastguard Worker 
1050*49cdfc7eSAndroid Build Coastguard Worker 	for_each_ctrl(ctrl) {
1051*49cdfc7eSAndroid Build Coastguard Worker 		if (!cgroup_ctrl_on_v2(ctrl) || !ctrl->ctrl_root->we_mounted_it
1052*49cdfc7eSAndroid Build Coastguard Worker 			|| !strcmp(ctrl->ctrl_name, "base"))
1053*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1054*49cdfc7eSAndroid Build Coastguard Worker 
1055*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_FILE_PRINTFAT(ctrl->ctrl_root->mnt_dir.dir_fd,
1056*49cdfc7eSAndroid Build Coastguard Worker 				   "cgroup.subtree_control",
1057*49cdfc7eSAndroid Build Coastguard Worker 				   "-%s", ctrl->ctrl_name);
1058*49cdfc7eSAndroid Build Coastguard Worker 	}
1059*49cdfc7eSAndroid Build Coastguard Worker 
1060*49cdfc7eSAndroid Build Coastguard Worker 	for_each_root(root) {
1061*49cdfc7eSAndroid Build Coastguard Worker 		if (!root->we_mounted_it)
1062*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1063*49cdfc7eSAndroid Build Coastguard Worker 
1064*49cdfc7eSAndroid Build Coastguard Worker 		/* This probably does not result in the CGroup root
1065*49cdfc7eSAndroid Build Coastguard Worker 		 * being destroyed
1066*49cdfc7eSAndroid Build Coastguard Worker 		 */
1067*49cdfc7eSAndroid Build Coastguard Worker 		if (umount2(root->mnt_path, MNT_DETACH))
1068*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1069*49cdfc7eSAndroid Build Coastguard Worker 
1070*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_RMDIR(root->mnt_path);
1071*49cdfc7eSAndroid Build Coastguard Worker 	}
1072*49cdfc7eSAndroid Build Coastguard Worker 
1073*49cdfc7eSAndroid Build Coastguard Worker clear_data:
1074*49cdfc7eSAndroid Build Coastguard Worker 	for_each_ctrl(ctrl) {
1075*49cdfc7eSAndroid Build Coastguard Worker 		ctrl->ctrl_root = NULL;
1076*49cdfc7eSAndroid Build Coastguard Worker 		ctrl->we_require_it = 0;
1077*49cdfc7eSAndroid Build Coastguard Worker 	}
1078*49cdfc7eSAndroid Build Coastguard Worker 
1079*49cdfc7eSAndroid Build Coastguard Worker 	for_each_root(root)
1080*49cdfc7eSAndroid Build Coastguard Worker 		close_path_fds(root);
1081*49cdfc7eSAndroid Build Coastguard Worker 
1082*49cdfc7eSAndroid Build Coastguard Worker 	memset(roots, 0, sizeof(roots));
1083*49cdfc7eSAndroid Build Coastguard Worker }
1084*49cdfc7eSAndroid Build Coastguard Worker 
1085*49cdfc7eSAndroid Build Coastguard Worker __attribute__((nonnull(2, 3)))
cgroup_group_add_dir(const struct tst_cg_group * const parent,struct tst_cg_group * const cg,struct cgroup_dir * const dir)1086*49cdfc7eSAndroid Build Coastguard Worker static void cgroup_group_add_dir(const struct tst_cg_group *const parent,
1087*49cdfc7eSAndroid Build Coastguard Worker 				 struct tst_cg_group *const cg,
1088*49cdfc7eSAndroid Build Coastguard Worker 				 struct cgroup_dir *const dir)
1089*49cdfc7eSAndroid Build Coastguard Worker {
1090*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_ctrl *ctrl;
1091*49cdfc7eSAndroid Build Coastguard Worker 	int i;
1092*49cdfc7eSAndroid Build Coastguard Worker 
1093*49cdfc7eSAndroid Build Coastguard Worker 	if (dir->dir_root->ver != TST_CG_V1)
1094*49cdfc7eSAndroid Build Coastguard Worker 		cg->dirs_by_ctrl[0] = dir;
1095*49cdfc7eSAndroid Build Coastguard Worker 
1096*49cdfc7eSAndroid Build Coastguard Worker 	for_each_ctrl(ctrl) {
1097*49cdfc7eSAndroid Build Coastguard Worker 		if (!has_ctrl(dir->ctrl_field, ctrl))
1098*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1099*49cdfc7eSAndroid Build Coastguard Worker 
1100*49cdfc7eSAndroid Build Coastguard Worker 		cg->dirs_by_ctrl[ctrl->ctrl_indx] = dir;
1101*49cdfc7eSAndroid Build Coastguard Worker 
1102*49cdfc7eSAndroid Build Coastguard Worker 		if (!parent || dir->dir_root->ver == TST_CG_V1)
1103*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1104*49cdfc7eSAndroid Build Coastguard Worker 
1105*49cdfc7eSAndroid Build Coastguard Worker 		if (strcmp(ctrl->ctrl_name, "base")) {
1106*49cdfc7eSAndroid Build Coastguard Worker 			SAFE_CG_PRINTF(parent, "cgroup.subtree_control",
1107*49cdfc7eSAndroid Build Coastguard Worker 					"+%s", ctrl->ctrl_name);
1108*49cdfc7eSAndroid Build Coastguard Worker 		}
1109*49cdfc7eSAndroid Build Coastguard Worker 	}
1110*49cdfc7eSAndroid Build Coastguard Worker 
1111*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; cg->dirs[i]; i++)
1112*49cdfc7eSAndroid Build Coastguard Worker 		;
1113*49cdfc7eSAndroid Build Coastguard Worker 	cg->dirs[i] = dir;
1114*49cdfc7eSAndroid Build Coastguard Worker }
1115*49cdfc7eSAndroid Build Coastguard Worker 
1116*49cdfc7eSAndroid Build Coastguard Worker struct tst_cg_group *
tst_cg_group_mk(const struct tst_cg_group * const parent,const char * const group_name_fmt,...)1117*49cdfc7eSAndroid Build Coastguard Worker tst_cg_group_mk(const struct tst_cg_group *const parent,
1118*49cdfc7eSAndroid Build Coastguard Worker 		    const char *const group_name_fmt, ...)
1119*49cdfc7eSAndroid Build Coastguard Worker {
1120*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_cg_group *cg;
1121*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir *const *dir;
1122*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir *new_dir;
1123*49cdfc7eSAndroid Build Coastguard Worker 	va_list ap;
1124*49cdfc7eSAndroid Build Coastguard Worker 	size_t name_len;
1125*49cdfc7eSAndroid Build Coastguard Worker 
1126*49cdfc7eSAndroid Build Coastguard Worker 	cg = SAFE_MALLOC(sizeof(*cg));
1127*49cdfc7eSAndroid Build Coastguard Worker 	memset(cg, 0, sizeof(*cg));
1128*49cdfc7eSAndroid Build Coastguard Worker 
1129*49cdfc7eSAndroid Build Coastguard Worker 	va_start(ap, group_name_fmt);
1130*49cdfc7eSAndroid Build Coastguard Worker 	name_len = vsnprintf(cg->group_name, NAME_MAX,
1131*49cdfc7eSAndroid Build Coastguard Worker 			     group_name_fmt, ap);
1132*49cdfc7eSAndroid Build Coastguard Worker 	va_end(ap);
1133*49cdfc7eSAndroid Build Coastguard Worker 
1134*49cdfc7eSAndroid Build Coastguard Worker 	if (name_len >= NAME_MAX)
1135*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "CGroup name is too long");
1136*49cdfc7eSAndroid Build Coastguard Worker 
1137*49cdfc7eSAndroid Build Coastguard Worker 	for_each_dir(parent, 0, dir) {
1138*49cdfc7eSAndroid Build Coastguard Worker 		new_dir = SAFE_MALLOC(sizeof(*new_dir));
1139*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_dir_mk(*dir, cg->group_name, new_dir);
1140*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_group_add_dir(parent, cg, new_dir);
1141*49cdfc7eSAndroid Build Coastguard Worker 	}
1142*49cdfc7eSAndroid Build Coastguard Worker 
1143*49cdfc7eSAndroid Build Coastguard Worker 	return cg;
1144*49cdfc7eSAndroid Build Coastguard Worker }
1145*49cdfc7eSAndroid Build Coastguard Worker 
tst_cg_group_name(const struct tst_cg_group * const cg)1146*49cdfc7eSAndroid Build Coastguard Worker const char *tst_cg_group_name(const struct tst_cg_group *const cg)
1147*49cdfc7eSAndroid Build Coastguard Worker {
1148*49cdfc7eSAndroid Build Coastguard Worker 	return cg->group_name;
1149*49cdfc7eSAndroid Build Coastguard Worker }
1150*49cdfc7eSAndroid Build Coastguard Worker 
tst_cg_group_unified_dir_fd(const struct tst_cg_group * const cg)1151*49cdfc7eSAndroid Build Coastguard Worker int tst_cg_group_unified_dir_fd(const struct tst_cg_group *const cg)
1152*49cdfc7eSAndroid Build Coastguard Worker {
1153*49cdfc7eSAndroid Build Coastguard Worker 	if(cg->dirs_by_ctrl[0])
1154*49cdfc7eSAndroid Build Coastguard Worker 		return cg->dirs_by_ctrl[0]->dir_fd;
1155*49cdfc7eSAndroid Build Coastguard Worker 
1156*49cdfc7eSAndroid Build Coastguard Worker 	return -1;
1157*49cdfc7eSAndroid Build Coastguard Worker }
1158*49cdfc7eSAndroid Build Coastguard Worker 
tst_cg_group_rm(struct tst_cg_group * const cg)1159*49cdfc7eSAndroid Build Coastguard Worker struct tst_cg_group *tst_cg_group_rm(struct tst_cg_group *const cg)
1160*49cdfc7eSAndroid Build Coastguard Worker {
1161*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir **dir;
1162*49cdfc7eSAndroid Build Coastguard Worker 
1163*49cdfc7eSAndroid Build Coastguard Worker 	for_each_dir(cg, 0, dir) {
1164*49cdfc7eSAndroid Build Coastguard Worker 		close((*dir)->dir_fd);
1165*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_UNLINKAT((*dir)->dir_parent->dir_fd,
1166*49cdfc7eSAndroid Build Coastguard Worker 			      (*dir)->dir_name,
1167*49cdfc7eSAndroid Build Coastguard Worker 			      AT_REMOVEDIR);
1168*49cdfc7eSAndroid Build Coastguard Worker 		free(*dir);
1169*49cdfc7eSAndroid Build Coastguard Worker 	}
1170*49cdfc7eSAndroid Build Coastguard Worker 
1171*49cdfc7eSAndroid Build Coastguard Worker 	free(cg);
1172*49cdfc7eSAndroid Build Coastguard Worker 	return NULL;
1173*49cdfc7eSAndroid Build Coastguard Worker }
1174*49cdfc7eSAndroid Build Coastguard Worker 
1175*49cdfc7eSAndroid Build Coastguard Worker __attribute__ ((nonnull, warn_unused_result))
cgroup_file_find(const char * const file,const int lineno,const char * const file_name)1176*49cdfc7eSAndroid Build Coastguard Worker static const struct cgroup_file *cgroup_file_find(const char *const file,
1177*49cdfc7eSAndroid Build Coastguard Worker 						  const int lineno,
1178*49cdfc7eSAndroid Build Coastguard Worker 						  const char *const file_name)
1179*49cdfc7eSAndroid Build Coastguard Worker {
1180*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_file *cfile;
1181*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_ctrl *ctrl;
1182*49cdfc7eSAndroid Build Coastguard Worker 	char ctrl_name[CTRL_NAME_MAX + 1];
1183*49cdfc7eSAndroid Build Coastguard Worker 	const char *const sep = strchr(file_name, '.');
1184*49cdfc7eSAndroid Build Coastguard Worker 	size_t len;
1185*49cdfc7eSAndroid Build Coastguard Worker 
1186*49cdfc7eSAndroid Build Coastguard Worker 	if (!sep) {
1187*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK,
1188*49cdfc7eSAndroid Build Coastguard Worker 			 "Invalid file name '%s'; did not find controller separator '.'",
1189*49cdfc7eSAndroid Build Coastguard Worker 			 file_name);
1190*49cdfc7eSAndroid Build Coastguard Worker 		return NULL;
1191*49cdfc7eSAndroid Build Coastguard Worker 	}
1192*49cdfc7eSAndroid Build Coastguard Worker 
1193*49cdfc7eSAndroid Build Coastguard Worker 	len = sep - file_name;
1194*49cdfc7eSAndroid Build Coastguard Worker 	memcpy(ctrl_name, file_name, len);
1195*49cdfc7eSAndroid Build Coastguard Worker 	ctrl_name[len] = '\0';
1196*49cdfc7eSAndroid Build Coastguard Worker 
1197*49cdfc7eSAndroid Build Coastguard Worker 	ctrl = cgroup_find_ctrl(ctrl_name, 1);
1198*49cdfc7eSAndroid Build Coastguard Worker 
1199*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctrl) {
1200*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK,
1201*49cdfc7eSAndroid Build Coastguard Worker 			 "Did not find controller '%s'\n", ctrl_name);
1202*49cdfc7eSAndroid Build Coastguard Worker 		return NULL;
1203*49cdfc7eSAndroid Build Coastguard Worker 	}
1204*49cdfc7eSAndroid Build Coastguard Worker 
1205*49cdfc7eSAndroid Build Coastguard Worker 	for (cfile = ctrl->files; cfile->file_name; cfile++) {
1206*49cdfc7eSAndroid Build Coastguard Worker 		if (!strcmp(file_name, cfile->file_name))
1207*49cdfc7eSAndroid Build Coastguard Worker 			break;
1208*49cdfc7eSAndroid Build Coastguard Worker 	}
1209*49cdfc7eSAndroid Build Coastguard Worker 
1210*49cdfc7eSAndroid Build Coastguard Worker 	if (!cfile->file_name) {
1211*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK,
1212*49cdfc7eSAndroid Build Coastguard Worker 			 "Did not find '%s' in '%s'\n",
1213*49cdfc7eSAndroid Build Coastguard Worker 			 file_name, ctrl->ctrl_name);
1214*49cdfc7eSAndroid Build Coastguard Worker 		return NULL;
1215*49cdfc7eSAndroid Build Coastguard Worker 	}
1216*49cdfc7eSAndroid Build Coastguard Worker 
1217*49cdfc7eSAndroid Build Coastguard Worker 	return cfile;
1218*49cdfc7eSAndroid Build Coastguard Worker }
1219*49cdfc7eSAndroid Build Coastguard Worker 
tst_cg_ver(const char * const file,const int lineno,const struct tst_cg_group * const cg,const char * const ctrl_name)1220*49cdfc7eSAndroid Build Coastguard Worker enum tst_cg_ver tst_cg_ver(const char *const file, const int lineno,
1221*49cdfc7eSAndroid Build Coastguard Worker 				    const struct tst_cg_group *const cg,
1222*49cdfc7eSAndroid Build Coastguard Worker 				    const char *const ctrl_name)
1223*49cdfc7eSAndroid Build Coastguard Worker {
1224*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_ctrl *const ctrl = cgroup_find_ctrl(ctrl_name, 1);
1225*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_dir *dir;
1226*49cdfc7eSAndroid Build Coastguard Worker 
1227*49cdfc7eSAndroid Build Coastguard Worker 	if (!strcmp(ctrl_name, "cgroup")) {
1228*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno,
1229*49cdfc7eSAndroid Build Coastguard Worker 			 TBROK,
1230*49cdfc7eSAndroid Build Coastguard Worker 			 "cgroup may be present on both V1 and V2 hierarchies");
1231*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
1232*49cdfc7eSAndroid Build Coastguard Worker 	}
1233*49cdfc7eSAndroid Build Coastguard Worker 
1234*49cdfc7eSAndroid Build Coastguard Worker 	if (!ctrl) {
1235*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno,
1236*49cdfc7eSAndroid Build Coastguard Worker 			 TBROK, "Unknown controller '%s'", ctrl_name);
1237*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
1238*49cdfc7eSAndroid Build Coastguard Worker 	}
1239*49cdfc7eSAndroid Build Coastguard Worker 
1240*49cdfc7eSAndroid Build Coastguard Worker 	dir = cg->dirs_by_ctrl[ctrl->ctrl_indx];
1241*49cdfc7eSAndroid Build Coastguard Worker 
1242*49cdfc7eSAndroid Build Coastguard Worker 	if (!dir) {
1243*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno,
1244*49cdfc7eSAndroid Build Coastguard Worker 			 TBROK, "%s controller not attached to CGroup %s",
1245*49cdfc7eSAndroid Build Coastguard Worker 			 ctrl_name, cg->group_name);
1246*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
1247*49cdfc7eSAndroid Build Coastguard Worker 	}
1248*49cdfc7eSAndroid Build Coastguard Worker 
1249*49cdfc7eSAndroid Build Coastguard Worker 	return dir->dir_root->ver;
1250*49cdfc7eSAndroid Build Coastguard Worker }
1251*49cdfc7eSAndroid Build Coastguard Worker 
1252*49cdfc7eSAndroid Build Coastguard Worker __attribute__ ((nonnull, warn_unused_result))
cgroup_file_alias(const struct cgroup_file * const cfile,const struct cgroup_dir * const dir)1253*49cdfc7eSAndroid Build Coastguard Worker static const char *cgroup_file_alias(const struct cgroup_file *const cfile,
1254*49cdfc7eSAndroid Build Coastguard Worker 				     const struct cgroup_dir *const dir)
1255*49cdfc7eSAndroid Build Coastguard Worker {
1256*49cdfc7eSAndroid Build Coastguard Worker 	if (dir->dir_root->ver != TST_CG_V1)
1257*49cdfc7eSAndroid Build Coastguard Worker 		return cfile->file_name;
1258*49cdfc7eSAndroid Build Coastguard Worker 
1259*49cdfc7eSAndroid Build Coastguard Worker 	if (cfile->ctrl_indx == CTRL_CPUSET &&
1260*49cdfc7eSAndroid Build Coastguard Worker 	    dir->dir_root->no_cpuset_prefix &&
1261*49cdfc7eSAndroid Build Coastguard Worker 	    cfile->file_name_v1) {
1262*49cdfc7eSAndroid Build Coastguard Worker 		return strchr(cfile->file_name_v1, '.') + 1;
1263*49cdfc7eSAndroid Build Coastguard Worker 	}
1264*49cdfc7eSAndroid Build Coastguard Worker 
1265*49cdfc7eSAndroid Build Coastguard Worker 	return cfile->file_name_v1;
1266*49cdfc7eSAndroid Build Coastguard Worker }
1267*49cdfc7eSAndroid Build Coastguard Worker 
safe_cg_has(const char * const file,const int lineno,const struct tst_cg_group * cg,const char * const file_name)1268*49cdfc7eSAndroid Build Coastguard Worker int safe_cg_has(const char *const file, const int lineno,
1269*49cdfc7eSAndroid Build Coastguard Worker 		    const struct tst_cg_group *cg,
1270*49cdfc7eSAndroid Build Coastguard Worker 		    const char *const file_name)
1271*49cdfc7eSAndroid Build Coastguard Worker {
1272*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_file *const cfile =
1273*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_file_find(file, lineno, file_name);
1274*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir *const *dir;
1275*49cdfc7eSAndroid Build Coastguard Worker 	const char *alias;
1276*49cdfc7eSAndroid Build Coastguard Worker 
1277*49cdfc7eSAndroid Build Coastguard Worker 	if (!cfile)
1278*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
1279*49cdfc7eSAndroid Build Coastguard Worker 
1280*49cdfc7eSAndroid Build Coastguard Worker 	for_each_dir(cg, cfile->ctrl_indx, dir) {
1281*49cdfc7eSAndroid Build Coastguard Worker 		alias = cgroup_file_alias(cfile, *dir);
1282*49cdfc7eSAndroid Build Coastguard Worker 		if (!alias)
1283*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1284*49cdfc7eSAndroid Build Coastguard Worker 
1285*49cdfc7eSAndroid Build Coastguard Worker 		if (!faccessat((*dir)->dir_fd, alias, F_OK, 0))
1286*49cdfc7eSAndroid Build Coastguard Worker 			return 1;
1287*49cdfc7eSAndroid Build Coastguard Worker 
1288*49cdfc7eSAndroid Build Coastguard Worker 		if (errno == ENOENT)
1289*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1290*49cdfc7eSAndroid Build Coastguard Worker 
1291*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK | TERRNO,
1292*49cdfc7eSAndroid Build Coastguard Worker 			 "faccessat(%d<%s>, %s, F_OK, 0)",
1293*49cdfc7eSAndroid Build Coastguard Worker 			 (*dir)->dir_fd, tst_decode_fd((*dir)->dir_fd), alias);
1294*49cdfc7eSAndroid Build Coastguard Worker 	}
1295*49cdfc7eSAndroid Build Coastguard Worker 
1296*49cdfc7eSAndroid Build Coastguard Worker 	return 0;
1297*49cdfc7eSAndroid Build Coastguard Worker }
1298*49cdfc7eSAndroid Build Coastguard Worker 
group_from_roots(struct tst_cg_group * const cg)1299*49cdfc7eSAndroid Build Coastguard Worker static void group_from_roots(struct tst_cg_group *const cg)
1300*49cdfc7eSAndroid Build Coastguard Worker {
1301*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_root *root;
1302*49cdfc7eSAndroid Build Coastguard Worker 
1303*49cdfc7eSAndroid Build Coastguard Worker 	if (cg->group_name[0]) {
1304*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK,
1305*49cdfc7eSAndroid Build Coastguard Worker 			"%s CGroup already initialized",
1306*49cdfc7eSAndroid Build Coastguard Worker 			cg == &test_group ? "Test" : "Drain");
1307*49cdfc7eSAndroid Build Coastguard Worker 	}
1308*49cdfc7eSAndroid Build Coastguard Worker 
1309*49cdfc7eSAndroid Build Coastguard Worker 	for_each_root(root) {
1310*49cdfc7eSAndroid Build Coastguard Worker 		struct cgroup_dir *dir =
1311*49cdfc7eSAndroid Build Coastguard Worker 			cg == &test_group ? &root->test_dir : &root->drain_dir;
1312*49cdfc7eSAndroid Build Coastguard Worker 
1313*49cdfc7eSAndroid Build Coastguard Worker 		if (dir->ctrl_field)
1314*49cdfc7eSAndroid Build Coastguard Worker 			cgroup_group_add_dir(NULL, cg, dir);
1315*49cdfc7eSAndroid Build Coastguard Worker 	}
1316*49cdfc7eSAndroid Build Coastguard Worker 
1317*49cdfc7eSAndroid Build Coastguard Worker 	if (cg->dirs[0]) {
1318*49cdfc7eSAndroid Build Coastguard Worker 		strncpy(cg->group_name, cg->dirs[0]->dir_name, NAME_MAX);
1319*49cdfc7eSAndroid Build Coastguard Worker 		return;
1320*49cdfc7eSAndroid Build Coastguard Worker 	}
1321*49cdfc7eSAndroid Build Coastguard Worker 
1322*49cdfc7eSAndroid Build Coastguard Worker 	tst_brk(TBROK,
1323*49cdfc7eSAndroid Build Coastguard Worker 		"No CGroups found; maybe you forgot to call tst_cg_require?");
1324*49cdfc7eSAndroid Build Coastguard Worker }
1325*49cdfc7eSAndroid Build Coastguard Worker 
tst_cg_init(void)1326*49cdfc7eSAndroid Build Coastguard Worker void tst_cg_init(void)
1327*49cdfc7eSAndroid Build Coastguard Worker {
1328*49cdfc7eSAndroid Build Coastguard Worker 	group_from_roots(&test_group);
1329*49cdfc7eSAndroid Build Coastguard Worker 	group_from_roots(&drain_group);
1330*49cdfc7eSAndroid Build Coastguard Worker }
1331*49cdfc7eSAndroid Build Coastguard Worker 
safe_cg_read(const char * const file,const int lineno,const struct tst_cg_group * const cg,const char * const file_name,char * const out,const size_t len)1332*49cdfc7eSAndroid Build Coastguard Worker ssize_t safe_cg_read(const char *const file, const int lineno,
1333*49cdfc7eSAndroid Build Coastguard Worker 			 const struct tst_cg_group *const cg,
1334*49cdfc7eSAndroid Build Coastguard Worker 			 const char *const file_name,
1335*49cdfc7eSAndroid Build Coastguard Worker 			 char *const out, const size_t len)
1336*49cdfc7eSAndroid Build Coastguard Worker {
1337*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_file *const cfile =
1338*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_file_find(file, lineno, file_name);
1339*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir *const *dir;
1340*49cdfc7eSAndroid Build Coastguard Worker 	const char *alias;
1341*49cdfc7eSAndroid Build Coastguard Worker 	size_t prev_len = 0;
1342*49cdfc7eSAndroid Build Coastguard Worker 	char prev_buf[BUFSIZ];
1343*49cdfc7eSAndroid Build Coastguard Worker 	ssize_t read_ret = 0;
1344*49cdfc7eSAndroid Build Coastguard Worker 
1345*49cdfc7eSAndroid Build Coastguard Worker 	for_each_dir(cg, cfile->ctrl_indx, dir) {
1346*49cdfc7eSAndroid Build Coastguard Worker 		alias = cgroup_file_alias(cfile, *dir);
1347*49cdfc7eSAndroid Build Coastguard Worker 		if (!alias)
1348*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1349*49cdfc7eSAndroid Build Coastguard Worker 
1350*49cdfc7eSAndroid Build Coastguard Worker 		if (prev_len)
1351*49cdfc7eSAndroid Build Coastguard Worker 			memcpy(prev_buf, out, prev_len);
1352*49cdfc7eSAndroid Build Coastguard Worker 
1353*49cdfc7eSAndroid Build Coastguard Worker 		read_ret = safe_file_readat(file, lineno,
1354*49cdfc7eSAndroid Build Coastguard Worker 					    (*dir)->dir_fd, alias, out, len);
1355*49cdfc7eSAndroid Build Coastguard Worker 		if (read_ret < 0)
1356*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1357*49cdfc7eSAndroid Build Coastguard Worker 
1358*49cdfc7eSAndroid Build Coastguard Worker 		if (prev_len && memcmp(out, prev_buf, prev_len)) {
1359*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk_(file, lineno, TBROK,
1360*49cdfc7eSAndroid Build Coastguard Worker 				 "%s has different value across roots",
1361*49cdfc7eSAndroid Build Coastguard Worker 				 file_name);
1362*49cdfc7eSAndroid Build Coastguard Worker 			break;
1363*49cdfc7eSAndroid Build Coastguard Worker 		}
1364*49cdfc7eSAndroid Build Coastguard Worker 
1365*49cdfc7eSAndroid Build Coastguard Worker 		prev_len = MIN(sizeof(prev_buf), (size_t)read_ret);
1366*49cdfc7eSAndroid Build Coastguard Worker 	}
1367*49cdfc7eSAndroid Build Coastguard Worker 
1368*49cdfc7eSAndroid Build Coastguard Worker 	out[MAX(read_ret, (ssize_t)0)] = '\0';
1369*49cdfc7eSAndroid Build Coastguard Worker 
1370*49cdfc7eSAndroid Build Coastguard Worker 	return read_ret;
1371*49cdfc7eSAndroid Build Coastguard Worker }
1372*49cdfc7eSAndroid Build Coastguard Worker 
safe_cg_printf(const char * const file,const int lineno,const struct tst_cg_group * cg,const char * const file_name,const char * const fmt,...)1373*49cdfc7eSAndroid Build Coastguard Worker void safe_cg_printf(const char *const file, const int lineno,
1374*49cdfc7eSAndroid Build Coastguard Worker 			const struct tst_cg_group *cg,
1375*49cdfc7eSAndroid Build Coastguard Worker 			const char *const file_name,
1376*49cdfc7eSAndroid Build Coastguard Worker 			const char *const fmt, ...)
1377*49cdfc7eSAndroid Build Coastguard Worker {
1378*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_file *const cfile =
1379*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_file_find(file, lineno, file_name);
1380*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir *const *dir;
1381*49cdfc7eSAndroid Build Coastguard Worker 	const char *alias;
1382*49cdfc7eSAndroid Build Coastguard Worker 	va_list va;
1383*49cdfc7eSAndroid Build Coastguard Worker 
1384*49cdfc7eSAndroid Build Coastguard Worker 	for_each_dir(cg, cfile->ctrl_indx, dir) {
1385*49cdfc7eSAndroid Build Coastguard Worker 		alias = cgroup_file_alias(cfile, *dir);
1386*49cdfc7eSAndroid Build Coastguard Worker 		if (!alias)
1387*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1388*49cdfc7eSAndroid Build Coastguard Worker 
1389*49cdfc7eSAndroid Build Coastguard Worker 		va_start(va, fmt);
1390*49cdfc7eSAndroid Build Coastguard Worker 		safe_file_vprintfat(file, lineno,
1391*49cdfc7eSAndroid Build Coastguard Worker 				    (*dir)->dir_fd, alias, fmt, va);
1392*49cdfc7eSAndroid Build Coastguard Worker 		va_end(va);
1393*49cdfc7eSAndroid Build Coastguard Worker 	}
1394*49cdfc7eSAndroid Build Coastguard Worker }
1395*49cdfc7eSAndroid Build Coastguard Worker 
safe_cg_open(const char * const file,const int lineno,const struct tst_cg_group * cg,const char * const file_name,int flags,int * fds)1396*49cdfc7eSAndroid Build Coastguard Worker int safe_cg_open(const char *const file, const int lineno,
1397*49cdfc7eSAndroid Build Coastguard Worker 		      const struct tst_cg_group *cg,
1398*49cdfc7eSAndroid Build Coastguard Worker 		      const char *const file_name, int flags, int *fds)
1399*49cdfc7eSAndroid Build Coastguard Worker {
1400*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_file *const cfile =
1401*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_file_find(file, lineno, file_name);
1402*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir *const *dir;
1403*49cdfc7eSAndroid Build Coastguard Worker 	const char *alias;
1404*49cdfc7eSAndroid Build Coastguard Worker 	int i = 0;
1405*49cdfc7eSAndroid Build Coastguard Worker 
1406*49cdfc7eSAndroid Build Coastguard Worker 	for_each_dir(cg, cfile->ctrl_indx, dir) {
1407*49cdfc7eSAndroid Build Coastguard Worker 		alias = cgroup_file_alias(cfile, *dir);
1408*49cdfc7eSAndroid Build Coastguard Worker 		if (!alias)
1409*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1410*49cdfc7eSAndroid Build Coastguard Worker 
1411*49cdfc7eSAndroid Build Coastguard Worker 		fds[i++] = safe_openat(file, lineno, (*dir)->dir_fd, alias, flags);
1412*49cdfc7eSAndroid Build Coastguard Worker 	}
1413*49cdfc7eSAndroid Build Coastguard Worker 
1414*49cdfc7eSAndroid Build Coastguard Worker 	return i;
1415*49cdfc7eSAndroid Build Coastguard Worker }
1416*49cdfc7eSAndroid Build Coastguard Worker 
safe_cg_fchown(const char * const file,const int lineno,const struct tst_cg_group * cg,const char * const file_name,uid_t owner,gid_t group)1417*49cdfc7eSAndroid Build Coastguard Worker void safe_cg_fchown(const char *const file, const int lineno,
1418*49cdfc7eSAndroid Build Coastguard Worker 			const struct tst_cg_group *cg,
1419*49cdfc7eSAndroid Build Coastguard Worker 			const char *const file_name,
1420*49cdfc7eSAndroid Build Coastguard Worker 			uid_t owner, gid_t group)
1421*49cdfc7eSAndroid Build Coastguard Worker {
1422*49cdfc7eSAndroid Build Coastguard Worker 	const struct cgroup_file *const cfile =
1423*49cdfc7eSAndroid Build Coastguard Worker 		cgroup_file_find(file, lineno, file_name);
1424*49cdfc7eSAndroid Build Coastguard Worker 	struct cgroup_dir *const *dir;
1425*49cdfc7eSAndroid Build Coastguard Worker 	const char *alias;
1426*49cdfc7eSAndroid Build Coastguard Worker 
1427*49cdfc7eSAndroid Build Coastguard Worker 	for_each_dir(cg, cfile->ctrl_indx, dir) {
1428*49cdfc7eSAndroid Build Coastguard Worker 		alias = cgroup_file_alias(cfile, *dir);
1429*49cdfc7eSAndroid Build Coastguard Worker 		if (!alias)
1430*49cdfc7eSAndroid Build Coastguard Worker 			continue;
1431*49cdfc7eSAndroid Build Coastguard Worker 
1432*49cdfc7eSAndroid Build Coastguard Worker 		safe_fchownat(file, lineno, (*dir)->dir_fd, alias, owner, group, 0);
1433*49cdfc7eSAndroid Build Coastguard Worker 	}
1434*49cdfc7eSAndroid Build Coastguard Worker }
1435*49cdfc7eSAndroid Build Coastguard Worker 
1436*49cdfc7eSAndroid Build Coastguard Worker 
safe_cg_scanf(const char * const file,const int lineno,const struct tst_cg_group * const cg,const char * const file_name,const char * const fmt,...)1437*49cdfc7eSAndroid Build Coastguard Worker void safe_cg_scanf(const char *const file, const int lineno,
1438*49cdfc7eSAndroid Build Coastguard Worker 		       const struct tst_cg_group *const cg,
1439*49cdfc7eSAndroid Build Coastguard Worker 		       const char *const file_name,
1440*49cdfc7eSAndroid Build Coastguard Worker 		       const char *const fmt, ...)
1441*49cdfc7eSAndroid Build Coastguard Worker {
1442*49cdfc7eSAndroid Build Coastguard Worker 	va_list va;
1443*49cdfc7eSAndroid Build Coastguard Worker 	char buf[BUFSIZ];
1444*49cdfc7eSAndroid Build Coastguard Worker 	ssize_t len = safe_cg_read(file, lineno,
1445*49cdfc7eSAndroid Build Coastguard Worker 				       cg, file_name, buf, sizeof(buf));
1446*49cdfc7eSAndroid Build Coastguard Worker 	const int conv_cnt = tst_count_scanf_conversions(fmt);
1447*49cdfc7eSAndroid Build Coastguard Worker 	int ret;
1448*49cdfc7eSAndroid Build Coastguard Worker 
1449*49cdfc7eSAndroid Build Coastguard Worker 	if (len < 1)
1450*49cdfc7eSAndroid Build Coastguard Worker 		return;
1451*49cdfc7eSAndroid Build Coastguard Worker 
1452*49cdfc7eSAndroid Build Coastguard Worker 	va_start(va, fmt);
1453*49cdfc7eSAndroid Build Coastguard Worker 	ret = vsscanf(buf, fmt, va);
1454*49cdfc7eSAndroid Build Coastguard Worker 	if (ret < 1) {
1455*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK | TERRNO,
1456*49cdfc7eSAndroid Build Coastguard Worker 			 "'%s': vsscanf('%s', '%s', ...)", file_name, buf, fmt);
1457*49cdfc7eSAndroid Build Coastguard Worker 	}
1458*49cdfc7eSAndroid Build Coastguard Worker 	va_end(va);
1459*49cdfc7eSAndroid Build Coastguard Worker 
1460*49cdfc7eSAndroid Build Coastguard Worker 	if (conv_cnt == ret)
1461*49cdfc7eSAndroid Build Coastguard Worker 		return;
1462*49cdfc7eSAndroid Build Coastguard Worker 
1463*49cdfc7eSAndroid Build Coastguard Worker 	tst_brk_(file, lineno, TBROK,
1464*49cdfc7eSAndroid Build Coastguard Worker 		 "'%s': vsscanf('%s', '%s', ..): Less conversions than expected: %d != %d",
1465*49cdfc7eSAndroid Build Coastguard Worker 		 file_name, buf, fmt, ret, conv_cnt);
1466*49cdfc7eSAndroid Build Coastguard Worker }
1467*49cdfc7eSAndroid Build Coastguard Worker 
safe_cg_lines_scanf(const char * const file,const int lineno,const struct tst_cg_group * const cg,const char * const file_name,const char * const fmt,...)1468*49cdfc7eSAndroid Build Coastguard Worker void safe_cg_lines_scanf(const char *const file, const int lineno,
1469*49cdfc7eSAndroid Build Coastguard Worker 			     const struct tst_cg_group *const cg,
1470*49cdfc7eSAndroid Build Coastguard Worker 			     const char *const file_name,
1471*49cdfc7eSAndroid Build Coastguard Worker 			     const char *const fmt, ...)
1472*49cdfc7eSAndroid Build Coastguard Worker {
1473*49cdfc7eSAndroid Build Coastguard Worker 	va_list va;
1474*49cdfc7eSAndroid Build Coastguard Worker 	char buf[BUFSIZ];
1475*49cdfc7eSAndroid Build Coastguard Worker 	ssize_t len = safe_cg_read(file, lineno,
1476*49cdfc7eSAndroid Build Coastguard Worker 				       cg, file_name, buf, sizeof(buf));
1477*49cdfc7eSAndroid Build Coastguard Worker 	const int conv_cnt = tst_count_scanf_conversions(fmt);
1478*49cdfc7eSAndroid Build Coastguard Worker 	int ret = 0;
1479*49cdfc7eSAndroid Build Coastguard Worker 	char *line, *buf_ptr;
1480*49cdfc7eSAndroid Build Coastguard Worker 
1481*49cdfc7eSAndroid Build Coastguard Worker 	if (len < 1)
1482*49cdfc7eSAndroid Build Coastguard Worker 		return;
1483*49cdfc7eSAndroid Build Coastguard Worker 
1484*49cdfc7eSAndroid Build Coastguard Worker 	line = strtok_r(buf, "\n", &buf_ptr);
1485*49cdfc7eSAndroid Build Coastguard Worker 	while (line && ret != conv_cnt) {
1486*49cdfc7eSAndroid Build Coastguard Worker 		va_start(va, fmt);
1487*49cdfc7eSAndroid Build Coastguard Worker 		ret = vsscanf(line, fmt, va);
1488*49cdfc7eSAndroid Build Coastguard Worker 		va_end(va);
1489*49cdfc7eSAndroid Build Coastguard Worker 
1490*49cdfc7eSAndroid Build Coastguard Worker 		line = strtok_r(NULL, "\n", &buf_ptr);
1491*49cdfc7eSAndroid Build Coastguard Worker 	}
1492*49cdfc7eSAndroid Build Coastguard Worker 
1493*49cdfc7eSAndroid Build Coastguard Worker 	if (conv_cnt == ret)
1494*49cdfc7eSAndroid Build Coastguard Worker 		return;
1495*49cdfc7eSAndroid Build Coastguard Worker 
1496*49cdfc7eSAndroid Build Coastguard Worker 	tst_brk_(file, lineno, TBROK,
1497*49cdfc7eSAndroid Build Coastguard Worker 		 "'%s': vsscanf('%s', '%s', ..): Less conversions than expected: %d != %d",
1498*49cdfc7eSAndroid Build Coastguard Worker 		 file_name, buf, fmt, ret, conv_cnt);
1499*49cdfc7eSAndroid Build Coastguard Worker }
1500*49cdfc7eSAndroid Build Coastguard Worker 
safe_cg_occursin(const char * const file,const int lineno,const struct tst_cg_group * const cg,const char * const file_name,const char * const needle)1501*49cdfc7eSAndroid Build Coastguard Worker int safe_cg_occursin(const char *const file, const int lineno,
1502*49cdfc7eSAndroid Build Coastguard Worker 			 const struct tst_cg_group *const cg,
1503*49cdfc7eSAndroid Build Coastguard Worker 			 const char *const file_name,
1504*49cdfc7eSAndroid Build Coastguard Worker 			 const char *const needle)
1505*49cdfc7eSAndroid Build Coastguard Worker {
1506*49cdfc7eSAndroid Build Coastguard Worker 	char buf[BUFSIZ];
1507*49cdfc7eSAndroid Build Coastguard Worker 
1508*49cdfc7eSAndroid Build Coastguard Worker 	safe_cg_read(file, lineno, cg, file_name, buf, sizeof(buf));
1509*49cdfc7eSAndroid Build Coastguard Worker 
1510*49cdfc7eSAndroid Build Coastguard Worker 	return !!strstr(buf, needle);
1511*49cdfc7eSAndroid Build Coastguard Worker }
1512