1#include "bpf_experimental.h"
2
3struct val_t {
4 long b, c, d;
5};
6
7struct elem {
8 long sum;
9 struct val_t __percpu_kptr *pc;
10};
11
12struct {
13 __uint(type, BPF_MAP_TYPE_ARRAY);
14 __uint(max_entries, 1);
15 __type(key, int);
16 __type(value, struct elem);
17} array SEC(".maps");
18
19void bpf_rcu_read_lock(void) __ksym;
20void bpf_rcu_read_unlock(void) __ksym;
21
22const volatile int nr_cpus;
23
24/* Initialize the percpu object */
25SEC("?fentry/bpf_fentry_test1")
26int BPF_PROG(test_array_map_1)
27{
28 struct val_t __percpu_kptr *p;
29 struct elem *e;
30 int index = 0;
31
32 e = bpf_map_lookup_elem(&array, &index);
33 if (!e)
34 return 0;
35
36 p = bpf_percpu_obj_new(struct val_t);
37 if (!p)
38 return 0;
39
40 p = bpf_kptr_xchg(&e->pc, p);
41 if (p)
42 bpf_percpu_obj_drop(p);
43
44 return 0;
45}
46
47/* Update percpu data */
48SEC("?fentry/bpf_fentry_test2")
49int BPF_PROG(test_array_map_2)
50{
51 struct val_t __percpu_kptr *p;
52 struct val_t *v;
53 struct elem *e;
54 int index = 0;
55
56 e = bpf_map_lookup_elem(&array, &index);
57 if (!e)
58 return 0;
59
60 p = e->pc;
61 if (!p)
62 return 0;
63
64 v = bpf_per_cpu_ptr(p, 0);
65 if (!v)
66 return 0;
67 v->c = 1;
68 v->d = 2;
69
70 return 0;
71}
72
73int cpu0_field_d, sum_field_c;
74int my_pid;
75
76/* Summarize percpu data */
77SEC("?fentry/bpf_fentry_test3")
78int BPF_PROG(test_array_map_3)
79{
80 struct val_t __percpu_kptr *p;
81 int i, index = 0;
82 struct val_t *v;
83 struct elem *e;
84
85 if ((bpf_get_current_pid_tgid() >> 32) != my_pid)
86 return 0;
87
88 e = bpf_map_lookup_elem(&array, &index);
89 if (!e)
90 return 0;
91
92 p = e->pc;
93 if (!p)
94 return 0;
95
96 bpf_for(i, 0, nr_cpus) {
97 v = bpf_per_cpu_ptr(p, i);
98 if (v) {
99 if (i == 0)
100 cpu0_field_d = v->d;
101 sum_field_c += v->c;
102 }
103 }
104
105 return 0;
106}
107
108/* Explicitly free allocated percpu data */
109SEC("?fentry/bpf_fentry_test4")
110int BPF_PROG(test_array_map_4)
111{
112 struct val_t __percpu_kptr *p;
113 struct elem *e;
114 int index = 0;
115
116 e = bpf_map_lookup_elem(&array, &index);
117 if (!e)
118 return 0;
119
120 /* delete */
121 p = bpf_kptr_xchg(&e->pc, NULL);
122 if (p) {
123 bpf_percpu_obj_drop(p);
124 }
125
126 return 0;
127}
128
129SEC("?fentry.s/bpf_fentry_test1")
130int BPF_PROG(test_array_map_10)
131{
132 struct val_t __percpu_kptr *p, *p1;
133 int i, index = 0;
134 struct val_t *v;
135 struct elem *e;
136
137 if ((bpf_get_current_pid_tgid() >> 32) != my_pid)
138 return 0;
139
140 e = bpf_map_lookup_elem(&array, &index);
141 if (!e)
142 return 0;
143
144 bpf_rcu_read_lock();
145 p = e->pc;
146 if (!p) {
147 p = bpf_percpu_obj_new(struct val_t);
148 if (!p)
149 goto out;
150
151 p1 = bpf_kptr_xchg(&e->pc, p);
152 if (p1) {
153 /* race condition */
154 bpf_percpu_obj_drop(p1);
155 }
156 }
157
158 v = bpf_this_cpu_ptr(p);
159 v->c = 3;
160 v = bpf_this_cpu_ptr(p);
161 v->c = 0;
162
163 v = bpf_per_cpu_ptr(p, 0);
164 if (!v)
165 goto out;
166 v->c = 1;
167 v->d = 2;
168
169 /* delete */
170 p1 = bpf_kptr_xchg(&e->pc, NULL);
171 if (!p1)
172 goto out;
173
174 bpf_for(i, 0, nr_cpus) {
175 v = bpf_per_cpu_ptr(p, i);
176 if (v) {
177 if (i == 0)
178 cpu0_field_d = v->d;
179 sum_field_c += v->c;
180 }
181 }
182
183 /* finally release p */
184 bpf_percpu_obj_drop(p1);
185out:
186 bpf_rcu_read_unlock();
187 return 0;
188}
189
190char _license[] SEC("license") = "GPL";
191

source code of linux/tools/testing/selftests/bpf/progs/percpu_alloc_array.c