BPF Archive mirror
 help / color / mirror / Atom feed
From: Alexei Starovoitov <alexei.starovoitov@gmail.com>
To: "Jose E. Marchesi" <jose.marchesi@oracle.com>
Cc: bpf <bpf@vger.kernel.org>, David Faust <david.faust@oracle.com>,
	 Cupertino Miranda <cupertino.miranda@oracle.com>
Subject: Re: [PATCH bpf-next V2] bpf: make list_for_each_entry portable
Date: Sun, 12 May 2024 17:46:12 -0700	[thread overview]
Message-ID: <CAADnVQKUytdTK5ri4WUcB9VCmX4S+Hjkx7YkcDAPwP3UX05jBQ@mail.gmail.com> (raw)
In-Reply-To: <20240511212243.23477-1-jose.marchesi@oracle.com>

On Sat, May 11, 2024 at 2:23 PM Jose E. Marchesi
<jose.marchesi@oracle.com> wrote:
>
> [Changes from V1:
> - The __compat_break has been abandoned in favor of
>   a more readable can_loop macro that can be used anywhere, including
>   loop conditions.]
>
> The macro list_for_each_entry is defined in bpf_arena_list.h as
> follows:
>
>   #define list_for_each_entry(pos, head, member)                                \
>         for (void * ___tmp = (pos = list_entry_safe((head)->first,              \
>                                                     typeof(*(pos)), member),    \
>                               (void *)0);                                       \
>              pos && ({ ___tmp = (void *)pos->member.next; 1; });                \
>              cond_break,                                                        \
>              pos = list_entry_safe((void __arena *)___tmp, typeof(*(pos)), member))
>
> The macro cond_break, in turn, expands to a statement expression that
> contains a `break' statement.  Compound statement expressions, and the
> subsequent ability of placing statements in the header of a `for'
> loop, are GNU extensions.
>
> Unfortunately, clang implements this GNU extension differently than
> GCC:
>
> - In GCC the `break' statement is bound to the containing "breakable"
>   context in which the defining `for' appears.  If there is no such
>   context, GCC emits a warning: break statement without enclosing `for'
>   o `switch' statement.
>
> - In clang the `break' statement is bound to the defining `for'.  If
>   the defining `for' is itself inside some breakable construct, then
>   clang emits a -Wgcc-compat warning.
>
> This patch adds a new macro can_loop to bpf_experimental, that
> implements the same logic than cond_break but evaluates to a boolean
> expression.  The patch also changes all the current instances of usage
> of cond_break withing the header of loop accordingly.
>
> Tested in bpf-next master.
> No regressions.
>
> Signed-off-by: Jose E. Marchesi <jose.marchesi@oracle.com>
> Cc: david.faust@oracle.com
> Cc: cupertino.miranda@oracle.com
> Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
> ---
>  tools/testing/selftests/bpf/bpf_arena_list.h  |  4 +--
>  .../testing/selftests/bpf/bpf_experimental.h  | 28 +++++++++++++++++++
>  .../testing/selftests/bpf/progs/arena_list.c  |  2 +-
>  .../bpf/progs/verifier_iterating_callbacks.c  |  9 +++---
>  4 files changed, 35 insertions(+), 8 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/bpf_arena_list.h b/tools/testing/selftests/bpf/bpf_arena_list.h
> index b99b9f408eff..85dbc3ea4da5 100644
> --- a/tools/testing/selftests/bpf/bpf_arena_list.h
> +++ b/tools/testing/selftests/bpf/bpf_arena_list.h
> @@ -29,6 +29,7 @@ static inline void *bpf_iter_num_new(struct bpf_iter_num *it, int i, int j) { re
>  static inline void bpf_iter_num_destroy(struct bpf_iter_num *it) {}
>  static inline bool bpf_iter_num_next(struct bpf_iter_num *it) { return true; }
>  #define cond_break ({})
> +#define can_loop true
>  #endif
>
>  /* Safely walk link list elements. Deletion of elements is allowed. */
> @@ -36,8 +37,7 @@ static inline bool bpf_iter_num_next(struct bpf_iter_num *it) { return true; }
>         for (void * ___tmp = (pos = list_entry_safe((head)->first,              \
>                                                     typeof(*(pos)), member),    \
>                               (void *)0);                                       \
> -            pos && ({ ___tmp = (void *)pos->member.next; 1; });                \
> -            cond_break,                                                        \
> +            pos && ({ ___tmp = (void *)pos->member.next; 1; }) && can_loop;    \
>              pos = list_entry_safe((void __arena *)___tmp, typeof(*(pos)), member))
>
>  static inline void list_add_head(arena_list_node_t *n, arena_list_head_t *h)
> diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h
> index 8b9cc87be4c4..13e79af0a17c 100644
> --- a/tools/testing/selftests/bpf/bpf_experimental.h
> +++ b/tools/testing/selftests/bpf/bpf_experimental.h
> @@ -326,7 +326,21 @@ l_true:                                                                                            \
>         })
>  #endif
>
> +/* Note that cond_break can only be portably used in the body of a
> +   breakable construct, whereas can_loop can be used anywhere.  */

I fixed this comment to be proper kernel style.

> +
>  #ifdef __BPF_FEATURE_MAY_GOTO
> +#define can_loop                                       \
> +       ({ __label__ l_break, l_continue;               \

fixed white space damage.

> +       bool ret = true;                                \
> +        asm volatile goto("may_goto %l[l_break]"       \

fixed broken formatting.

> +                     :::: l_break);                    \
> +       goto l_continue;                                \
> +       l_break: ret = false;                           \
> +       l_continue:;                                    \
> +       ret;                                            \
> +       })
> +
>  #define cond_break                                     \
>         ({ __label__ l_break, l_continue;               \
>          asm volatile goto("may_goto %l[l_break]"       \
> @@ -336,6 +350,20 @@ l_true:                                                                                            \
>         l_continue:;                                    \
>         })
>  #else
> +#define can_loop                                       \
> +       ({ __label__ l_break, l_continue;               \
> +        bool ret = true;                               \
> +        asm volatile goto("1:.byte 0xe5;                       \
> +                     .byte 0;                          \
> +                     .long ((%l[l_break] - 1b - 8) / 8) & 0xffff;      \
> +                     .short 0"                         \
> +                     :::: l_break);                    \
> +       goto l_continue;                                \
> +       l_break: ret = false;                           \
> +       l_continue:;                                    \
> +       ret;                                            \
> +       })
> +

This copy paste of the macro is a bit annoying,
but I don't see a clean way to make can_loop and cond_break
to use a common macro without being unreadable.
So applied with the above fixes.

Thanks!

  reply	other threads:[~2024-05-13  0:46 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-11 21:22 [PATCH bpf-next V2] bpf: make list_for_each_entry portable Jose E. Marchesi
2024-05-13  0:46 ` Alexei Starovoitov [this message]
2024-05-13  0:50 ` patchwork-bot+netdevbpf

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=CAADnVQKUytdTK5ri4WUcB9VCmX4S+Hjkx7YkcDAPwP3UX05jBQ@mail.gmail.com \
    --to=alexei.starovoitov@gmail.com \
    --cc=bpf@vger.kernel.org \
    --cc=cupertino.miranda@oracle.com \
    --cc=david.faust@oracle.com \
    --cc=jose.marchesi@oracle.com \
    /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;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).