Re: [RFC bpf-next] bpf: generate 'nomerge' for map helpers in bpf_helper_defs.h

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Jun 20, 2023 at 11:27 AM Jose E. Marchesi <jemarch@xxxxxxx> wrote:
>
>
> > On Thu, Jun 15, 2023 at 7:25 AM Eduard Zingerman <eddyz87@xxxxxxxxx> wrote:
> >>
> >> Update code generation for bpf_helper_defs.h by adding
> >> __attribute__((nomerge)) for a set of helper functions to prevent some
> >> verifier unfriendly compiler optimizations.
> >>
> >> This addresses a recent mailing list thread [1].
> >> There Zhongqiu Duan and Yonghong Song discussed a C program as below:
> >>
> >>      if (data_end - data > 1024) {
> >>          bpf_for_each_map_elem(&map1, cb, &cb_data, 0);
> >>      } else {
> >>          bpf_for_each_map_elem(&map2, cb, &cb_data, 0);
> >>      }
> >>
> >> Which was converted by clang to something like this:
> >>
> >>      if (data_end - data > 1024)
> >>        tmp = &map1;
> >>      else
> >>        tmp = &map2;
> >>      bpf_for_each_map_elem(tmp, cb, &cb_data, 0);
> >>
> >> Which in turn triggered verification error, because
> >> verifier.c:record_func_map() requires a single map address for each
> >> bpf_for_each_map_elem() call.
> >>
> >> In fact, this is a requirement for the following helpers:
> >> - bpf_tail_call
> >> - bpf_map_lookup_elem
> >> - bpf_map_update_elem
> >> - bpf_map_delete_elem
> >> - bpf_map_push_elem
> >> - bpf_map_pop_elem
> >> - bpf_map_peek_elem
> >> - bpf_for_each_map_elem
> >> - bpf_redirect_map
> >> - bpf_map_lookup_percpu_elem
> >>
> >> I had an off-list discussion with Yonghong where we agreed that clang
> >> attribute 'nomerge' (see [2]) could be used to prevent the
> >> optimization hitting in [1]. However, currently 'nomerge' applies only
> >> to functions and statements, hence I submitted change requests [3],
> >> [4] to allow specifying 'nomerge' for function pointers as well.
> >>
> >> The patch below updates bpf_helper_defs.h generation by adding a
> >> definition of __nomerge macro, and using this macro in definitions of
> >> relevant helpers.
> >>
> >> The generated code looks as follows:
> >>
> >>     /* This is auto-generated file. See bpf_doc.py for details. */
> >>
> >>     #if __has_attribute(nomerge)
> >>     #define __nomerge __attribute__((nomerge))
> >>     #else
> >>     #define __nomerge
> >>     #endif
> >>
> >>     /* Forward declarations of BPF structs */
> >>     ...
> >>     static long (*bpf_for_each_map_elem)(void *map, ...) __nomerge = (void *) 164;
> >>     ...
> >>
> >> (In non-RFC version the macro definition would have to be updated to
> >>  check for supported clang version).
> >>
> >> Does community agree with such approach?
> >
> > Makes sense to me. Let's just be very careful to do proper detection
> > of __nomerge "applicability" to ensure we don't cause compilation
> > errors for unsupported Clang (which I'm sure you are well aware of)
> > *and* make it compatible with GCC, so we don't fix it later.
>
> GCC doesn't support the "nomerge" attribute at this point.  We will look
> into adding it or find some other equivalent mechanism that can be
> abstracted in the __nomerge macro.
>
> >>
> >> [1] https://lore.kernel.org/bpf/03bdf90f-f374-1e67-69d6-76dd9c8318a4@xxxxxxxx/
> >> [2] https://clang.llvm.org/docs/AttributeReference.html#nomerge
> >> [3] https://reviews.llvm.org/D152986
> >> [4] https://reviews.llvm.org/D152987
> >> ---
> >>  scripts/bpf_doc.py | 37 ++++++++++++++++++++++++++++++-------
> >>  1 file changed, 30 insertions(+), 7 deletions(-)
> >>
> >> diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py
> >> index eaae2ce78381..dbd4893c793e 100755
> >> --- a/scripts/bpf_doc.py
> >> +++ b/scripts/bpf_doc.py
> >> @@ -777,14 +777,33 @@ class PrinterHelpers(Printer):
> >>          'bpf_get_socket_cookie',
> >>          'bpf_sk_assign',
> >>      ]
> >> +    # Helpers that need __nomerge attribute
> >> +    nomerge_helpers = set([
> >> +       "bpf_tail_call",
> >> +       "bpf_map_lookup_elem",
> >> +       "bpf_map_update_elem",
> >> +       "bpf_map_delete_elem",
> >> +       "bpf_map_push_elem",
> >> +       "bpf_map_pop_elem",
> >> +       "bpf_map_peek_elem",
> >> +       "bpf_for_each_map_elem",
> >> +       "bpf_redirect_map",
> >> +       "bpf_map_lookup_percpu_elem"
> >> +    ])
> >> +
> >> +    macros = '''\
> >> +#if __has_attribute(nomerge)
> >> +#define __nomerge __attribute__((nomerge))
> >> +#else
> >> +#define __nomerge
> >> +#endif'''

Let's add an extensive comment here,
so that people looking at bpf_helper_defs.h don't need
to search clang documentation on what this attr is doing.
I bet even compiler experts won't be able to explain 'why'
after reading the doc:
https://clang.llvm.org/docs/AttributeReference.html#nomerge
The example from the commit log should probably be in the comment too.
Other than that the approach makes sense to me.





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux