BPF List
 help / color / mirror / Atom feed
From: Anton Protopopov <a.s.protopopov@gmail.com>
To: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Cc: bpf <bpf@vger.kernel.org>, Alexei Starovoitov <ast@kernel.org>,
	Andrii Nakryiko <andrii@kernel.org>,
	Anton Protopopov <aspsk@isovalent.com>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Eduard Zingerman <eddyz87@gmail.com>,
	Quentin Monnet <qmo@kernel.org>,
	Yonghong Song <yonghong.song@linux.dev>
Subject: Re: [PATCH v2 bpf-next 03/13] bpf, x86: add new map type: instructions array
Date: Mon, 22 Sep 2025 10:38:37 +0000	[thread overview]
Message-ID: <aNEnLZzOyEuNOtXu@mail.gmail.com> (raw)
In-Reply-To: <CAADnVQJsuxh5HrNKW_-_yuO5FqLQ8S4A4YN9bZfRHhO5pt5Dtg@mail.gmail.com>

On 25/09/19 05:30PM, Alexei Starovoitov wrote:
> On Sat, Sep 13, 2025 at 12:33 PM Anton Protopopov
> <a.s.protopopov@gmail.com> wrote:
> > --- /dev/null
> > +++ b/kernel/bpf/bpf_insn_array.c
> > @@ -0,0 +1,336 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +
> 
> add copyright?

Yes, thanks!

