Blame view

kernel/bpf/arraymap.c 15.4 KB
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of version 2 of the GNU General Public
   * License as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * General Public License for more details.
   */
  #include <linux/bpf.h>
  #include <linux/err.h>
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
14
15
  #include <linux/slab.h>
  #include <linux/mm.h>
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
16
  #include <linux/filter.h>
0cdf5640e   Daniel Borkmann   ebpf: include per...
17
  #include <linux/perf_event.h>
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
18

a10423b87   Alexei Starovoitov   bpf: introduce BP...
19
20
21
  static void bpf_array_free_percpu(struct bpf_array *array)
  {
  	int i;
2a8bc5316   Eric Dumazet   bpf: add schedule...
22
  	for (i = 0; i < array->map.max_entries; i++) {
a10423b87   Alexei Starovoitov   bpf: introduce BP...
23
  		free_percpu(array->pptrs[i]);
2a8bc5316   Eric Dumazet   bpf: add schedule...
24
25
  		cond_resched();
  	}
a10423b87   Alexei Starovoitov   bpf: introduce BP...
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  }
  
  static int bpf_array_alloc_percpu(struct bpf_array *array)
  {
  	void __percpu *ptr;
  	int i;
  
  	for (i = 0; i < array->map.max_entries; i++) {
  		ptr = __alloc_percpu_gfp(array->elem_size, 8,
  					 GFP_USER | __GFP_NOWARN);
  		if (!ptr) {
  			bpf_array_free_percpu(array);
  			return -ENOMEM;
  		}
  		array->pptrs[i] = ptr;
2a8bc5316   Eric Dumazet   bpf: add schedule...
41
  		cond_resched();
a10423b87   Alexei Starovoitov   bpf: introduce BP...
42
43
44
45
  	}
  
  	return 0;
  }
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
46
47
48
  /* Called from syscall */
  static struct bpf_map *array_map_alloc(union bpf_attr *attr)
  {
a10423b87   Alexei Starovoitov   bpf: introduce BP...
49
  	bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
50
51
  	u32 elem_size, index_mask, max_entries;
  	bool unpriv = !capable(CAP_SYS_ADMIN);
422baf61d   Daniel Borkmann   bpf: fix mlock pr...
52
  	u64 cost, array_size, mask64;
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
53
  	struct bpf_array *array;
422baf61d   Daniel Borkmann   bpf: fix mlock pr...
54
  	int ret;
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
55
56
57
  
  	/* check sanity of attributes */
  	if (attr->max_entries == 0 || attr->key_size != 4 ||
823707b68   Alexei Starovoitov   bpf: check for re...
58
  	    attr->value_size == 0 || attr->map_flags)
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
59
  		return ERR_PTR(-EINVAL);
01b3f5215   Alexei Starovoitov   bpf: fix allocati...
60
61
62
63
64
  	if (attr->value_size >= 1 << (KMALLOC_SHIFT_MAX - 1))
  		/* if value_size is bigger, the user space won't be able to
  		 * access the elements.
  		 */
  		return ERR_PTR(-E2BIG);
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
65
  	elem_size = round_up(attr->value_size, 8);
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
66
  	max_entries = attr->max_entries;
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
67

820ef2a0e   Daniel Borkmann   bpf, array: fix o...
68
69
70
71
72
73
74
75
76
77
  	/* On 32 bit archs roundup_pow_of_two() with max_entries that has
  	 * upper most bit set in u32 space is undefined behavior due to
  	 * resulting 1U << 32, so do it manually here in u64 space.
  	 */
  	mask64 = fls_long(max_entries - 1);
  	mask64 = 1ULL << mask64;
  	mask64 -= 1;
  
  	index_mask = mask64;
  	if (unpriv) {
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
78
79
80
81
  		/* round up array size to nearest power of 2,
  		 * since cpu will speculate within index_mask limits
  		 */
  		max_entries = index_mask + 1;
820ef2a0e   Daniel Borkmann   bpf, array: fix o...
82
83
84
85
  		/* Check for overflows. */
  		if (max_entries < attr->max_entries)
  			return ERR_PTR(-E2BIG);
  	}
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
86

a10423b87   Alexei Starovoitov   bpf: introduce BP...
87
88
  	array_size = sizeof(*array);
  	if (percpu)
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
89
  		array_size += (u64) max_entries * sizeof(void *);
a10423b87   Alexei Starovoitov   bpf: introduce BP...
90
  	else
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
91
  		array_size += (u64) max_entries * elem_size;
a10423b87   Alexei Starovoitov   bpf: introduce BP...
92
93
  
  	/* make sure there is no u32 overflow later in round_up() */
422baf61d   Daniel Borkmann   bpf: fix mlock pr...
94
95
  	cost = array_size;
  	if (cost >= U32_MAX - PAGE_SIZE)
daaf427c6   Alexei Starovoitov   bpf: fix arraymap...
96
  		return ERR_PTR(-ENOMEM);
422baf61d   Daniel Borkmann   bpf: fix mlock pr...
97
98
99
100
101
102
103
104
105
106
  	if (percpu) {
  		cost += (u64)attr->max_entries * elem_size * num_possible_cpus();
  		if (cost >= U32_MAX - PAGE_SIZE)
  			return ERR_PTR(-ENOMEM);
  	}
  	cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
  
  	ret = bpf_map_precharge_memlock(cost);
  	if (ret < 0)
  		return ERR_PTR(ret);
daaf427c6   Alexei Starovoitov   bpf: fix arraymap...
107

28fbcfa08   Alexei Starovoitov   bpf: add array ty...
108
  	/* allocate all map elements and zero-initialize them */
251d00bf1   Daniel Borkmann   bpf: don't trigge...
109
110
111
  	array = bpf_map_area_alloc(array_size);
  	if (!array)
  		return ERR_PTR(-ENOMEM);
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
112
113
  	array->index_mask = index_mask;
  	array->map.unpriv_array = unpriv;
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
114
115
  
  	/* copy mandatory map attributes */
a10423b87   Alexei Starovoitov   bpf: introduce BP...
116
  	array->map.map_type = attr->map_type;
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
117
118
119
  	array->map.key_size = attr->key_size;
  	array->map.value_size = attr->value_size;
  	array->map.max_entries = attr->max_entries;
816cfeb77   Daniel Borkmann   bpf: fix wrong ex...
120
  	array->map.map_flags = attr->map_flags;
422baf61d   Daniel Borkmann   bpf: fix mlock pr...
121
  	array->map.pages = cost;
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
122
  	array->elem_size = elem_size;
422baf61d   Daniel Borkmann   bpf: fix mlock pr...
123
124
125
  	if (percpu &&
  	    (elem_size > PCPU_MIN_UNIT_SIZE ||
  	     bpf_array_alloc_percpu(array))) {
251d00bf1   Daniel Borkmann   bpf: don't trigge...
126
  		bpf_map_area_free(array);
a10423b87   Alexei Starovoitov   bpf: introduce BP...
127
128
  		return ERR_PTR(-ENOMEM);
  	}
a10423b87   Alexei Starovoitov   bpf: introduce BP...
129

28fbcfa08   Alexei Starovoitov   bpf: add array ty...
130
  	return &array->map;
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
131
132
133
134
135
136
137
  }
  
  /* Called from syscall or from eBPF program */
  static void *array_map_lookup_elem(struct bpf_map *map, void *key)
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
  	u32 index = *(u32 *)key;
