diff mbox series

[bpf-next] libbpf: synchronize access to print function pointer

Message ID 20230325010845.46000-1-inwardvessel@gmail.com (mailing list archive)
State Accepted
Commit f1cb927cdb6280e0ce283174cc1bf395dffc43d4
Delegated to: BPF
Headers show
Series [bpf-next] libbpf: synchronize access to print function pointer | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for bpf-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 20 this patch: 20
netdev/cc_maintainers warning 10 maintainers not CCed: song@kernel.org sdf@google.com haoluo@google.com yhs@fb.com daniel@iogearbox.net john.fastabend@gmail.com kpsingh@kernel.org jolsa@kernel.org martin.lau@linux.dev ast@kernel.org
netdev/build_clang success Errors and warnings before: 18 this patch: 18
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 20 this patch: 20
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 32 lines checked
netdev/kdoc success Errors and warnings before: 114 this patch: 114
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-11 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-12 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-13 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32 on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-21 fail Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_no_alu32_parallel on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_progs_parallel on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-30 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-31 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-32 success Logs for test_verifier on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-34 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-35 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-33 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-15 success Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on s390x with gcc
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-7 success Logs for set-matrix

Commit Message

JP Kobryn March 25, 2023, 1:08 a.m. UTC
This patch prevents races on the print function pointer, allowing the
libbpf_set_print() function to become thread safe.

Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
---
 tools/lib/bpf/libbpf.c | 9 ++++++---
 tools/lib/bpf/libbpf.h | 3 +++
 2 files changed, 9 insertions(+), 3 deletions(-)

Comments

Stanislav Fomichev March 25, 2023, 3:09 a.m. UTC | #1
On 03/24, JP Kobryn wrote:
> This patch prevents races on the print function pointer, allowing the
> libbpf_set_print() function to become thread safe.

Why does it have to be thread-safe? The rest of the APIs aren't, so
why can't use solve it on your side by wrapping those calls with a
mutex?

(is there some context I'm missing?)

> Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
> ---
>   tools/lib/bpf/libbpf.c | 9 ++++++---
>   tools/lib/bpf/libbpf.h | 3 +++
>   2 files changed, 9 insertions(+), 3 deletions(-)

> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index f6a071db5c6e..15737d7b5a28 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -216,9 +216,10 @@ static libbpf_print_fn_t __libbpf_pr = __base_pr;

>   libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn)
>   {
> -	libbpf_print_fn_t old_print_fn = __libbpf_pr;
> +	libbpf_print_fn_t old_print_fn;
> +
> +	old_print_fn = __atomic_exchange_n(&__libbpf_pr, fn, __ATOMIC_RELAXED);

> -	__libbpf_pr = fn;
>   	return old_print_fn;
>   }

