Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: Introduce BPF_F_PRESERVE_ELEMS for perf event array

Currently, perf event in perf event array is removed from the array when
the map fd used to add the event is closed. This behavior makes it
difficult to the share perf events with perf event array.

Introduce perf event map that keeps the perf event open with a new flag
BPF_F_PRESERVE_ELEMS. With this flag set, perf events in the array are not
removed when the original map fd is closed. Instead, the perf event will
stay in the map until 1) it is explicitly removed from the array; or 2)
the array is freed.

Signed-off-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200930224927.1936644-2-songliubraving@fb.com

authored by

Song Liu and committed by
Alexei Starovoitov
792caccc 3effc06a

+23 -2
+3
include/uapi/linux/bpf.h
··· 414 414 415 415 /* Enable memory-mapping BPF map */ 416 416 BPF_F_MMAPABLE = (1U << 10), 417 + 418 + /* Share perf_event among processes */ 419 + BPF_F_PRESERVE_ELEMS = (1U << 11), 417 420 }; 418 421 419 422 /* Flags for BPF_PROG_QUERY. */
+17 -2
kernel/bpf/arraymap.c
··· 15 15 #include "map_in_map.h" 16 16 17 17 #define ARRAY_CREATE_FLAG_MASK \ 18 - (BPF_F_NUMA_NODE | BPF_F_MMAPABLE | BPF_F_ACCESS_MASK) 18 + (BPF_F_NUMA_NODE | BPF_F_MMAPABLE | BPF_F_ACCESS_MASK | \ 19 + BPF_F_PRESERVE_ELEMS) 19 20 20 21 static void bpf_array_free_percpu(struct bpf_array *array) 21 22 { ··· 63 62 64 63 if (attr->map_type != BPF_MAP_TYPE_ARRAY && 65 64 attr->map_flags & BPF_F_MMAPABLE) 65 + return -EINVAL; 66 + 67 + if (attr->map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY && 68 + attr->map_flags & BPF_F_PRESERVE_ELEMS) 66 69 return -EINVAL; 67 70 68 71 if (attr->value_size > KMALLOC_MAX_SIZE) ··· 1139 1134 struct bpf_event_entry *ee; 1140 1135 int i; 1141 1136 1137 + if (map->map_flags & BPF_F_PRESERVE_ELEMS) 1138 + return; 1139 + 1142 1140 rcu_read_lock(); 1143 1141 for (i = 0; i < array->map.max_entries; i++) { 1144 1142 ee = READ_ONCE(array->ptrs[i]); ··· 1151 1143 rcu_read_unlock(); 1152 1144 } 1153 1145 1146 + static void perf_event_fd_array_map_free(struct bpf_map *map) 1147 + { 1148 + if (map->map_flags & BPF_F_PRESERVE_ELEMS) 1149 + bpf_fd_array_map_clear(map); 1150 + fd_array_map_free(map); 1151 + } 1152 + 1154 1153 static int perf_event_array_map_btf_id; 1155 1154 const struct bpf_map_ops perf_event_array_map_ops = { 1156 1155 .map_meta_equal = bpf_map_meta_equal, 1157 1156 .map_alloc_check = fd_array_map_alloc_check, 1158 1157 .map_alloc = array_map_alloc, 1159 - .map_free = fd_array_map_free, 1158 + .map_free = perf_event_fd_array_map_free, 1160 1159 .map_get_next_key = array_map_get_next_key, 1161 1160 .map_lookup_elem = fd_array_map_lookup_elem, 1162 1161 .map_delete_elem = fd_array_map_delete_elem,
+3
tools/include/uapi/linux/bpf.h
··· 414 414 415 415 /* Enable memory-mapping BPF map */ 416 416 BPF_F_MMAPABLE = (1U << 10), 417 + 418 + /* Share perf_event among processes */ 419 + BPF_F_PRESERVE_ELEMS = (1U << 11), 417 420 }; 418 421 419 422 /* Flags for BPF_PROG_QUERY. */