> > +#include <linux/bpf.h>
> > +#include <linux/sort.h>
> > +
> > +#define MAX_INSN_ARRAY_ENTRIES 256
> > +
> > +struct bpf_insn_array {
> > +       struct bpf_map map;
> > +       struct mutex state_mutex;
> > +       int state;
> > +       long *ips;
> > +       DECLARE_FLEX_ARRAY(struct bpf_insn_ptr, ptrs);
> > +};
> > +
> > +enum {
> > +       INSN_ARRAY_STATE_FREE = 0,
> > +       INSN_ARRAY_STATE_INIT,
> > +       INSN_ARRAY_STATE_READY,
> > +};
> > +
> > +#define cast_insn_array(MAP_PTR) \
> > +       container_of(MAP_PTR, struct bpf_insn_array, map)
> 
> container_of((MAP_PTR)
> checkpatch will be happier.

Thanks, fixed

> > +
> > +#define INSN_DELETED ((u32)-1)
> > +
> > +static inline u32 insn_array_alloc_size(u32 max_entries)
> > +{
> > +       const u32 base_size = sizeof(struct bpf_insn_array);
> > +       const u32 entry_size = sizeof(struct bpf_insn_ptr);
> > +
> > +       return base_size + entry_size * max_entries;
> > +}
> > +
> > +static int insn_array_alloc_check(union bpf_attr *attr)
> > +{
> > +       if (attr->max_entries == 0 ||
> > +           attr->key_size != 4 ||
> > +           attr->value_size != 8 ||
> > +           attr->map_flags != 0)
> > +               return -EINVAL;
> 
> Use single line or two, instead of 4.

Done

> > +
> > +       if (attr->max_entries > MAX_INSN_ARRAY_ENTRIES)
> > +               return -E2BIG;
> > +
> > +       return 0;
> > +}
> > +
> > +static void insn_array_free(struct bpf_map *map)
> > +{
> > +       struct bpf_insn_array *insn_array = cast_insn_array(map);
> > +
> > +       kfree(insn_array->ips);
> > +       bpf_map_area_free(insn_array);
> > +}
> > +
> > +static struct bpf_map *insn_array_alloc(union bpf_attr *attr)
> > +{
> > +       u64 size = insn_array_alloc_size(attr->max_entries);
> > +       struct bpf_insn_array *insn_array;
> > +
> > +       insn_array = bpf_map_area_alloc(size, NUMA_NO_NODE);
> > +       if (!insn_array)
> > +               return ERR_PTR(-ENOMEM);
> > +
> > +       insn_array->ips = kcalloc(attr->max_entries, sizeof(long), GFP_KERNEL);
> > +       if (!insn_array->ips) {
> > +               insn_array_free(&insn_array->map);
> > +               return ERR_PTR(-ENOMEM);
> > +       }
> > +
> > +       bpf_map_init_from_attr(&insn_array->map, attr);
> > +
> > +       mutex_init(&insn_array->state_mutex);
> > +       insn_array->state = INSN_ARRAY_STATE_FREE;
> > +
> > +       return &insn_array->map;
> > +}
> > +
> > +static int insn_array_get_next_key(struct bpf_map *map, void *key, void *next_key)
> > +{
> > +       struct bpf_insn_array *insn_array = cast_insn_array(map);
> > +       u32 index = key ? *(u32 *)key : U32_MAX;
> > +       u32 *next = (u32 *)next_key;
> > +
> > +       if (index >= insn_array->map.max_entries) {
> > +               *next = 0;
> > +               return 0;
> > +       }
> > +
> > +       if (index == insn_array->map.max_entries - 1)
> > +               return -ENOENT;
> > +
> > +       *next = index + 1;
> > +       return 0;
> > +}
> 
> Full copy paste of array_map_get_next_key() is a bit too much.
> Pls refactor array_map_get_next_key() to avoid casting
> to struct bpf_array, then such a helper can work for both maps.

Ok, thank, will do.

> > +
> > +static void *insn_array_lookup_elem(struct bpf_map *map, void *key)
> > +{
> > +       struct bpf_insn_array *insn_array = cast_insn_array(map);
> > +       u32 index = *(u32 *)key;
> > +
> > +       if (unlikely(index >= insn_array->map.max_entries))
> > +               return NULL;
> > +
> > +       return &insn_array->ptrs[index].user_value;
> > +}
> > +
> > +static long insn_array_update_elem(struct bpf_map *map, void *key, void *value, u64 map_flags)
> > +{
> > +       struct bpf_insn_array *insn_array = cast_insn_array(map);
> > +       u32 index = *(u32 *)key;
> > +       struct bpf_insn_array_value val = {};
> > +       int err = 0;
> > +
> > +       if (unlikely((map_flags & ~BPF_F_LOCK) > BPF_EXIST))
> > +               return -EINVAL;
> 
> copy paste gone wrong. BPF_F_LOCK is not supported here.

thanks, removed

> > +
> > +       if (unlikely(index >= insn_array->map.max_entries))
> > +               return -E2BIG;
> > +
> > +       if (unlikely(map_flags & BPF_NOEXIST))
> > +               return -EEXIST;
> > +
> > +       /* No updates for maps in use */
> > +       if (!mutex_trylock(&insn_array->state_mutex))
> > +               return -EBUSY;
> 
> trylock ?!
> 
> If I'm reading it correctly
> check_map_func_compatibility() prevents usage of this helper
> from the prog, so this is syscall only,
> but trylock?!

See the comment below.

> > +
> > +       if (insn_array->state != INSN_ARRAY_STATE_FREE) {
> > +               err = -EBUSY;
> > +               goto unlock;
> > +       }
> > +
> > +       copy_map_value(map, &val, value);
> > +       if (val.jitted_off || val.xlated_off == INSN_DELETED) {
> > +               err = -EINVAL;
> > +               goto unlock;
> > +       }
> > +
> > +       insn_array->ptrs[index].orig_xlated_off = val.xlated_off;
> > +       insn_array->ptrs[index].user_value.xlated_off = val.xlated_off;
> > +
> > +unlock:
> > +       mutex_unlock(&insn_array->state_mutex);
> > +       return err;
> > +}
> > +
> > +static long insn_array_delete_elem(struct bpf_map *map, void *key)
> > +{
> > +       return -EINVAL;
> > +}
> > +
> > +static int insn_array_check_btf(const struct bpf_map *map,
> > +                             const struct btf *btf,
> > +                             const struct btf_type *key_type,
> > +                             const struct btf_type *value_type)
> > +{
> > +       if (!btf_type_is_i32(key_type))
> > +               return -EINVAL;
> > +
> > +       if (!btf_type_is_i64(value_type))
> > +               return -EINVAL;
> > +
> > +       return 0;
> > +}
> > +
> > +static u64 insn_array_mem_usage(const struct bpf_map *map)
> > +{
> > +       u64 extra_size = 0;
> > +
> > +       extra_size += sizeof(long) * map->max_entries; /* insn_array->ips */
> > +
> > +       return insn_array_alloc_size(map->max_entries) + extra_size;
> > +}
> > +
> > +BTF_ID_LIST_SINGLE(insn_array_btf_ids, struct, bpf_insn_array)
> > +
> > +const struct bpf_map_ops insn_array_map_ops = {
> > +       .map_alloc_check = insn_array_alloc_check,
> > +       .map_alloc = insn_array_alloc,
> > +       .map_free = insn_array_free,
> > +       .map_get_next_key = insn_array_get_next_key,
> > +       .map_lookup_elem = insn_array_lookup_elem,
> > +       .map_update_elem = insn_array_update_elem,
> > +       .map_delete_elem = insn_array_delete_elem,
> > +       .map_check_btf = insn_array_check_btf,
> > +       .map_mem_usage = insn_array_mem_usage,
> > +       .map_btf_id = &insn_array_btf_ids[0],
> > +};
> > +
> > +static bool is_insn_array(const struct bpf_map *map)
> > +{
> > +       return map->map_type == BPF_MAP_TYPE_INSN_ARRAY;
> > +}
> > +
> > +static inline bool valid_offsets(const struct bpf_insn_array *insn_array,
> > +                                const struct bpf_prog *prog)
> > +{
> > +       u32 off;
> > +       int i;
> > +
> > +       for (i = 0; i < insn_array->map.max_entries; i++) {
> > +               off = insn_array->ptrs[i].orig_xlated_off;
> > +
> > +               if (off >= prog->len)
> > +                       return false;
> > +
> > +               if (off > 0) {
> > +                       if (prog->insnsi[off-1].code == (BPF_LD | BPF_DW | BPF_IMM))
> > +                               return false;
> > +               }
> > +       }
> > +
> > +       return true;
> > +}
> > +
> > +int bpf_insn_array_init(struct bpf_map *map, const struct bpf_prog *prog)
> > +{
> > +       struct bpf_insn_array *insn_array = cast_insn_array(map);
> > +       int i;
> > +
> > +       if (!valid_offsets(insn_array, prog))
> > +               return -EINVAL;
> > +
> > +       /*
> > +        * There can be only one program using the map
> > +        */
> > +       mutex_lock(&insn_array->state_mutex);
> > +       if (insn_array->state != INSN_ARRAY_STATE_FREE) {
> > +               mutex_unlock(&insn_array->state_mutex);
> > +               return -EBUSY;
> > +       }
> > +       insn_array->state = INSN_ARRAY_STATE_INIT;
> > +       mutex_unlock(&insn_array->state_mutex);
> 
> only verifier calls this helpers, no?
> Why all the mutexes here and below ?
> All the mutexes is a big red flag to me.
> Will stop any further comments here.

Mutex came here from the future patch for static keys.
I will see how to rewrite this with just an atomic state.
(Try lock came from fixing some robot report which I struggle to find now...)

  reply	other threads:[~2025-09-22 10:32 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-13 19:39 [PATCH v2 bpf-next 00/13] BPF indirect jumps Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 01/13] bpf: fix the return value of push_stack Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 02/13] bpf: save the start of functions in bpf_prog_aux Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 03/13] bpf, x86: add new map type: instructions array Anton Protopopov
