On Mon, Jun 30, 2025 at 2:21 PM Ihor Solodrai <isolodrai@xxxxxxxx> wrote: > > Currently there is no straightforward way to fill dynptr memory with a > value (most commonly zero). One can do it with bpf_dynptr_write(), but > a temporary buffer is necessary for that. > > Implement bpf_dynptr_memset() - an analogue of memset() from libc. > > Signed-off-by: Ihor Solodrai <isolodrai@xxxxxxxx> > --- > kernel/bpf/helpers.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 47 insertions(+) > > diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c > index f48fa3fe8dec..415b50415598 100644 > --- a/kernel/bpf/helpers.c > +++ b/kernel/bpf/helpers.c > @@ -2907,6 +2907,52 @@ __bpf_kfunc int bpf_dynptr_copy(struct bpf_dynptr *dst_ptr, u32 dst_off, > return 0; > } > > +/** > + * bpf_dynptr_memset() - Fill dynptr memory with a constant byte. > + * @ptr: Destination dynptr - where data will be filled > + * @offset: Offset into the dynptr to start filling from > + * @size: Number of bytes to fill > + * @val: Constant byte to fill the memory with > + * > + * Fills the size bytes of the memory area pointed to by ptr nit: looking at other doc comments, you should use @size when referring to parameter (same for @ptr, though nit-within-nit: we seem to be using "p" for similar functions) > + * at offset with the constant byte val. > + * Returns 0 on success; negative error, otherwise. > + */ > + __bpf_kfunc int bpf_dynptr_memset(struct bpf_dynptr *ptr, u32 offset, u32 size, u8 val) > + { > + struct bpf_dynptr_kern *p = (struct bpf_dynptr_kern *)ptr; > + u32 chunk_sz, write_off; > + char buf[256]; > + void* slice; > + int err; > + > + if (__bpf_dynptr_is_rdonly(p)) > + return -EINVAL; > + > + err = bpf_dynptr_check_off_len(p, offset, size); > + if (err) > + return err; > + > + slice = bpf_dynptr_slice_rdwr(ptr, offset, NULL, size); > + if (likely(slice)) { > + memset(slice, val, size); > + return 0; > + } I think what (I believe, Mykyta) was saying is that by doing slice = bpf_dynptr_slice_rdwr(...); if (likely(slice)) { memset(...); return 0; } if (__bpf_dynptr_is_rdonly(p)) return -EINVAL; err = bpf_dynptr_check_off_len(...); if (err) return err; we have the fastest possible expected happy case, and we'll do all the sanity checking if happy path fails either due to non-contiguity of memory or due to invalid size/offset/read-write permission pw-bot: cr > + > + /* Non-linear data under the dynptr, write from a local buffer */ > + chunk_sz = min_t(u32, sizeof(buf), size); > + memset(buf, val, chunk_sz); > + > + for (write_off = 0; write_off < size; write_off += chunk_sz) { > + chunk_sz = min_t(u32, sizeof(buf), size - write_off); > + err = __bpf_dynptr_write(p, offset + write_off, buf, chunk_sz, 0); > + if (err) > + return err; > + } > + > + return 0; > +} > + > __bpf_kfunc void *bpf_cast_to_kern_ctx(void *obj) > { > return obj; > @@ -3735,6 +3781,7 @@ BTF_ID_FLAGS(func, bpf_dynptr_is_rdonly) > BTF_ID_FLAGS(func, bpf_dynptr_size) > BTF_ID_FLAGS(func, bpf_dynptr_clone) > BTF_ID_FLAGS(func, bpf_dynptr_copy) > +BTF_ID_FLAGS(func, bpf_dynptr_memset) > #ifdef CONFIG_NET > BTF_ID_FLAGS(func, bpf_modify_return_test_tp) > #endif > -- > 2.47.1 >