a10423b87   Alexei Starovoitov   bpf: introduce BP...
138
  	if (unlikely(index >= array->map.max_entries))
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
139
  		return NULL;
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
140
  	return array->value + array->elem_size * (index & array->index_mask);
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
141
  }
a10423b87   Alexei Starovoitov   bpf: introduce BP...
142
143
144
145
146
147
148
149
  /* Called from eBPF program */
  static void *percpu_array_map_lookup_elem(struct bpf_map *map, void *key)
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
  	u32 index = *(u32 *)key;
  
  	if (unlikely(index >= array->map.max_entries))
  		return NULL;
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
150
  	return this_cpu_ptr(array->pptrs[index & array->index_mask]);
a10423b87   Alexei Starovoitov   bpf: introduce BP...
151
  }
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value)
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
  	u32 index = *(u32 *)key;
  	void __percpu *pptr;
  	int cpu, off = 0;
  	u32 size;
  
  	if (unlikely(index >= array->map.max_entries))
  		return -ENOENT;
  
  	/* per_cpu areas are zero-filled and bpf programs can only
  	 * access 'value_size' of them, so copying rounded areas
  	 * will not leak any kernel data
  	 */
  	size = round_up(map->value_size, 8);
  	rcu_read_lock();
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
169
  	pptr = array->pptrs[index & array->index_mask];
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
170
171
172
173
174
175
176
  	for_each_possible_cpu(cpu) {
  		bpf_long_memcpy(value + off, per_cpu_ptr(pptr, cpu), size);
  		off += size;
  	}
  	rcu_read_unlock();
  	return 0;
  }
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  /* Called from syscall */
  static int array_map_get_next_key(struct bpf_map *map, void *key, void *next_key)
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
  	u32 index = *(u32 *)key;
  	u32 *next = (u32 *)next_key;
  
  	if (index >= array->map.max_entries) {
  		*next = 0;
  		return 0;
  	}
  
  	if (index == array->map.max_entries - 1)
  		return -ENOENT;
  
  	*next = index + 1;
  	return 0;
  }
  
  /* Called from syscall or from eBPF program */
  static int array_map_update_elem(struct bpf_map *map, void *key, void *value,
  				 u64 map_flags)
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
  	u32 index = *(u32 *)key;