2025-09-15  4:09   ` kernel test robot
2025-09-20  0:30   ` Alexei Starovoitov
2025-09-22 10:38     ` Anton Protopopov [this message]
2025-09-22 16:16       ` Alexei Starovoitov
2025-09-22 17:37         ` Anton Protopopov
2025-09-22 17:57           ` Alexei Starovoitov
2025-09-22 19:23             ` Anton Protopopov
2025-09-22 20:24               ` Alexei Starovoitov
2025-09-23  9:55             ` Anton Protopopov
2025-09-23 15:14               ` Alexei Starovoitov
2025-09-13 19:39 ` [PATCH v2 bpf-next 04/13] selftests/bpf: add selftests for new insn_array map Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 05/13] bpf: support instructions arrays with constants blinding Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 06/13] selftests/bpf: test instructions arrays with blinding Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 07/13] bpf, x86: allow indirect jumps to r8...r15 Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 08/13] bpf, x86: add support for indirect jumps Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 09/13] bpf: disasm: add support for BPF_JMP|BPF_JA|BPF_X Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 10/13] libbpf: fix formatting of bpf_object__append_subprog_code Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 11/13] libbpf: support llvm-generated indirect jumps Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 12/13] bpftool: Recognize insn_array map type Anton Protopopov
2025-09-16 20:33   ` Quentin Monnet
2025-09-18  8:11     ` Anton Protopopov
2025-09-13 19:39 ` [PATCH v2 bpf-next 13/13] selftests/bpf: add selftests for indirect jumps Anton Protopopov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aNEnLZzOyEuNOtXu@mail.gmail.com \
    --to=a.s.protopopov@gmail.com \
    --cc=alexei.starovoitov@gmail.com \
    --cc=andrii@kernel.org \
    --cc=aspsk@isovalent.com \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=qmo@kernel.org \
    --cc=yonghong.song@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox