All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yonghong Song <yonghong.song@linux.dev>
To: Dave Marchevsky <davemarchevsky@fb.com>, bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>,
	Martin KaFai Lau <martin.lau@kernel.org>,
	Kernel Team <kernel-team@fb.com>
Subject: Re: [PATCH v1 bpf-next 2/4] bpf: Refactor btf_find_field with btf_field_info_search
Date: Mon, 30 Oct 2023 12:56:10 -0700	[thread overview]
Message-ID: <c6770450-b5f3-4def-8541-d6c4371f8cb7@linux.dev> (raw)
In-Reply-To: <ce4cbfe1-fd20-413a-a3ad-d34bac38fca1@linux.dev>


On 10/30/23 12:31 PM, Yonghong Song wrote:
>
> On 10/23/23 3:00 PM, Dave Marchevsky wrote:
>> btf_find_field takes (btf_type, special_field_types) and returns info
>> about the specific special fields in btf_type, in the form of an array
>> of struct btf_field info. The meat of this 'search for special fields'
>
> struct btf_field_info.
>
>> process happens in btf_find_datasec_var and btf_find_struct_field
>> helpers: each member is examined and, if it's special, a struct
>> btf_field_info describing it is added to the return array. Indeed, any
>> function that might add to the output probably also looks at struct
>> members or datasec vars.
>>
>> Most of the parameters passed around between helpers doing the search
>> can be grouped into two categories: "info about the output array" and
>> "info about which fields to search for". This patch joins those together
>> in struct btf_field_info_search, simplifying the signatures of most
>> helpers involved in the search, including array flattening helper that
>> later patches in the series will add.
>>
>> The aforementioned array flattening logic will greatly increase the
>> number of btf_field_info's needed to describe some structs, so this
>> patch also turns the statically-sized struct btf_field_info
>> info_arr[BTF_FIELDS_MAX] into a growable array with a larger max size.
>
> Since this patch is a 'refactoring' patch, let us delay this patch


sorry. typo. "this patch" -> "this change".