a10423b87   Alexei Starovoitov   bpf: introduce BP...
202
  	if (unlikely(map_flags > BPF_EXIST))
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
203
204
  		/* unknown flags */
  		return -EINVAL;
a10423b87   Alexei Starovoitov   bpf: introduce BP...
205
  	if (unlikely(index >= array->map.max_entries))
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
206
207
  		/* all elements were pre-allocated, cannot insert a new one */
  		return -E2BIG;
a10423b87   Alexei Starovoitov   bpf: introduce BP...
208
  	if (unlikely(map_flags == BPF_NOEXIST))
daaf427c6   Alexei Starovoitov   bpf: fix arraymap...
209
  		/* all elements already exist */
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
210
  		return -EEXIST;
a10423b87   Alexei Starovoitov   bpf: introduce BP...
211
  	if (array->map.map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
212
  		memcpy(this_cpu_ptr(array->pptrs[index & array->index_mask]),
a10423b87   Alexei Starovoitov   bpf: introduce BP...
213
214
  		       value, map->value_size);
  	else
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
215
216
  		memcpy(array->value +
  		       array->elem_size * (index & array->index_mask),
a10423b87   Alexei Starovoitov   bpf: introduce BP...
217
  		       value, map->value_size);
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
218
219
  	return 0;
  }
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  int bpf_percpu_array_update(struct bpf_map *map, void *key, void *value,
  			    u64 map_flags)
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
  	u32 index = *(u32 *)key;
  	void __percpu *pptr;
  	int cpu, off = 0;
  	u32 size;
  
  	if (unlikely(map_flags > BPF_EXIST))
  		/* unknown flags */
  		return -EINVAL;
  
  	if (unlikely(index >= array->map.max_entries))
  		/* all elements were pre-allocated, cannot insert a new one */
  		return -E2BIG;
  
  	if (unlikely(map_flags == BPF_NOEXIST))
  		/* all elements already exist */
  		return -EEXIST;
  
  	/* the user space will provide round_up(value_size, 8) bytes that
  	 * will be copied into per-cpu area. bpf programs can only access
  	 * value_size of it. During lookup the same extra bytes will be
  	 * returned or zeros which were zero-filled by percpu_alloc,
  	 * so no kernel data leaks possible
  	 */
  	size = round_up(map->value_size, 8);
  	rcu_read_lock();
