diff options
Diffstat (limited to 'kernel/bpf/arraymap.c')
-rw-r--r-- | kernel/bpf/arraymap.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 4d7d5d0ed76a..bc9da93db403 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/filter.h> | 17 | #include <linux/filter.h> |
18 | #include <linux/perf_event.h> | 18 | #include <linux/perf_event.h> |
19 | 19 | ||
20 | #include "map_in_map.h" | ||
21 | |||
20 | static void bpf_array_free_percpu(struct bpf_array *array) | 22 | static void bpf_array_free_percpu(struct bpf_array *array) |
21 | { | 23 | { |
22 | int i; | 24 | int i; |
@@ -602,3 +604,64 @@ static int __init register_cgroup_array_map(void) | |||
602 | } | 604 | } |
603 | late_initcall(register_cgroup_array_map); | 605 | late_initcall(register_cgroup_array_map); |
604 | #endif | 606 | #endif |
607 | |||
608 | static struct bpf_map *array_of_map_alloc(union bpf_attr *attr) | ||
609 | { | ||
610 | struct bpf_map *map, *inner_map_meta; | ||
611 | |||
612 | inner_map_meta = bpf_map_meta_alloc(attr->inner_map_fd); | ||
613 | if (IS_ERR(inner_map_meta)) | ||
614 | return inner_map_meta; | ||
615 | |||
616 | map = fd_array_map_alloc(attr); | ||
617 | if (IS_ERR(map)) { | ||
618 | bpf_map_meta_free(inner_map_meta); | ||
619 | return map; | ||
620 | } | ||
621 | |||
622 | map->inner_map_meta = inner_map_meta; | ||
623 | |||
624 | return map; | ||
625 | } | ||
626 | |||
627 | static void array_of_map_free(struct bpf_map *map) | ||
628 | { | ||
629 | /* map->inner_map_meta is only accessed by syscall which | ||
630 | * is protected by fdget/fdput. | ||
631 | */ | ||
632 | bpf_map_meta_free(map->inner_map_meta); | ||
633 | bpf_fd_array_map_clear(map); | ||
634 | fd_array_map_free(map); | ||
635 | } | ||
636 | |||
637 | static void *array_of_map_lookup_elem(struct bpf_map *map, void *key) | ||
638 | { | ||
639 | struct bpf_map **inner_map = array_map_lookup_elem(map, key); | ||
640 | |||
641 | if (!inner_map) | ||
642 | return NULL; | ||
643 | |||
644 | return READ_ONCE(*inner_map); | ||
645 | } | ||
646 | |||
647 | static const struct bpf_map_ops array_of_map_ops = { | ||
648 | .map_alloc = array_of_map_alloc, | ||
649 | .map_free = array_of_map_free, | ||
650 | .map_get_next_key = array_map_get_next_key, | ||
651 | .map_lookup_elem = array_of_map_lookup_elem, | ||
652 | .map_delete_elem = fd_array_map_delete_elem, | ||
653 | .map_fd_get_ptr = bpf_map_fd_get_ptr, | ||
654 | .map_fd_put_ptr = bpf_map_fd_put_ptr, | ||
655 | }; | ||
656 | |||
657 | static struct bpf_map_type_list array_of_map_type __ro_after_init = { | ||
658 | .ops = &array_of_map_ops, | ||
659 | .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, | ||
660 | }; | ||
661 | |||
662 | static int __init register_array_of_map(void) | ||
663 | { | ||
664 | bpf_register_map_type(&array_of_map_type); | ||
665 | return 0; | ||
666 | } | ||
667 | late_initcall(register_array_of_map); | ||