xref: /linux/tools/testing/selftests/bpf/progs/percpu_alloc_array.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
16adf82a4SYonghong Song #include "bpf_experimental.h"
26adf82a4SYonghong Song 
36adf82a4SYonghong Song struct val_t {
46adf82a4SYonghong Song 	long b, c, d;
56adf82a4SYonghong Song };
66adf82a4SYonghong Song 
76adf82a4SYonghong Song struct elem {
86adf82a4SYonghong Song 	long sum;
96adf82a4SYonghong Song 	struct val_t __percpu_kptr *pc;
106adf82a4SYonghong Song };
116adf82a4SYonghong Song 
126adf82a4SYonghong Song struct {
136adf82a4SYonghong Song 	__uint(type, BPF_MAP_TYPE_ARRAY);
146adf82a4SYonghong Song 	__uint(max_entries, 1);
156adf82a4SYonghong Song 	__type(key, int);
166adf82a4SYonghong Song 	__type(value, struct elem);
176adf82a4SYonghong Song } array SEC(".maps");
186adf82a4SYonghong Song 
196adf82a4SYonghong Song void bpf_rcu_read_lock(void) __ksym;
206adf82a4SYonghong Song void bpf_rcu_read_unlock(void) __ksym;
216adf82a4SYonghong Song 
226adf82a4SYonghong Song const volatile int nr_cpus;
236adf82a4SYonghong Song 
246adf82a4SYonghong Song /* Initialize the percpu object */
256adf82a4SYonghong Song SEC("?fentry/bpf_fentry_test1")
BPF_PROG(test_array_map_1)266adf82a4SYonghong Song int BPF_PROG(test_array_map_1)
276adf82a4SYonghong Song {
286adf82a4SYonghong Song 	struct val_t __percpu_kptr *p;
296adf82a4SYonghong Song 	struct elem *e;
306adf82a4SYonghong Song 	int index = 0;
316adf82a4SYonghong Song 
326adf82a4SYonghong Song 	e = bpf_map_lookup_elem(&array, &index);
336adf82a4SYonghong Song 	if (!e)
346adf82a4SYonghong Song 		return 0;
356adf82a4SYonghong Song 
366adf82a4SYonghong Song 	p = bpf_percpu_obj_new(struct val_t);
376adf82a4SYonghong Song 	if (!p)
386adf82a4SYonghong Song 		return 0;
396adf82a4SYonghong Song 
406adf82a4SYonghong Song 	p = bpf_kptr_xchg(&e->pc, p);
416adf82a4SYonghong Song 	if (p)
426adf82a4SYonghong Song 		bpf_percpu_obj_drop(p);
436adf82a4SYonghong Song 
446adf82a4SYonghong Song 	return 0;
456adf82a4SYonghong Song }
466adf82a4SYonghong Song 
476adf82a4SYonghong Song /* Update percpu data */
486adf82a4SYonghong Song SEC("?fentry/bpf_fentry_test2")
BPF_PROG(test_array_map_2)496adf82a4SYonghong Song int BPF_PROG(test_array_map_2)
506adf82a4SYonghong Song {
516adf82a4SYonghong Song 	struct val_t __percpu_kptr *p;
526adf82a4SYonghong Song 	struct val_t *v;
536adf82a4SYonghong Song 	struct elem *e;
546adf82a4SYonghong Song 	int index = 0;
556adf82a4SYonghong Song 
566adf82a4SYonghong Song 	e = bpf_map_lookup_elem(&array, &index);
576adf82a4SYonghong Song 	if (!e)
586adf82a4SYonghong Song 		return 0;
596adf82a4SYonghong Song 
606adf82a4SYonghong Song 	p = e->pc;
616adf82a4SYonghong Song 	if (!p)
626adf82a4SYonghong Song 		return 0;
636adf82a4SYonghong Song 
646adf82a4SYonghong Song 	v = bpf_per_cpu_ptr(p, 0);
656adf82a4SYonghong Song 	if (!v)
666adf82a4SYonghong Song 		return 0;
676adf82a4SYonghong Song 	v->c = 1;
686adf82a4SYonghong Song 	v->d = 2;
696adf82a4SYonghong Song 
706adf82a4SYonghong Song 	return 0;
716adf82a4SYonghong Song }
726adf82a4SYonghong Song 
736adf82a4SYonghong Song int cpu0_field_d, sum_field_c;
74*2d78928cSAndrii Nakryiko int my_pid;
756adf82a4SYonghong Song 
766adf82a4SYonghong Song /* Summarize percpu data */
776adf82a4SYonghong Song SEC("?fentry/bpf_fentry_test3")
BPF_PROG(test_array_map_3)786adf82a4SYonghong Song int BPF_PROG(test_array_map_3)
796adf82a4SYonghong Song {
806adf82a4SYonghong Song 	struct val_t __percpu_kptr *p;
816adf82a4SYonghong Song 	int i, index = 0;
826adf82a4SYonghong Song 	struct val_t *v;
836adf82a4SYonghong Song 	struct elem *e;
846adf82a4SYonghong Song 
85*2d78928cSAndrii Nakryiko 	if ((bpf_get_current_pid_tgid() >> 32) != my_pid)
86*2d78928cSAndrii Nakryiko 		return 0;
87*2d78928cSAndrii Nakryiko 
886adf82a4SYonghong Song 	e = bpf_map_lookup_elem(&array, &index);
896adf82a4SYonghong Song 	if (!e)
906adf82a4SYonghong Song 		return 0;
916adf82a4SYonghong Song 
926adf82a4SYonghong Song 	p = e->pc;
936adf82a4SYonghong Song 	if (!p)
946adf82a4SYonghong Song 		return 0;
956adf82a4SYonghong Song 
966adf82a4SYonghong Song 	bpf_for(i, 0, nr_cpus) {
976adf82a4SYonghong Song 		v = bpf_per_cpu_ptr(p, i);
986adf82a4SYonghong Song 		if (v) {
996adf82a4SYonghong Song 			if (i == 0)
1006adf82a4SYonghong Song 				cpu0_field_d = v->d;
1016adf82a4SYonghong Song 			sum_field_c += v->c;
1026adf82a4SYonghong Song 		}
1036adf82a4SYonghong Song 	}
1046adf82a4SYonghong Song 
1056adf82a4SYonghong Song 	return 0;
1066adf82a4SYonghong Song }
1076adf82a4SYonghong Song 
1086adf82a4SYonghong Song /* Explicitly free allocated percpu data */
1096adf82a4SYonghong Song SEC("?fentry/bpf_fentry_test4")
BPF_PROG(test_array_map_4)1106adf82a4SYonghong Song int BPF_PROG(test_array_map_4)
1116adf82a4SYonghong Song {
1126adf82a4SYonghong Song 	struct val_t __percpu_kptr *p;
1136adf82a4SYonghong Song 	struct elem *e;
1146adf82a4SYonghong Song 	int index = 0;
1156adf82a4SYonghong Song 
1166adf82a4SYonghong Song 	e = bpf_map_lookup_elem(&array, &index);
1176adf82a4SYonghong Song 	if (!e)
1186adf82a4SYonghong Song 		return 0;
1196adf82a4SYonghong Song 
1206adf82a4SYonghong Song 	/* delete */
1216adf82a4SYonghong Song 	p = bpf_kptr_xchg(&e->pc, NULL);
1226adf82a4SYonghong Song 	if (p) {
1236adf82a4SYonghong Song 		bpf_percpu_obj_drop(p);
1246adf82a4SYonghong Song 	}
1256adf82a4SYonghong Song 
1266adf82a4SYonghong Song 	return 0;
1276adf82a4SYonghong Song }
1286adf82a4SYonghong Song 
1296adf82a4SYonghong Song SEC("?fentry.s/bpf_fentry_test1")
BPF_PROG(test_array_map_10)1306adf82a4SYonghong Song int BPF_PROG(test_array_map_10)
1316adf82a4SYonghong Song {
1326adf82a4SYonghong Song 	struct val_t __percpu_kptr *p, *p1;
1336adf82a4SYonghong Song 	int i, index = 0;
1346adf82a4SYonghong Song 	struct val_t *v;
1356adf82a4SYonghong Song 	struct elem *e;
1366adf82a4SYonghong Song 
137*2d78928cSAndrii Nakryiko 	if ((bpf_get_current_pid_tgid() >> 32) != my_pid)
138*2d78928cSAndrii Nakryiko 		return 0;
139*2d78928cSAndrii Nakryiko 
1406adf82a4SYonghong Song 	e = bpf_map_lookup_elem(&array, &index);
1416adf82a4SYonghong Song 	if (!e)
1426adf82a4SYonghong Song 		return 0;
1436adf82a4SYonghong Song 
1446adf82a4SYonghong Song 	bpf_rcu_read_lock();
1456adf82a4SYonghong Song 	p = e->pc;
1466adf82a4SYonghong Song 	if (!p) {
1476adf82a4SYonghong Song 		p = bpf_percpu_obj_new(struct val_t);
1486adf82a4SYonghong Song 		if (!p)
1496adf82a4SYonghong Song 			goto out;
1506adf82a4SYonghong Song 
1516adf82a4SYonghong Song 		p1 = bpf_kptr_xchg(&e->pc, p);
1526adf82a4SYonghong Song 		if (p1) {
1536adf82a4SYonghong Song 			/* race condition */
1546adf82a4SYonghong Song 			bpf_percpu_obj_drop(p1);
1556adf82a4SYonghong Song 		}
1566adf82a4SYonghong Song 	}
1576adf82a4SYonghong Song 
1586adf82a4SYonghong Song 	v = bpf_this_cpu_ptr(p);
1596adf82a4SYonghong Song 	v->c = 3;
1606adf82a4SYonghong Song 	v = bpf_this_cpu_ptr(p);
1616adf82a4SYonghong Song 	v->c = 0;
1626adf82a4SYonghong Song 
1636adf82a4SYonghong Song 	v = bpf_per_cpu_ptr(p, 0);
1646adf82a4SYonghong Song 	if (!v)
1656adf82a4SYonghong Song 		goto out;
1666adf82a4SYonghong Song 	v->c = 1;
1676adf82a4SYonghong Song 	v->d = 2;
1686adf82a4SYonghong Song 
1696adf82a4SYonghong Song 	/* delete */
1706adf82a4SYonghong Song 	p1 = bpf_kptr_xchg(&e->pc, NULL);
1716adf82a4SYonghong Song 	if (!p1)
1726adf82a4SYonghong Song 		goto out;
1736adf82a4SYonghong Song 
1746adf82a4SYonghong Song 	bpf_for(i, 0, nr_cpus) {
1756adf82a4SYonghong Song 		v = bpf_per_cpu_ptr(p, i);
1766adf82a4SYonghong Song 		if (v) {
1776adf82a4SYonghong Song 			if (i == 0)
1786adf82a4SYonghong Song 				cpu0_field_d = v->d;
1796adf82a4SYonghong Song 			sum_field_c += v->c;
1806adf82a4SYonghong Song 		}
1816adf82a4SYonghong Song 	}
1826adf82a4SYonghong Song 
1836adf82a4SYonghong Song 	/* finally release p */
1846adf82a4SYonghong Song 	bpf_percpu_obj_drop(p1);
1856adf82a4SYonghong Song out:
1866adf82a4SYonghong Song 	bpf_rcu_read_unlock();
1876adf82a4SYonghong Song 	return 0;
1886adf82a4SYonghong Song }
1896adf82a4SYonghong Song 
1906adf82a4SYonghong Song char _license[] SEC("license") = "GPL";
191