a9bfac14c   Alexei Starovoitov   bpf: prevent out-...
249
  	pptr = array->pptrs[index & array->index_mask];
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
250
251
252
253
254
255
256
  	for_each_possible_cpu(cpu) {
  		bpf_long_memcpy(per_cpu_ptr(pptr, cpu), value + off, size);
  		off += size;
  	}
  	rcu_read_unlock();
  	return 0;
  }
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  /* Called from syscall or from eBPF program */
  static int array_map_delete_elem(struct bpf_map *map, void *key)
  {
  	return -EINVAL;
  }
  
  /* Called when map->refcnt goes to zero, either from workqueue or from syscall */
  static void array_map_free(struct bpf_map *map)
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
  
  	/* at this point bpf_prog->aux->refcnt == 0 and this map->refcnt == 0,
  	 * so the programs (can be more than one that used this map) were
  	 * disconnected from events. Wait for outstanding programs to complete
  	 * and free the array
  	 */
  	synchronize_rcu();
a10423b87   Alexei Starovoitov   bpf: introduce BP...
274
275
  	if (array->map.map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
  		bpf_array_free_percpu(array);
251d00bf1   Daniel Borkmann   bpf: don't trigge...
276
  	bpf_map_area_free(array);
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
277
  }
a2c83fff5   Daniel Borkmann   ebpf: constify va...
278
  static const struct bpf_map_ops array_ops = {
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
279
280
281
282
283
284
285
  	.map_alloc = array_map_alloc,
  	.map_free = array_map_free,
  	.map_get_next_key = array_map_get_next_key,
  	.map_lookup_elem = array_map_lookup_elem,
  	.map_update_elem = array_map_update_elem,
  	.map_delete_elem = array_map_delete_elem,
  };
a2c83fff5   Daniel Borkmann   ebpf: constify va...
286
  static struct bpf_map_type_list array_type __read_mostly = {
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
287
288
289
  	.ops = &array_ops,
  	.type = BPF_MAP_TYPE_ARRAY,
  };
a10423b87   Alexei Starovoitov   bpf: introduce BP...
290
291
292
293
294
295
296
297
298
299
300
301
302
  static const struct bpf_map_ops percpu_array_ops = {
  	.map_alloc = array_map_alloc,
  	.map_free = array_map_free,
  	.map_get_next_key = array_map_get_next_key,
  	.map_lookup_elem = percpu_array_map_lookup_elem,
  	.map_update_elem = array_map_update_elem,
  	.map_delete_elem = array_map_delete_elem,
  };
  
  static struct bpf_map_type_list percpu_array_type __read_mostly = {
  	.ops = &percpu_array_ops,
  	.type = BPF_MAP_TYPE_PERCPU_ARRAY,
  };
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
303
304
  static int __init register_array_map(void)
  {
a2c83fff5   Daniel Borkmann   ebpf: constify va...
305
  	bpf_register_map_type(&array_type);
a10423b87   Alexei Starovoitov   bpf: introduce BP...
306
  	bpf_register_map_type(&percpu_array_type);
28fbcfa08   Alexei Starovoitov   bpf: add array ty...
307
308
309
  	return 0;
  }
  late_initcall(register_array_map);
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
310

2a36f0b92   Wang Nan   bpf: Make the bpf...
311
  static struct bpf_map *fd_array_map_alloc(union bpf_attr *attr)
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
312
  {
2a36f0b92   Wang Nan   bpf: Make the bpf...
313
  	/* only file descriptors can be stored in this type of map */
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
314
315
316
317
  	if (attr->value_size != sizeof(u32))
  		return ERR_PTR(-EINVAL);
  	return array_map_alloc(attr);
  }
2a36f0b92   Wang Nan   bpf: Make the bpf...
318
  static void fd_array_map_free(struct bpf_map *map)
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
319
320
321
322
323
324
325
326
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
  	int i;
  
  	synchronize_rcu();
  
  	/* make sure it's empty */
  	for (i = 0; i < array->map.max_entries; i++)
2a36f0b92   Wang Nan   bpf: Make the bpf...
327
  		BUG_ON(array->ptrs[i] != NULL);
251d00bf1   Daniel Borkmann   bpf: don't trigge...
328
329
  
  	bpf_map_area_free(array);
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
330
  }
2a36f0b92   Wang Nan   bpf: Make the bpf...
331
  static void *fd_array_map_lookup_elem(struct bpf_map *map, void *key)
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
332
333
334
335
336
  {
  	return NULL;
  }
  
  /* only called from syscall */
