1f583ddf1SDavid Vernet // SPDX-License-Identifier: GPL-2.0
2f583ddf1SDavid Vernet /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3f583ddf1SDavid Vernet 
4f583ddf1SDavid Vernet #include <vmlinux.h>
5f583ddf1SDavid Vernet #include <bpf/bpf_tracing.h>
6f583ddf1SDavid Vernet #include <bpf/bpf_helpers.h>
7f583ddf1SDavid Vernet 
8f583ddf1SDavid Vernet #include "cgrp_kfunc_common.h"
9f583ddf1SDavid Vernet 
10f583ddf1SDavid Vernet char _license[] SEC("license") = "GPL";
11f583ddf1SDavid Vernet 
12f583ddf1SDavid Vernet int err, pid, invocations;
13f583ddf1SDavid Vernet 
14f583ddf1SDavid Vernet /* Prototype for all of the program trace events below:
15f583ddf1SDavid Vernet  *
16f583ddf1SDavid Vernet  * TRACE_EVENT(cgroup_mkdir,
17f583ddf1SDavid Vernet  *         TP_PROTO(struct cgroup *cgrp, const char *path),
18f583ddf1SDavid Vernet  *         TP_ARGS(cgrp, path)
19f583ddf1SDavid Vernet  */
20f583ddf1SDavid Vernet 
is_test_kfunc_task(void)21f583ddf1SDavid Vernet static bool is_test_kfunc_task(void)
22f583ddf1SDavid Vernet {
23f583ddf1SDavid Vernet 	int cur_pid = bpf_get_current_pid_tgid() >> 32;
24f583ddf1SDavid Vernet 	bool same = pid == cur_pid;
25f583ddf1SDavid Vernet 
26f583ddf1SDavid Vernet 	if (same)
27f583ddf1SDavid Vernet 		__sync_fetch_and_add(&invocations, 1);
28f583ddf1SDavid Vernet 
29f583ddf1SDavid Vernet 	return same;
30f583ddf1SDavid Vernet }
31f583ddf1SDavid Vernet 
32f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
BPF_PROG(test_cgrp_acquire_release_argument,struct cgroup * cgrp,const char * path)33f583ddf1SDavid Vernet int BPF_PROG(test_cgrp_acquire_release_argument, struct cgroup *cgrp, const char *path)
34f583ddf1SDavid Vernet {
35f583ddf1SDavid Vernet 	struct cgroup *acquired;
36f583ddf1SDavid Vernet 
37f583ddf1SDavid Vernet 	if (!is_test_kfunc_task())
38f583ddf1SDavid Vernet 		return 0;
39f583ddf1SDavid Vernet 
40f583ddf1SDavid Vernet 	acquired = bpf_cgroup_acquire(cgrp);
411d712839SDavid Vernet 	if (!acquired)
421d712839SDavid Vernet 		err = 1;
431d712839SDavid Vernet 	else
44f583ddf1SDavid Vernet 		bpf_cgroup_release(acquired);
45f583ddf1SDavid Vernet 
46f583ddf1SDavid Vernet 	return 0;
47f583ddf1SDavid Vernet }
48f583ddf1SDavid Vernet 
49f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
BPF_PROG(test_cgrp_acquire_leave_in_map,struct cgroup * cgrp,const char * path)50f583ddf1SDavid Vernet int BPF_PROG(test_cgrp_acquire_leave_in_map, struct cgroup *cgrp, const char *path)
51f583ddf1SDavid Vernet {
52f583ddf1SDavid Vernet 	long status;
53f583ddf1SDavid Vernet 
54f583ddf1SDavid Vernet 	if (!is_test_kfunc_task())
55f583ddf1SDavid Vernet 		return 0;
56f583ddf1SDavid Vernet 
57f583ddf1SDavid Vernet 	status = cgrps_kfunc_map_insert(cgrp);
58f583ddf1SDavid Vernet 	if (status)
59f583ddf1SDavid Vernet 		err = 1;
60f583ddf1SDavid Vernet 
61f583ddf1SDavid Vernet 	return 0;
62f583ddf1SDavid Vernet }
63f583ddf1SDavid Vernet 
64f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
BPF_PROG(test_cgrp_xchg_release,struct cgroup * cgrp,const char * path)65f583ddf1SDavid Vernet int BPF_PROG(test_cgrp_xchg_release, struct cgroup *cgrp, const char *path)
66f583ddf1SDavid Vernet {
670047d834SAlexei Starovoitov 	struct cgroup *kptr, *cg;
68f583ddf1SDavid Vernet 	struct __cgrps_kfunc_map_value *v;
69f583ddf1SDavid Vernet 	long status;
70f583ddf1SDavid Vernet 
71f583ddf1SDavid Vernet 	if (!is_test_kfunc_task())
72f583ddf1SDavid Vernet 		return 0;
73f583ddf1SDavid Vernet 
74f583ddf1SDavid Vernet 	status = cgrps_kfunc_map_insert(cgrp);
75f583ddf1SDavid Vernet 	if (status) {
76f583ddf1SDavid Vernet 		err = 1;
77f583ddf1SDavid Vernet 		return 0;
78f583ddf1SDavid Vernet 	}
79f583ddf1SDavid Vernet 
80f583ddf1SDavid Vernet 	v = cgrps_kfunc_map_value_lookup(cgrp);
81f583ddf1SDavid Vernet 	if (!v) {
82f583ddf1SDavid Vernet 		err = 2;
83f583ddf1SDavid Vernet 		return 0;
84f583ddf1SDavid Vernet 	}
85f583ddf1SDavid Vernet 
860047d834SAlexei Starovoitov 	kptr = v->cgrp;
870047d834SAlexei Starovoitov 	if (!kptr) {
880047d834SAlexei Starovoitov 		err = 4;
890047d834SAlexei Starovoitov 		return 0;
900047d834SAlexei Starovoitov 	}
910047d834SAlexei Starovoitov 
920047d834SAlexei Starovoitov 	cg = bpf_cgroup_ancestor(kptr, 1);
930047d834SAlexei Starovoitov 	if (cg)	/* verifier only check */
940047d834SAlexei Starovoitov 		bpf_cgroup_release(cg);
950047d834SAlexei Starovoitov 
96f583ddf1SDavid Vernet 	kptr = bpf_kptr_xchg(&v->cgrp, NULL);
97f583ddf1SDavid Vernet 	if (!kptr) {
98f583ddf1SDavid Vernet 		err = 3;
99f583ddf1SDavid Vernet 		return 0;
100f583ddf1SDavid Vernet 	}
101f583ddf1SDavid Vernet 
102f583ddf1SDavid Vernet 	bpf_cgroup_release(kptr);
103f583ddf1SDavid Vernet 
104f583ddf1SDavid Vernet 	return 0;
105f583ddf1SDavid Vernet }
106f583ddf1SDavid Vernet 
107f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
BPF_PROG(test_cgrp_get_release,struct cgroup * cgrp,const char * path)108f583ddf1SDavid Vernet int BPF_PROG(test_cgrp_get_release, struct cgroup *cgrp, const char *path)
109f583ddf1SDavid Vernet {
110f583ddf1SDavid Vernet 	struct cgroup *kptr;
111f583ddf1SDavid Vernet 	struct __cgrps_kfunc_map_value *v;
112f583ddf1SDavid Vernet 	long status;
113f583ddf1SDavid Vernet 
114f583ddf1SDavid Vernet 	if (!is_test_kfunc_task())
115f583ddf1SDavid Vernet 		return 0;
116f583ddf1SDavid Vernet 
117f583ddf1SDavid Vernet 	status = cgrps_kfunc_map_insert(cgrp);
118f583ddf1SDavid Vernet 	if (status) {
119f583ddf1SDavid Vernet 		err = 1;
120f583ddf1SDavid Vernet 		return 0;
121f583ddf1SDavid Vernet 	}
122f583ddf1SDavid Vernet 
123f583ddf1SDavid Vernet 	v = cgrps_kfunc_map_value_lookup(cgrp);
124f583ddf1SDavid Vernet 	if (!v) {
125f583ddf1SDavid Vernet 		err = 2;
126f583ddf1SDavid Vernet 		return 0;
127f583ddf1SDavid Vernet 	}
128f583ddf1SDavid Vernet 
129*6499fe6eSDavid Vernet 	bpf_rcu_read_lock();
130*6499fe6eSDavid Vernet 	kptr = v->cgrp;
131*6499fe6eSDavid Vernet 	if (!kptr)
132f583ddf1SDavid Vernet 		err = 3;
133*6499fe6eSDavid Vernet 	bpf_rcu_read_unlock();
134f583ddf1SDavid Vernet 
135f583ddf1SDavid Vernet 	return 0;
136f583ddf1SDavid Vernet }
137227a89cfSDavid Vernet 
138227a89cfSDavid Vernet SEC("tp_btf/cgroup_mkdir")
BPF_PROG(test_cgrp_get_ancestors,struct cgroup * cgrp,const char * path)139227a89cfSDavid Vernet int BPF_PROG(test_cgrp_get_ancestors, struct cgroup *cgrp, const char *path)
140227a89cfSDavid Vernet {
141227a89cfSDavid Vernet 	struct cgroup *self, *ancestor1, *invalid;
142227a89cfSDavid Vernet 
143227a89cfSDavid Vernet 	if (!is_test_kfunc_task())
144227a89cfSDavid Vernet 		return 0;
145227a89cfSDavid Vernet 
146227a89cfSDavid Vernet 	self = bpf_cgroup_ancestor(cgrp, cgrp->level);
147227a89cfSDavid Vernet 	if (!self) {
148227a89cfSDavid Vernet 		err = 1;
149227a89cfSDavid Vernet 		return 0;
150227a89cfSDavid Vernet 	}
151227a89cfSDavid Vernet 
152227a89cfSDavid Vernet 	if (self->self.id != cgrp->self.id) {
153227a89cfSDavid Vernet 		bpf_cgroup_release(self);
154227a89cfSDavid Vernet 		err = 2;
155227a89cfSDavid Vernet 		return 0;
156227a89cfSDavid Vernet 	}
157227a89cfSDavid Vernet 	bpf_cgroup_release(self);
158227a89cfSDavid Vernet 
159227a89cfSDavid Vernet 	ancestor1 = bpf_cgroup_ancestor(cgrp, cgrp->level - 1);
160227a89cfSDavid Vernet 	if (!ancestor1) {
161227a89cfSDavid Vernet 		err = 3;
162227a89cfSDavid Vernet 		return 0;
163227a89cfSDavid Vernet 	}
164227a89cfSDavid Vernet 	bpf_cgroup_release(ancestor1);
165227a89cfSDavid Vernet 
166227a89cfSDavid Vernet 	invalid = bpf_cgroup_ancestor(cgrp, 10000);
167227a89cfSDavid Vernet 	if (invalid) {
168227a89cfSDavid Vernet 		bpf_cgroup_release(invalid);
169227a89cfSDavid Vernet 		err = 4;
170227a89cfSDavid Vernet 		return 0;
171227a89cfSDavid Vernet 	}
172227a89cfSDavid Vernet 
173227a89cfSDavid Vernet 	invalid = bpf_cgroup_ancestor(cgrp, -1);
174227a89cfSDavid Vernet 	if (invalid) {
175227a89cfSDavid Vernet 		bpf_cgroup_release(invalid);
176227a89cfSDavid Vernet 		err = 5;
177227a89cfSDavid Vernet 		return 0;
178227a89cfSDavid Vernet 	}
179227a89cfSDavid Vernet 
180227a89cfSDavid Vernet 	return 0;
181227a89cfSDavid Vernet }
182d0093aaeSTejun Heo 
183d0093aaeSTejun Heo SEC("tp_btf/cgroup_mkdir")
BPF_PROG(test_cgrp_from_id,struct cgroup * cgrp,const char * path)184d0093aaeSTejun Heo int BPF_PROG(test_cgrp_from_id, struct cgroup *cgrp, const char *path)
185d0093aaeSTejun Heo {
186d0093aaeSTejun Heo 	struct cgroup *parent, *res;
187d0093aaeSTejun Heo 	u64 parent_cgid;
188d0093aaeSTejun Heo 
189d0093aaeSTejun Heo 	if (!is_test_kfunc_task())
190d0093aaeSTejun Heo 		return 0;
191d0093aaeSTejun Heo 
192d0093aaeSTejun Heo 	/* @cgrp's ID is not visible yet, let's test with the parent */
193d0093aaeSTejun Heo 	parent = bpf_cgroup_ancestor(cgrp, cgrp->level - 1);
194d0093aaeSTejun Heo 	if (!parent) {
195d0093aaeSTejun Heo 		err = 1;
196d0093aaeSTejun Heo 		return 0;
197d0093aaeSTejun Heo 	}
198d0093aaeSTejun Heo 
199d0093aaeSTejun Heo 	parent_cgid = parent->kn->id;
200d0093aaeSTejun Heo 	bpf_cgroup_release(parent);
201d0093aaeSTejun Heo 
202d0093aaeSTejun Heo 	res = bpf_cgroup_from_id(parent_cgid);
203d0093aaeSTejun Heo 	if (!res) {
204d0093aaeSTejun Heo 		err = 2;
205d0093aaeSTejun Heo 		return 0;
206d0093aaeSTejun Heo 	}
207d0093aaeSTejun Heo 
208d0093aaeSTejun Heo 	bpf_cgroup_release(res);
209d0093aaeSTejun Heo 
210d0093aaeSTejun Heo 	if (res != parent) {
211d0093aaeSTejun Heo 		err = 3;
212d0093aaeSTejun Heo 		return 0;
213d0093aaeSTejun Heo 	}
214d0093aaeSTejun Heo 
215d0093aaeSTejun Heo 	res = bpf_cgroup_from_id((u64)-1);
216d0093aaeSTejun Heo 	if (res) {
217d0093aaeSTejun Heo 		bpf_cgroup_release(res);
218d0093aaeSTejun Heo 		err = 4;
219d0093aaeSTejun Heo 		return 0;
220d0093aaeSTejun Heo 	}
221d0093aaeSTejun Heo 
222d0093aaeSTejun Heo 	return 0;
223d0093aaeSTejun Heo }
224