> @@ -227,8 +228,10 @@ void libbpf_print(enum libbpf_print_level level,  
> const char *format, ...)
>   {
>   	va_list args;
>   	int old_errno;
> +	libbpf_print_fn_t print_fn;

> -	if (!__libbpf_pr)
> +	print_fn = __atomic_load_n(&__libbpf_pr, __ATOMIC_RELAXED);
> +	if (!print_fn)
>   		return;

>   	old_errno = errno;
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index 1615e55e2e79..4478809ff9ca 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -99,6 +99,9 @@ typedef int (*libbpf_print_fn_t)(enum  
> libbpf_print_level level,
>   /**
>    * @brief **libbpf_set_print()** sets user-provided log callback  
> function to
>    * be used for libbpf warnings and informational messages.
> + *
> + * This function is thread safe.
> + *
>    * @param fn The log print function. If NULL, libbpf won't print  
> anything.
>    * @return Pointer to old print function.
>    */
> --
> 2.39.2
Andrii Nakryiko March 27, 2023, 6:32 p.m. UTC | #2
On Fri, Mar 24, 2023 at 8:09 PM Stanislav Fomichev <sdf@google.com> wrote:
>
> On 03/24, JP Kobryn wrote:
> > This patch prevents races on the print function pointer, allowing the
> > libbpf_set_print() function to become thread safe.
>
> Why does it have to be thread-safe? The rest of the APIs aren't, so

It doesn't have to, but if it can be made thread-safe trivially, it
probably should be. Rust users are especially sensitive to this (see
discussion in [0] for example).

Generally speaking, yep, libbpf APIs are not thread-safe by default
(we don't do explicit locking anywhere inside libbpf), but there are a
bunch of APIs that are inherently thread-safe as they are stateless
(like feature probing, string conversion APIs, I suspect upon
inspection we'll see that all bpf_program__attach_*() APIs are also
probably thread-safe already). So we should start marking them as such
to avoid confusion and uncertainty for users. I'd also like to
document somewhere that two independent bpf_objects can be used safely
on two separate threads, because whatever state they are sharing (like
feature detection cache) is designed in such a way to be thread-safe
and shareable with no locking.

  [0] https://github.com/libbpf/libbpf-rs/pull/374#issuecomment-1462565778

> why can't use solve it on your side by wrapping those calls with a
> mutex?

It would be very unfortunate to wrap libbpf_set_print and *all other
libbpf API* in mutex.

>
> (is there some context I'm missing?)
>
> > Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
> > ---
> >   tools/lib/bpf/libbpf.c | 9 ++++++---
> >   tools/lib/bpf/libbpf.h | 3 +++
> >   2 files changed, 9 insertions(+), 3 deletions(-)
>
> > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > index f6a071db5c6e..15737d7b5a28 100644
> > --- a/tools/lib/bpf/libbpf.c
> > +++ b/tools/lib/bpf/libbpf.c
> > @@ -216,9 +216,10 @@ static libbpf_print_fn_t __libbpf_pr = __base_pr;
>
> >   libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn)
> >   {
> > -     libbpf_print_fn_t old_print_fn = __libbpf_pr;
> > +     libbpf_print_fn_t old_print_fn;
> > +
> > +     old_print_fn = __atomic_exchange_n(&__libbpf_pr, fn, __ATOMIC_RELAXED);
>
> > -     __libbpf_pr = fn;
> >       return old_print_fn;
> >   }
>
> > @@ -227,8 +228,10 @@ void libbpf_print(enum libbpf_print_level level,
> > const char *format, ...)
> >   {
> >       va_list args;
> >       int old_errno;
> > +     libbpf_print_fn_t print_fn;
>
> > -     if (!__libbpf_pr)
> > +     print_fn = __atomic_load_n(&__libbpf_pr, __ATOMIC_RELAXED);
> > +     if (!print_fn)
> >               return;
>
> >       old_errno = errno;
> > diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> > index 1615e55e2e79..4478809ff9ca 100644
> > --- a/tools/lib/bpf/libbpf.h
> > +++ b/tools/lib/bpf/libbpf.h
> > @@ -99,6 +99,9 @@ typedef int (*libbpf_print_fn_t)(enum
> > libbpf_print_level level,
> >   /**
> >    * @brief **libbpf_set_print()** sets user-provided log callback
> > function to
> >    * be used for libbpf warnings and informational messages.
> > + *
> > + * This function is thread safe.
> > + *
> >    * @param fn The log print function. If NULL, libbpf won't print
> > anything.
> >    * @return Pointer to old print function.
> >    */
> > --
> > 2.39.2
>
Andrii Nakryiko March 27, 2023, 6:36 p.m. UTC | #3
On Fri, Mar 24, 2023 at 6:09 PM JP Kobryn <inwardvessel@gmail.com> wrote:
>
> This patch prevents races on the print function pointer, allowing the
> libbpf_set_print() function to become thread safe.
>
> Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
> ---

I reworked the patch subject to "libbpf: Ensure print callback usage
is thread-safe", it felt more on point. Also changed to "thread-safe",
which seems to be a proper spelling for this term.

Applied to bpf-next, thanks!

>  tools/lib/bpf/libbpf.c | 9 ++++++---
>  tools/lib/bpf/libbpf.h | 3 +++
>  2 files changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index f6a071db5c6e..15737d7b5a28 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -216,9 +216,10 @@ static libbpf_print_fn_t __libbpf_pr = __base_pr;
>
>  libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn)
>  {
> -       libbpf_print_fn_t old_print_fn = __libbpf_pr;
> +       libbpf_print_fn_t old_print_fn;
> +
> +       old_print_fn = __atomic_exchange_n(&__libbpf_pr, fn, __ATOMIC_RELAXED);
>
> -       __libbpf_pr = fn;
>         return old_print_fn;
>  }
>
> @@ -227,8 +228,10 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
>  {
>         va_list args;
>         int old_errno;
> +       libbpf_print_fn_t print_fn;
>
> -       if (!__libbpf_pr)
> +       print_fn = __atomic_load_n(&__libbpf_pr, __ATOMIC_RELAXED);
> +       if (!print_fn)
>                 return;
>
>         old_errno = errno;
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index 1615e55e2e79..4478809ff9ca 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -99,6 +99,9 @@ typedef int (*libbpf_print_fn_t)(enum libbpf_print_level level,
>  /**
>   * @brief **libbpf_set_print()** sets user-provided log callback function to
>   * be used for libbpf warnings and informational messages.
> + *
> + * This function is thread safe.
> + *

I moved this part to after @return spec, where details about functions
are normally put.

>   * @param fn The log print function. If NULL, libbpf won't print anything.
>   * @return Pointer to old print function.
>   */
> --
> 2.39.2
>
patchwork-bot+netdevbpf@kernel.org March 27, 2023, 6:40 p.m. UTC | #4
Hello:

This patch was applied to bpf/bpf-next.git (master)
by Andrii Nakryiko <andrii@kernel.org>:

On Fri, 24 Mar 2023 18:08:45 -0700 you wrote:
> This patch prevents races on the print function pointer, allowing the
> libbpf_set_print() function to become thread safe.
> 
> Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
> ---
>  tools/lib/bpf/libbpf.c | 9 ++++++---
>  tools/lib/bpf/libbpf.h | 3 +++
>  2 files changed, 9 insertions(+), 3 deletions(-)

Here is the summary with links:
  - [bpf-next] libbpf: synchronize access to print function pointer
    https://git.kernel.org/bpf/bpf-next/c/f1cb927cdb62

You are awesome, thank you!
diff mbox series

Patch

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index f6a071db5c6e..15737d7b5a28 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -216,9 +216,10 @@  static libbpf_print_fn_t __libbpf_pr = __base_pr;
 
 libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn)
 {
-	libbpf_print_fn_t old_print_fn = __libbpf_pr;
+	libbpf_print_fn_t old_print_fn;
+
+	old_print_fn = __atomic_exchange_n(&__libbpf_pr, fn, __ATOMIC_RELAXED);
 
-	__libbpf_pr = fn;
 	return old_print_fn;
 }
 
@@ -227,8 +228,10 @@  void libbpf_print(enum libbpf_print_level level, const char *format, ...)
 {
 	va_list args;
 	int old_errno;
+	libbpf_print_fn_t print_fn;
 
-	if (!__libbpf_pr)
+	print_fn = __atomic_load_n(&__libbpf_pr, __ATOMIC_RELAXED);
+	if (!print_fn)
 		return;
 
 	old_errno = errno;
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 1615e55e2e79..4478809ff9ca 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -99,6 +99,9 @@  typedef int (*libbpf_print_fn_t)(enum libbpf_print_level level,
 /**
  * @brief **libbpf_set_print()** sets user-provided log callback function to
  * be used for libbpf warnings and informational messages.
+ *
+ * This function is thread safe.
+ *
  * @param fn The log print function. If NULL, libbpf won't print anything.
  * @return Pointer to old print function.
  */