d056a7887   Daniel Borkmann   bpf, maps: extend...
337
338
  int bpf_fd_array_map_update_elem(struct bpf_map *map, struct file *map_file,
  				 void *key, void *value, u64 map_flags)
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
339
340
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
2a36f0b92   Wang Nan   bpf: Make the bpf...
341
  	void *new_ptr, *old_ptr;
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
342
343
344
345
346
347
348
349
350
  	u32 index = *(u32 *)key, ufd;
  
  	if (map_flags != BPF_ANY)
  		return -EINVAL;
  
  	if (index >= array->map.max_entries)
  		return -E2BIG;
  
  	ufd = *(u32 *)value;
d056a7887   Daniel Borkmann   bpf, maps: extend...
351
  	new_ptr = map->ops->map_fd_get_ptr(map, map_file, ufd);
2a36f0b92   Wang Nan   bpf: Make the bpf...
352
353
  	if (IS_ERR(new_ptr))
  		return PTR_ERR(new_ptr);
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
354

2a36f0b92   Wang Nan   bpf: Make the bpf...
355
356
357
  	old_ptr = xchg(array->ptrs + index, new_ptr);
  	if (old_ptr)
  		map->ops->map_fd_put_ptr(old_ptr);
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
358
359
360
  
  	return 0;
  }
2a36f0b92   Wang Nan   bpf: Make the bpf...
361
  static int fd_array_map_delete_elem(struct bpf_map *map, void *key)
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
362
363
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
2a36f0b92   Wang Nan   bpf: Make the bpf...
364
  	void *old_ptr;
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
365
366
367
368
  	u32 index = *(u32 *)key;
  
  	if (index >= array->map.max_entries)
  		return -E2BIG;
2a36f0b92   Wang Nan   bpf: Make the bpf...
369
370
371
  	old_ptr = xchg(array->ptrs + index, NULL);
  	if (old_ptr) {
  		map->ops->map_fd_put_ptr(old_ptr);
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
372
373
374
375
376
  		return 0;
  	} else {
  		return -ENOENT;
  	}
  }
d056a7887   Daniel Borkmann   bpf, maps: extend...
377
378
  static void *prog_fd_array_get_ptr(struct bpf_map *map,
  				   struct file *map_file, int fd)
2a36f0b92   Wang Nan   bpf: Make the bpf...
379
380
381
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
  	struct bpf_prog *prog = bpf_prog_get(fd);
d056a7887   Daniel Borkmann   bpf, maps: extend...
382

2a36f0b92   Wang Nan   bpf: Make the bpf...
383
384
385
386
387
388
389
  	if (IS_ERR(prog))
  		return prog;
  
  	if (!bpf_prog_array_compatible(array, prog)) {
  		bpf_prog_put(prog);
  		return ERR_PTR(-EINVAL);
  	}
d056a7887   Daniel Borkmann   bpf, maps: extend...
390

2a36f0b92   Wang Nan   bpf: Make the bpf...
391
392
393
394
395
  	return prog;
  }
  
  static void prog_fd_array_put_ptr(void *ptr)
  {
1aacde3d2   Daniel Borkmann   bpf: generally mo...
396
  	bpf_prog_put(ptr);
2a36f0b92   Wang Nan   bpf: Make the bpf...
397
  }
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
398
  /* decrement refcnt of all bpf_progs that are stored in this map */
2a36f0b92   Wang Nan   bpf: Make the bpf...
399
  void bpf_fd_array_map_clear(struct bpf_map *map)
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
400
401
402
403
404
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
  	int i;
  
  	for (i = 0; i < array->map.max_entries; i++)
2a36f0b92   Wang Nan   bpf: Make the bpf...
405
  		fd_array_map_delete_elem(map, &i);
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
406
407
408
  }
  
  static const struct bpf_map_ops prog_array_ops = {
2a36f0b92   Wang Nan   bpf: Make the bpf...
409
410
  	.map_alloc = fd_array_map_alloc,
  	.map_free = fd_array_map_free,
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
411
  	.map_get_next_key = array_map_get_next_key,
2a36f0b92   Wang Nan   bpf: Make the bpf...
412
  	.map_lookup_elem = fd_array_map_lookup_elem,
2a36f0b92   Wang Nan   bpf: Make the bpf...
413
414
415
  	.map_delete_elem = fd_array_map_delete_elem,
  	.map_fd_get_ptr = prog_fd_array_get_ptr,
  	.map_fd_put_ptr = prog_fd_array_put_ptr,
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
416
417
418
419
420
421
422
423
424
425
426
427
428
  };
  
  static struct bpf_map_type_list prog_array_type __read_mostly = {
  	.ops = &prog_array_ops,
  	.type = BPF_MAP_TYPE_PROG_ARRAY,
  };
  
  static int __init register_prog_array_map(void)
  {
  	bpf_register_map_type(&prog_array_type);
  	return 0;
  }
  late_initcall(register_prog_array_map);
