Add two helpers that are primarily used in combination with the writable-buffer support. The bpf_buffer_reserve() helper sets aside a chunk of buffer space that can be written to, and once all data has been written, the bpf_buffer_commit() helper is used to make the data in the ring buffer visible to userspace. Signed-off-by: Kris Van Hees <kris.van.hees@xxxxxxxxxx> Reviewed-by: Nick Alcock <nick.alcock@xxxxxxxxxx> --- include/uapi/linux/bpf.h | 39 ++++++++++++++++++++++- kernel/bpf/verifier.c | 6 +++- tools/include/uapi/linux/bpf.h | 39 ++++++++++++++++++++++- tools/testing/selftests/bpf/bpf_helpers.h | 4 +++ 4 files changed, 85 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 7bcb707539d1..2b7772aa00b6 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -2681,6 +2681,41 @@ union bpf_attr { * the implementing program type. * Return * 0 on success, or a negative error in case of failure. + * + * int bpf_buffer_reserve(void *ctx, int id, struct bpf_map *map, int size) + * Description + * Reserve *size* bytes in the output buffer for the special BPF + * BPF perf event referenced by *map*, a BPF map of type + * **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. The perf event must have + * the attributes: **PERF_SAMPLE_RAW** as **sample_type**, + * **PERF_TYPE_SOFTWARE** as **type**, and + * **PERF_COUNT_SW_BPF_OUTPUT** as **config**. The reserved space + * will be available as the writable buffer identified with + * numeric ID **id** in the context. + * + * The amount of reserved bytes cannot exceed the page size. + * The chunk of buffer space will be reserved within a single + * page, and if this results in unused space at the end of the + * previous page in the ring-buffer, that unsused space will be + * filled with zeros. + * Return + * 0 on success, or a negative error in case of failure. + * + * int bpf_buffer_commit(void *ctx, int id, struct bpf_map *map) + * Description + * FInalize the previously reserved space in the output buffer + * for the special BPF perf event referenced by *map*, a BPF map + * of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. The perf event must + * have the attributes: **PERF_SAMPLE_RAW** as **sample_type**, + * **PERF_TYPE_SOFTWARE** as **type**, and + * **PERF_COUNT_SW_BPF_OUTPUT** as **config**. + * + * The writable buffer identified with numeric ID **id** in the + * context will be invalidated, and can no longer be used to + * write data to until a new **bpf_buffer_reserve**\ () has been + * invoked. + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -2792,7 +2827,9 @@ union bpf_attr { FN(strtoul), \ FN(sk_storage_get), \ FN(sk_storage_delete), \ - FN(finalize_context), + FN(finalize_context), \ + FN(buffer_reserve), \ + FN(buffer_commit), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 90ae04b4d5c7..ff73ed743a58 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2763,7 +2763,9 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env, case BPF_MAP_TYPE_PERF_EVENT_ARRAY: if (func_id != BPF_FUNC_perf_event_read && func_id != BPF_FUNC_perf_event_output && - func_id != BPF_FUNC_perf_event_read_value) + func_id != BPF_FUNC_perf_event_read_value && + func_id != BPF_FUNC_buffer_reserve && + func_id != BPF_FUNC_buffer_commit) goto error; break; case BPF_MAP_TYPE_STACK_TRACE: @@ -2848,6 +2850,8 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env, case BPF_FUNC_perf_event_read: case BPF_FUNC_perf_event_output: case BPF_FUNC_perf_event_read_value: + case BPF_FUNC_buffer_reserve: + case BPF_FUNC_buffer_commit: if (map->map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) goto error; break; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 7bcb707539d1..2b7772aa00b6 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -2681,6 +2681,41 @@ union bpf_attr { * the implementing program type. * Return * 0 on success, or a negative error in case of failure. + * + * int bpf_buffer_reserve(void *ctx, int id, struct bpf_map *map, int size) + * Description + * Reserve *size* bytes in the output buffer for the special BPF + * BPF perf event referenced by *map*, a BPF map of type + * **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. The perf event must have + * the attributes: **PERF_SAMPLE_RAW** as **sample_type**, + * **PERF_TYPE_SOFTWARE** as **type**, and + * **PERF_COUNT_SW_BPF_OUTPUT** as **config**. The reserved space + * will be available as the writable buffer identified with + * numeric ID **id** in the context. + * + * The amount of reserved bytes cannot exceed the page size. + * The chunk of buffer space will be reserved within a single + * page, and if this results in unused space at the end of the + * previous page in the ring-buffer, that unsused space will be + * filled with zeros. + * Return + * 0 on success, or a negative error in case of failure. + * + * int bpf_buffer_commit(void *ctx, int id, struct bpf_map *map) + * Description + * FInalize the previously reserved space in the output buffer + * for the special BPF perf event referenced by *map*, a BPF map + * of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. The perf event must + * have the attributes: **PERF_SAMPLE_RAW** as **sample_type**, + * **PERF_TYPE_SOFTWARE** as **type**, and + * **PERF_COUNT_SW_BPF_OUTPUT** as **config**. + * + * The writable buffer identified with numeric ID **id** in the + * context will be invalidated, and can no longer be used to + * write data to until a new **bpf_buffer_reserve**\ () has been + * invoked. + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -2792,7 +2827,9 @@ union bpf_attr { FN(strtoul), \ FN(sk_storage_get), \ FN(sk_storage_delete), \ - FN(finalize_context), + FN(finalize_context), \ + FN(buffer_reserve), \ + FN(buffer_commit), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index d98a62b3b56c..72af8157d4db 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -218,6 +218,10 @@ static int (*bpf_sk_storage_delete)(void *map, struct bpf_sock *sk) = (void *)BPF_FUNC_sk_storage_delete; static int (*bpf_finalize_context)(void *ctx, void *map) = (void *) BPF_FUNC_finalize_context; +static int (*bpf_buffer_reserve)(void *ctx, int id, void *map, int size) = + (void *) BPF_FUNC_buffer_reserve; +static int (*bpf_buffer_commit)(void *ctx, int id, void *map) = + (void *) BPF_FUNC_buffer_commit; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions -- 2.20.1