> until the next one. This patch should be strictly a refactoring
> patch so it becomes easier to verify changes.
>
>>
>> Implementation notes:
>>    * BTF_FIELDS_MAX is now max size of growable btf_field_info *infos
>>      instead of initial (and max) size of static result array
>>      * Static array before had 10 elems (+1 tmp btf_field_info)
>>      * growable array starts with 16 and doubles every time it needs to
>>        grow, up to BTF_FIELDS_MAX of 256
>>
>>    * __next_field_infos is used with next_cnt > 1 later in the series
>>
>>    * btf_find_{datasec_var, struct_field} have special logic for an edge
>>      case where the result array is full but the field being examined
>>      gets BTF_FIELD_IGNORE return from btf_find_{struct, 
>> kptr,graph_root}
>>      * If result wasn't BTF_FIELD_IGNORE, a btf_field_info would have to
>>        be added to the array. Since it is we can look at next field.
>>      * Before this patch the logic handling this edge case was hard to
>>        follow and used a tmp btf_struct_info. This patch moves the
>>        add-if-not-ignore logic down into btf_find_{struct, kptr,
>>        graph_root}, removing the need to opportunistically grab a
>>        btf_field_info to populate before knowing if it's actually
>>        necessary. Now a new one is grabbed only if the field shouldn't
>>        be ignored.
>
> This extra 'tmp' btf_field_info approach sounds okay to me
> in the original code. The previous code has a static size
> and there is no realloc. Now you introduced realloc, so
> removing extra 'tmp' seems do make sense.
>
>
>>
>>    * Within btf_find_{datasec_var, struct_field}, each member is
>>      currently examined in two phases: first btf_get_field_type checks
>>      the member type name, then btf_find_{struct,graph_root,kptr} do
>>      additional sanity checking and populate struct btf_field_info. Kptr
>>      fields don't have a specific type name, though, so
>>      btf_get_field_type assumes that - if we're looking for kptrs - any
>>      member that fails type name check could be a kptr field.
>>      * As a result btf_find_kptr effectively does all the pointer
>>        hopping, sanity checking, and info population. Instead of trying
>>        to fit kptr handling into this two-phase model, where it's
>>        unwieldy, handle it in a separate codepath when name matching
>>        fails.
>>
>> Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
>> ---
>>   include/linux/bpf.h |   4 +-
>>   kernel/bpf/btf.c    | 331 +++++++++++++++++++++++++++++---------------
>>   2 files changed, 219 insertions(+), 116 deletions(-)
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index b4825d3cdb29..e07cac5cc3cf 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -171,8 +171,8 @@ struct bpf_map_ops {
>>   };
>>     enum {
>> -    /* Support at most 10 fields in a BTF type */
>> -    BTF_FIELDS_MAX       = 10,
>> +    /* Support at most 256 fields in a BTF type */
>> +    BTF_FIELDS_MAX       = 256,
>>   };
>>     enum btf_field_type {
>> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
>> index 975ef8e73393..e999ba85c363 100644
>> --- a/kernel/bpf/btf.c
>> +++ b/kernel/bpf/btf.c
>> @@ -3257,25 +3257,94 @@ struct btf_field_info {
>>       };
>>   };
>>   +struct btf_field_info_search {
>> +    /* growable array. allocated in __next_field_infos
>> +     * free'd in btf_parse_fields
>> +     */
>> +    struct btf_field_info *infos;
>> +    /* size of infos */
>> +    int info_cnt;
>> +    /* index of next btf_field_info to populate */
>> +    int idx;
>> +
>> +    /* btf_field_types to search for */
>> +    u32 field_mask;
>> +    /* btf_field_types found earlier */
>> +    u32 seen_mask;
>> +};
>> +
>> +/* Reserve next_cnt contiguous btf_field_info's for caller to populate
>> + * Returns ptr to first reserved btf_field_info
>> + */
>> +static struct btf_field_info *__next_field_infos(struct 
>> btf_field_info_search *srch,
>> +                         u32 next_cnt)
>> +{
>> +    struct btf_field_info *new_infos, *ret;
>> +
>> +    if (!next_cnt)
>> +        return ERR_PTR(-EINVAL);
>
> Looks next_cnt is never 0.
>
>> +
>> +    if (srch->idx + next_cnt < srch->info_cnt)
>> +        goto nogrow_out;
>> +
>> +    /* Need to grow */
>> +    if (srch->idx + next_cnt > BTF_FIELDS_MAX)
>> +        return ERR_PTR(-E2BIG);
>> +
>> +    while (srch->idx + next_cnt >= srch->info_cnt)
>> +        srch->info_cnt = srch->infos ? srch->info_cnt * 2 : 16;
>> +
>> +    new_infos = krealloc(srch->infos,
>> +                 srch->info_cnt * sizeof(struct btf_field_info),
>> +                 GFP_KERNEL | __GFP_NOWARN);
>> +    if (!new_infos)
>> +        return ERR_PTR(-ENOMEM);
>> +    srch->infos = new_infos;
>> +
>> +nogrow_out:
>> +    ret = &srch->infos[srch->idx];
>> +    srch->idx += next_cnt;
>> +    return ret;
>> +}
>> +
>> +/* Request srch's next free btf_field_info to populate, possibly 
>> growing
>> + * srch->infos
>> + */
>> +static struct btf_field_info *__next_field_info(struct 
>> btf_field_info_search *srch)
>> +{
>> +    return __next_field_infos(srch, 1);
>> +}
>> +
>>   static int btf_find_struct(const struct btf *btf, const struct 
>> btf_type *t,
>>                  u32 off, int sz, enum btf_field_type field_type,
>> -               struct btf_field_info *info)
>> +               struct btf_field_info_search *srch)
>>   {
>> +    struct btf_field_info *info;
>> +
>>       if (!__btf_type_is_struct(t))
>>           return BTF_FIELD_IGNORE;
>>       if (t->size != sz)
>>           return BTF_FIELD_IGNORE;
>> +
>> +    info = __next_field_info(srch);
>> +    if (IS_ERR_OR_NULL(info))
>> +        return PTR_ERR(info);
>
> info cannot be NULL.
>
>> +
>>       info->type = field_type;
>>       info->off = off;
>>       return BTF_FIELD_FOUND;
>>   }
>>   -static int btf_find_kptr(const struct btf *btf, const struct 
>> btf_type *t,
>> -             u32 off, int sz, struct btf_field_info *info)
>> +static int btf_maybe_find_kptr(const struct btf *btf, const struct 
>> btf_type *t,
>> +                   u32 off, struct btf_field_info_search *srch)
>>   {
>> +    struct btf_field_info *info;
>>       enum btf_field_type type;
>>       u32 res_id;
>>   +    if (!(srch->field_mask & BPF_KPTR))
>> +        return BTF_FIELD_IGNORE;
>> +
>>       /* Permit modifiers on the pointer itself */
>>       if (btf_type_is_volatile(t))
>>           t = btf_type_by_id(btf, t->type);
>> @@ -3304,6 +3373,10 @@ static int btf_find_kptr(const struct btf 
>> *btf, const struct btf_type *t,
>>       if (!__btf_type_is_struct(t))
>>           return -EINVAL;
>>   +    info = __next_field_info(srch);
>> +    if (IS_ERR_OR_NULL(info))
>> +        return PTR_ERR(info);
>
> info cannot be NULL.
>
>> +
>>       info->type = type;
>>       info->off = off;
>>       info->kptr.type_id = res_id;
>> @@ -3340,9 +3413,10 @@ const char *btf_find_decl_tag_value(const 
>> struct btf *btf, const struct btf_type
>>   static int
>>   btf_find_graph_root(const struct btf *btf, const struct btf_type *pt,
>>               const struct btf_type *t, int comp_idx, u32 off,
>> -            int sz, struct btf_field_info *info,
>> +            int sz, struct btf_field_info_search *srch,
>>               enum btf_field_type head_type)
>>   {
>> +    struct btf_field_info *info;
>>       const char *node_field_name;
>>       const char *value_type;
>>       s32 id;
>> @@ -3367,6 +3441,11 @@ btf_find_graph_root(const struct btf *btf, 
>> const struct btf_type *pt,
>>       node_field_name++;
>>       if (str_is_empty(node_field_name))
>>           return -EINVAL;
>> +
>> +    info = __next_field_info(srch);
>> +    if (IS_ERR_OR_NULL(info))
>> +        return PTR_ERR(info);
>> +
>
> ditto.
>
>>       info->type = head_type;
>>       info->off = off;
>>       info->graph_root.value_btf_id = id;
>> @@ -3374,25 +3453,24 @@ btf_find_graph_root(const struct btf *btf, 
>> const struct btf_type *pt,
>>       return BTF_FIELD_FOUND;
>>   }
>>   -#define field_mask_test_name(field_type, field_type_str)        \
>> -    if (field_mask & field_type && !strcmp(name, field_type_str)) 
>> {    \
>> -        type = field_type;                    \
>> -        goto end;                        \
>> +#define field_mask_test_name(field_type, field_type_str)            \
>> +    if (srch->field_mask & field_type && !strcmp(name, 
>> field_type_str)) {    \
>> +        return field_type;                        \
>>       }
>>   -#define field_mask_test_name_check_seen(field_type, 
>> field_type_str)    \
>> -    if (field_mask & field_type && !strcmp(name, field_type_str)) 
>> {    \
>> -        if (*seen_mask & field_type)                \
>> -            return -E2BIG;                    \
>> -        *seen_mask |= field_type;                \
>> -        type = field_type;                    \
>> -        goto end;                        \
>> +#define field_mask_test_name_check_seen(field_type, 
>> field_type_str)        \
>> +    if (srch->field_mask & field_type && !strcmp(name, 
>> field_type_str)) {    \
>> +        if (srch->seen_mask & field_type) \
>> +            return -E2BIG;                        \
>> +        srch->seen_mask |= field_type;                    \
>> +        return field_type;                        \
>>       }
>>   -static int btf_get_field_type(const char *name, u32 field_mask, 
>> u32 *seen_mask,
>> -                  int *align, int *sz)
>
> [...]
>
>

  reply	other threads:[~2023-10-30 19:56 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-23 22:00 [PATCH v1 bpf-next 0/4] Descend into struct, array types when searching for fields Dave Marchevsky
2023-10-23 22:00 ` [PATCH v1 bpf-next 1/4] bpf: Fix btf_get_field_type to fail for multiple bpf_refcount fields Dave Marchevsky
2023-10-30 17:56   ` Yonghong Song
2023-11-01 21:56   ` Andrii Nakryiko
2023-10-23 22:00 ` [PATCH v1 bpf-next 2/4] bpf: Refactor btf_find_field with btf_field_info_search Dave Marchevsky
2023-10-28 14:52   ` Jiri Olsa
2023-10-30 19:31   ` Yonghong Song
2023-10-30 19:56     ` Yonghong Song [this message]
2023-11-01 21:56   ` Andrii Nakryiko
2023-10-23 22:00 ` [PATCH v1 bpf-next 3/4] btf: Descend into structs and arrays during special field search Dave Marchevsky
2023-10-26  1:24   ` kernel test robot
2023-10-30 12:56   ` Jiri Olsa
2023-10-30 20:56   ` Yonghong Song
2023-11-01 21:56   ` Andrii Nakryiko
2023-10-23 22:00 ` [PATCH v1 bpf-next 4/4] selftests/bpf: Add tests exercising aggregate type BTF " Dave Marchevsky
2023-10-23 23:32   ` kernel test robot
2023-10-30 21:10   ` Yonghong Song
2023-11-01 21:56   ` Andrii Nakryiko

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=c6770450-b5f3-4def-8541-d6c4371f8cb7@linux.dev \
    --to=yonghong.song@linux.dev \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davemarchevsky@fb.com \
    --cc=kernel-team@fb.com \
    --cc=martin.lau@kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.