ea317b267   Kaixu Xia   bpf: Add new bpf ...
429

3b1efb196   Daniel Borkmann   bpf, maps: flush ...
430
431
  static struct bpf_event_entry *bpf_event_entry_gen(struct file *perf_file,
  						   struct file *map_file)
ea317b267   Kaixu Xia   bpf: Add new bpf ...
432
  {
3b1efb196   Daniel Borkmann   bpf, maps: flush ...
433
  	struct bpf_event_entry *ee;
858d68f10   Daniel Borkmann   bpf: bpf_event_en...
434
  	ee = kzalloc(sizeof(*ee), GFP_ATOMIC);
3b1efb196   Daniel Borkmann   bpf, maps: flush ...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
  	if (ee) {
  		ee->event = perf_file->private_data;
  		ee->perf_file = perf_file;
  		ee->map_file = map_file;
  	}
  
  	return ee;
  }
  
  static void __bpf_event_entry_free(struct rcu_head *rcu)
  {
  	struct bpf_event_entry *ee;
  
  	ee = container_of(rcu, struct bpf_event_entry, rcu);
  	fput(ee->perf_file);
  	kfree(ee);
  }
  
  static void bpf_event_entry_free_rcu(struct bpf_event_entry *ee)
  {
  	call_rcu(&ee->rcu, __bpf_event_entry_free);
ea317b267   Kaixu Xia   bpf: Add new bpf ...
456
  }
d056a7887   Daniel Borkmann   bpf, maps: extend...
457
458
  static void *perf_event_fd_array_get_ptr(struct bpf_map *map,
  					 struct file *map_file, int fd)
ea317b267   Kaixu Xia   bpf: Add new bpf ...
459
  {
ea317b267   Kaixu Xia   bpf: Add new bpf ...
460
  	const struct perf_event_attr *attr;
3b1efb196   Daniel Borkmann   bpf, maps: flush ...
461
462
463
  	struct bpf_event_entry *ee;
  	struct perf_event *event;
  	struct file *perf_file;
ea317b267   Kaixu Xia   bpf: Add new bpf ...
464

3b1efb196   Daniel Borkmann   bpf, maps: flush ...
465
466
467
  	perf_file = perf_event_get(fd);
  	if (IS_ERR(perf_file))
  		return perf_file;
e03e7ee34   Alexei Starovoitov   perf/bpf: Convert...
468

3b1efb196   Daniel Borkmann   bpf, maps: flush ...
469
470
  	event = perf_file->private_data;
  	ee = ERR_PTR(-EINVAL);
ea317b267   Kaixu Xia   bpf: Add new bpf ...
471
472
  
  	attr = perf_event_attrs(event);
3b1efb196   Daniel Borkmann   bpf, maps: flush ...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
  	if (IS_ERR(attr) || attr->inherit)
  		goto err_out;
  
  	switch (attr->type) {
  	case PERF_TYPE_SOFTWARE:
  		if (attr->config != PERF_COUNT_SW_BPF_OUTPUT)
  			goto err_out;
  		/* fall-through */
  	case PERF_TYPE_RAW:
  	case PERF_TYPE_HARDWARE:
  		ee = bpf_event_entry_gen(perf_file, map_file);
  		if (ee)
  			return ee;
  		ee = ERR_PTR(-ENOMEM);
  		/* fall-through */
  	default:
  		break;
  	}
62544ce8e   Alexei Starovoitov   bpf: fix bpf_perf...
491

3b1efb196   Daniel Borkmann   bpf, maps: flush ...
492
493
494
  err_out:
  	fput(perf_file);
  	return ee;
ea317b267   Kaixu Xia   bpf: Add new bpf ...
495
496
497
498
  }
  
  static void perf_event_fd_array_put_ptr(void *ptr)
  {
3b1efb196   Daniel Borkmann   bpf, maps: flush ...
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
  	bpf_event_entry_free_rcu(ptr);
  }
  
  static void perf_event_fd_array_release(struct bpf_map *map,
  					struct file *map_file)
  {
  	struct bpf_array *array = container_of(map, struct bpf_array, map);
  	struct bpf_event_entry *ee;
  	int i;
  
  	rcu_read_lock();
  	for (i = 0; i < array->map.max_entries; i++) {
  		ee = READ_ONCE(array->ptrs[i]);
  		if (ee && ee->map_file == map_file)
  			fd_array_map_delete_elem(map, &i);
  	}
  	rcu_read_unlock();
ea317b267   Kaixu Xia   bpf: Add new bpf ...
516
517
518
519
  }
  
  static const struct bpf_map_ops perf_event_array_ops = {
  	.map_alloc = fd_array_map_alloc,
3b1efb196   Daniel Borkmann   bpf, maps: flush ...
520
  	.map_free = fd_array_map_free,
ea317b267   Kaixu Xia   bpf: Add new bpf ...
521
522
  	.map_get_next_key = array_map_get_next_key,
  	.map_lookup_elem = fd_array_map_lookup_elem,
ea317b267   Kaixu Xia   bpf: Add new bpf ...
523
524
525
  	.map_delete_elem = fd_array_map_delete_elem,
  	.map_fd_get_ptr = perf_event_fd_array_get_ptr,
  	.map_fd_put_ptr = perf_event_fd_array_put_ptr,
3b1efb196   Daniel Borkmann   bpf, maps: flush ...
526
  	.map_release = perf_event_fd_array_release,
ea317b267   Kaixu Xia   bpf: Add new bpf ...
527
528
529
530
531
532
533
534
535
536
537
538
539
  };
  
  static struct bpf_map_type_list perf_event_array_type __read_mostly = {
  	.ops = &perf_event_array_ops,
  	.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
  };
  
  static int __init register_perf_event_array_map(void)
  {
  	bpf_register_map_type(&perf_event_array_type);
  	return 0;
  }
  late_initcall(register_perf_event_array_map);
4ed8ec521   Martin KaFai Lau   cgroup: bpf: Add ...
540

60d20f919   Sargun Dhillon   bpf: Add bpf_curr...
541
  #ifdef CONFIG_CGROUPS
4ed8ec521   Martin KaFai Lau   cgroup: bpf: Add ...
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
  static void *cgroup_fd_array_get_ptr(struct bpf_map *map,
  				     struct file *map_file /* not used */,
  				     int fd)
  {
  	return cgroup_get_from_fd(fd);
  }
  
  static void cgroup_fd_array_put_ptr(void *ptr)
  {
  	/* cgroup_put free cgrp after a rcu grace period */
  	cgroup_put(ptr);
  }
  
  static void cgroup_fd_array_free(struct bpf_map *map)
  {
  	bpf_fd_array_map_clear(map);
  	fd_array_map_free(map);
  }
  
  static const struct bpf_map_ops cgroup_array_ops = {
  	.map_alloc = fd_array_map_alloc,
  	.map_free = cgroup_fd_array_free,
  	.map_get_next_key = array_map_get_next_key,
  	.map_lookup_elem = fd_array_map_lookup_elem,
  	.map_delete_elem = fd_array_map_delete_elem,
  	.map_fd_get_ptr = cgroup_fd_array_get_ptr,
  	.map_fd_put_ptr = cgroup_fd_array_put_ptr,
  };
  
  static struct bpf_map_type_list cgroup_array_type __read_mostly = {
  	.ops = &cgroup_array_ops,
  	.type = BPF_MAP_TYPE_CGROUP_ARRAY,
  };
  
  static int __init register_cgroup_array_map(void)
  {
  	bpf_register_map_type(&cgroup_array_type);
  	return 0;
  }
  late_initcall(register_cgroup_array_map);
  #endif