aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/arraymap.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/arraymap.c')
-rw-r--r--kernel/bpf/arraymap.c102
1 files changed, 74 insertions, 28 deletions
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index bfedcbdb4d84..5af30732697b 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -427,59 +427,105 @@ static int __init register_prog_array_map(void)
427} 427}
428late_initcall(register_prog_array_map); 428late_initcall(register_prog_array_map);
429 429
430static void perf_event_array_map_free(struct bpf_map *map) 430static struct bpf_event_entry *bpf_event_entry_gen(struct file *perf_file,
431 struct file *map_file)
431{ 432{
432 bpf_fd_array_map_clear(map); 433 struct bpf_event_entry *ee;
433 fd_array_map_free(map); 434
435 ee = kzalloc(sizeof(*ee), GFP_KERNEL);
436 if (ee) {
437 ee->event = perf_file->private_data;
438 ee->perf_file = perf_file;
439 ee->map_file = map_file;
440 }
441
442 return ee;
443}
444
445static void __bpf_event_entry_free(struct rcu_head *rcu)
446{
447 struct bpf_event_entry *ee;
448
449 ee = container_of(rcu, struct bpf_event_entry, rcu);
450 fput(ee->perf_file);
451 kfree(ee);
452}
453
454static void bpf_event_entry_free_rcu(struct bpf_event_entry *ee)
455{
456 call_rcu(&ee->rcu, __bpf_event_entry_free);
434} 457}
435 458
436static void *perf_event_fd_array_get_ptr(struct bpf_map *map, 459static void *perf_event_fd_array_get_ptr(struct bpf_map *map,
437 struct file *map_file, int fd) 460 struct file *map_file, int fd)
438{ 461{
439 struct perf_event *event;
440 const struct perf_event_attr *attr; 462 const struct perf_event_attr *attr;
441 struct file *file; 463 struct bpf_event_entry *ee;
464 struct perf_event *event;
465 struct file *perf_file;
442 466
443 file = perf_event_get(fd); 467 perf_file = perf_event_get(fd);
444 if (IS_ERR(file)) 468 if (IS_ERR(perf_file))
445 return file; 469 return perf_file;
446 470
447 event = file->private_data; 471 event = perf_file->private_data;
472 ee = ERR_PTR(-EINVAL);
448 473
449 attr = perf_event_attrs(event); 474 attr = perf_event_attrs(event);
450 if (IS_ERR(attr)) 475 if (IS_ERR(attr) || attr->inherit)
451 goto err; 476 goto err_out;
452 477
453 if (attr->inherit) 478 switch (attr->type) {
454 goto err; 479 case PERF_TYPE_SOFTWARE:
455 480 if (attr->config != PERF_COUNT_SW_BPF_OUTPUT)
456 if (attr->type == PERF_TYPE_RAW) 481 goto err_out;
457 return file; 482 /* fall-through */
458 483 case PERF_TYPE_RAW:
459 if (attr->type == PERF_TYPE_HARDWARE) 484 case PERF_TYPE_HARDWARE:
460 return file; 485 ee = bpf_event_entry_gen(perf_file, map_file);
486 if (ee)
487 return ee;
488 ee = ERR_PTR(-ENOMEM);
489 /* fall-through */
490 default:
491 break;
492 }
461 493
462 if (attr->type == PERF_TYPE_SOFTWARE && 494err_out:
463 attr->config == PERF_COUNT_SW_BPF_OUTPUT) 495 fput(perf_file);
464 return file; 496 return ee;
465err:
466 fput(file);
467 return ERR_PTR(-EINVAL);
468} 497}
469 498
470static void perf_event_fd_array_put_ptr(void *ptr) 499static void perf_event_fd_array_put_ptr(void *ptr)
471{ 500{
472 fput((struct file *)ptr); 501 bpf_event_entry_free_rcu(ptr);
502}
503
504static void perf_event_fd_array_release(struct bpf_map *map,
505 struct file *map_file)
506{
507 struct bpf_array *array = container_of(map, struct bpf_array, map);
508 struct bpf_event_entry *ee;
509 int i;
510
511 rcu_read_lock();
512 for (i = 0; i < array->map.max_entries; i++) {
513 ee = READ_ONCE(array->ptrs[i]);
514 if (ee && ee->map_file == map_file)
515 fd_array_map_delete_elem(map, &i);
516 }
517 rcu_read_unlock();
473} 518}
474 519
475static const struct bpf_map_ops perf_event_array_ops = { 520static const struct bpf_map_ops perf_event_array_ops = {
476 .map_alloc = fd_array_map_alloc, 521 .map_alloc = fd_array_map_alloc,
477 .map_free = perf_event_array_map_free, 522 .map_free = fd_array_map_free,
478 .map_get_next_key = array_map_get_next_key, 523 .map_get_next_key = array_map_get_next_key,
479 .map_lookup_elem = fd_array_map_lookup_elem, 524 .map_lookup_elem = fd_array_map_lookup_elem,
480 .map_delete_elem = fd_array_map_delete_elem, 525 .map_delete_elem = fd_array_map_delete_elem,
481 .map_fd_get_ptr = perf_event_fd_array_get_ptr, 526 .map_fd_get_ptr = perf_event_fd_array_get_ptr,
482 .map_fd_put_ptr = perf_event_fd_array_put_ptr, 527 .map_fd_put_ptr = perf_event_fd_array_put_ptr,
528 .map_release = perf_event_fd_array_release,
483}; 529};
484 530
485static struct bpf_map_type_list perf_event_array_type __read_mostly = { 531static struct bpf_map_type_list perf_event_array_type __read_mostly = {