diff mbox series

[bpf-next] libbpf: Add bpf_object__unpin()

Message ID aeb83832ae61bbf463e1b2e39c1e30c3b227f5a5.1692769396.git.dxu@dxuuu.xyz (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series [bpf-next] libbpf: Add bpf_object__unpin() | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-VM_Test-0 success Logs for ShellCheck
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-5 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-1 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-12 success Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for veristat
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-8 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-15 success Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-11 success Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for test_maps on s390x with gcc
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: 9 this patch: 9
netdev/cc_maintainers success CCed 12 of 12 maintainers
netdev/build_clang success Errors and warnings before: 9 this patch: 9
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: 9 this patch: 9
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 33 lines checked
netdev/kdoc success Errors and warnings before: 118 this patch: 118
netdev/source_inline success Was 0 now: 0

Commit Message

Daniel Xu Aug. 23, 2023, 5:44 a.m. UTC
For bpf_object__pin_programs() there is bpf_object__unpin_programs().
Likewise bpf_object__unpin_maps() for bpf_object__pin_maps().

But no bpf_object__unpin() for bpf_object__pin(). Adding the former adds
symmetry to the API.

It's also convenient for cleanup in application code. It's an API I
would've used if it was available for a repro I was writing earlier.

Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
---
 tools/lib/bpf/libbpf.c   | 15 +++++++++++++++
 tools/lib/bpf/libbpf.h   |  1 +
 tools/lib/bpf/libbpf.map |  1 +
 3 files changed, 17 insertions(+)

Comments

Song Liu Aug. 23, 2023, 11:30 a.m. UTC | #1
On Tue, Aug 22, 2023 at 10:44 PM Daniel Xu <dxu@dxuuu.xyz> wrote:
>
> For bpf_object__pin_programs() there is bpf_object__unpin_programs().
> Likewise bpf_object__unpin_maps() for bpf_object__pin_maps().
>
> But no bpf_object__unpin() for bpf_object__pin(). Adding the former adds
> symmetry to the API.
>
> It's also convenient for cleanup in application code. It's an API I
> would've used if it was available for a repro I was writing earlier.
>
> Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>

Reviewed-by: Song Liu <song@kernel.org>
Jiri Olsa Aug. 23, 2023, 11:48 a.m. UTC | #2
On Tue, Aug 22, 2023 at 11:44:25PM -0600, Daniel Xu wrote:
> For bpf_object__pin_programs() there is bpf_object__unpin_programs().
> Likewise bpf_object__unpin_maps() for bpf_object__pin_maps().
> 
> But no bpf_object__unpin() for bpf_object__pin(). Adding the former adds
> symmetry to the API.
> 
> It's also convenient for cleanup in application code. It's an API I
> would've used if it was available for a repro I was writing earlier.
> 
> Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
> ---
>  tools/lib/bpf/libbpf.c   | 15 +++++++++++++++
>  tools/lib/bpf/libbpf.h   |  1 +
>  tools/lib/bpf/libbpf.map |  1 +
>  3 files changed, 17 insertions(+)
> 
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 4c3967d94b6d..96ff1aa4bf6a 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -8376,6 +8376,21 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
>  	return 0;
>  }
>  
> +int bpf_object__unpin(struct bpf_object *obj, const char *path)
> +{
> +	int err;
> +
> +	err = bpf_object__unpin_programs(obj, path);
> +	if (err)
> +		return libbpf_err(err);
> +
> +	err = bpf_object__unpin_maps(obj, path);
> +	if (err)
> +		return libbpf_err(err);
> +
> +	return 0;
> +}
> +
>  static void bpf_map__destroy(struct bpf_map *map)
>  {
>  	if (map->inner_map) {
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index 2e3eb3614c40..0e52621cba43 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -266,6 +266,7 @@ LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj,
>  LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj,
>  					  const char *path);
>  LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
> +LIBBPF_API int bpf_object__unpin(struct bpf_object *object, const char *path);
>  
>  LIBBPF_API const char *bpf_object__name(const struct bpf_object *obj);
>  LIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj);
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index 841a2f9c6fef..abf8fea3988e 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -399,4 +399,5 @@ LIBBPF_1.3.0 {
>  		bpf_program__attach_netfilter;
>  		bpf_program__attach_tcx;
>  		bpf_program__attach_uprobe_multi;
> +		bpf_object__unpin;

nit, I think we add in here in alphabetical order

jirka

>  } LIBBPF_1.2.0;
> -- 
> 2.41.0
>
Andrii Nakryiko Aug. 23, 2023, 5:19 p.m. UTC | #3
On Tue, Aug 22, 2023 at 10:44 PM Daniel Xu <dxu@dxuuu.xyz> wrote:
>
> For bpf_object__pin_programs() there is bpf_object__unpin_programs().
> Likewise bpf_object__unpin_maps() for bpf_object__pin_maps().
>
> But no bpf_object__unpin() for bpf_object__pin(). Adding the former adds
> symmetry to the API.
>
> It's also convenient for cleanup in application code. It's an API I
> would've used if it was available for a repro I was writing earlier.
>
> Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
> ---
>  tools/lib/bpf/libbpf.c   | 15 +++++++++++++++
>  tools/lib/bpf/libbpf.h   |  1 +
>  tools/lib/bpf/libbpf.map |  1 +
>  3 files changed, 17 insertions(+)
>
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 4c3967d94b6d..96ff1aa4bf6a 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -8376,6 +8376,21 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
>         return 0;
>  }
>
> +int bpf_object__unpin(struct bpf_object *obj, const char *path)
> +{
> +       int err;
> +
> +       err = bpf_object__unpin_programs(obj, path);
> +       if (err)
> +               return libbpf_err(err);
> +
> +       err = bpf_object__unpin_maps(obj, path);
> +       if (err)
> +               return libbpf_err(err);
> +
> +       return 0;
> +}
> +

pin APIs predate me, and I barely ever use them, but I wonder if
people feel fine with the fact that if any single unpin fails, all the
other programs/maps will not be unpinned? I also wonder if the best
effort unpinning of everything (while propagating first/last error) is
more practical? Looking at bpf_object__pin_programs, we try unpin
everything, even if some unpins fail.

Any thoughts or preferences?

>  static void bpf_map__destroy(struct bpf_map *map)
>  {
>         if (map->inner_map) {
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index 2e3eb3614c40..0e52621cba43 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -266,6 +266,7 @@ LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj,
>  LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj,
>                                           const char *path);
>  LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
> +LIBBPF_API int bpf_object__unpin(struct bpf_object *object, const char *path);
>
>  LIBBPF_API const char *bpf_object__name(const struct bpf_object *obj);
>  LIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj);
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index 841a2f9c6fef..abf8fea3988e 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -399,4 +399,5 @@ LIBBPF_1.3.0 {
>                 bpf_program__attach_netfilter;
>                 bpf_program__attach_tcx;
>                 bpf_program__attach_uprobe_multi;
> +               bpf_object__unpin;
>  } LIBBPF_1.2.0;
> --
> 2.41.0
>
Song Liu Aug. 23, 2023, 6:08 p.m. UTC | #4
On Wed, Aug 23, 2023 at 10:19 AM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> On Tue, Aug 22, 2023 at 10:44 PM Daniel Xu <dxu@dxuuu.xyz> wrote:
> >
> > For bpf_object__pin_programs() there is bpf_object__unpin_programs().
> > Likewise bpf_object__unpin_maps() for bpf_object__pin_maps().
> >
> > But no bpf_object__unpin() for bpf_object__pin(). Adding the former adds
> > symmetry to the API.
> >
> > It's also convenient for cleanup in application code. It's an API I
> > would've used if it was available for a repro I was writing earlier.
> >
> > Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
> > ---
> >  tools/lib/bpf/libbpf.c   | 15 +++++++++++++++
> >  tools/lib/bpf/libbpf.h   |  1 +
> >  tools/lib/bpf/libbpf.map |  1 +
> >  3 files changed, 17 insertions(+)
> >
> > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > index 4c3967d94b6d..96ff1aa4bf6a 100644
> > --- a/tools/lib/bpf/libbpf.c
> > +++ b/tools/lib/bpf/libbpf.c
> > @@ -8376,6 +8376,21 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
> >         return 0;
> >  }
> >
> > +int bpf_object__unpin(struct bpf_object *obj, const char *path)
> > +{
> > +       int err;
> > +
> > +       err = bpf_object__unpin_programs(obj, path);
> > +       if (err)
> > +               return libbpf_err(err);
> > +
> > +       err = bpf_object__unpin_maps(obj, path);
> > +       if (err)
> > +               return libbpf_err(err);
> > +
> > +       return 0;
> > +}
> > +
>
> pin APIs predate me, and I barely ever use them, but I wonder if
> people feel fine with the fact that if any single unpin fails, all the
> other programs/maps will not be unpinned? I also wonder if the best
> effort unpinning of everything (while propagating first/last error) is
> more practical? Looking at bpf_object__pin_programs, we try unpin
> everything, even if some unpins fail.

I think the behavior of bpf_object__pin_programs() makes sense for
the error handling path, e.g. undo everything as much as possible.
bpf_object__unpin(), OTOH, is similar to bpf_object__unpin_programs()
and bpf_object__unpin_maps(), if something went wrong, we just give up.

>
> Any thoughts or preferences?

I think current version is ok, as it matches bpf_object__unpin_programs
and bpf_object__unpin_maps behavior. But I guess we can change all
3?

Thanks,
Song
Daniel Xu Aug. 23, 2023, 6:43 p.m. UTC | #5
On Wed, Aug 23, 2023 at 10:19:10AM -0700, Andrii Nakryiko wrote:
> On Tue, Aug 22, 2023 at 10:44 PM Daniel Xu <dxu@dxuuu.xyz> wrote:
> >
> > For bpf_object__pin_programs() there is bpf_object__unpin_programs().
> > Likewise bpf_object__unpin_maps() for bpf_object__pin_maps().
> >
> > But no bpf_object__unpin() for bpf_object__pin(). Adding the former adds
> > symmetry to the API.
> >
> > It's also convenient for cleanup in application code. It's an API I
> > would've used if it was available for a repro I was writing earlier.
> >
> > Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
> > ---
> >  tools/lib/bpf/libbpf.c   | 15 +++++++++++++++
> >  tools/lib/bpf/libbpf.h   |  1 +
> >  tools/lib/bpf/libbpf.map |  1 +
> >  3 files changed, 17 insertions(+)
> >
> > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > index 4c3967d94b6d..96ff1aa4bf6a 100644
> > --- a/tools/lib/bpf/libbpf.c
> > +++ b/tools/lib/bpf/libbpf.c
> > @@ -8376,6 +8376,21 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
> >         return 0;
> >  }
> >
> > +int bpf_object__unpin(struct bpf_object *obj, const char *path)
> > +{
> > +       int err;
> > +
> > +       err = bpf_object__unpin_programs(obj, path);
> > +       if (err)
> > +               return libbpf_err(err);
> > +
> > +       err = bpf_object__unpin_maps(obj, path);
> > +       if (err)
> > +               return libbpf_err(err);
> > +
> > +       return 0;
> > +}
> > +
> 
> pin APIs predate me, and I barely ever use them, but I wonder if
> people feel fine with the fact that if any single unpin fails, all the
> other programs/maps will not be unpinned? I also wonder if the best
> effort unpinning of everything (while propagating first/last error) is
> more practical? Looking at bpf_object__pin_programs, we try unpin
> everything, even if some unpins fail.
> 
> Any thoughts or preferences?

Yeah, I noticed bpf_object__pin_programs() tries to simulate some
transactionality. However, bpf_object__unpin_programs() and
bpf_object__unpin_maps() both do not try rollbacks and have already been
exposed as public API. So I thought it would be best to stay consistent.

I also figured it's unlikely only a single unpin() fails. For pin(), you
could have name collisions. But not for unpin(). I suppose the main
error case is if some 3rd party (or yourself) comes in and messes with
your objects in bpffs.

In general, though, there are other places where transactionality would
be a nice property. For example, if I have a TC prog that I want to
attach to, say, _all_ ethernet interfaces, I have to be careful about
rollbacks in the event of failure on a single iface.

It would be really nice if the kernel  had a general way to provide
atomicity w.r.t. multiple operations. But I suppose that's a hard
problem.

[...]

Thanks,
Daniel
Andrii Nakryiko Aug. 23, 2023, 9:16 p.m. UTC | #6
On Wed, Aug 23, 2023 at 11:43 AM Daniel Xu <dxu@dxuuu.xyz> wrote:
>
> On Wed, Aug 23, 2023 at 10:19:10AM -0700, Andrii Nakryiko wrote:
> > On Tue, Aug 22, 2023 at 10:44 PM Daniel Xu <dxu@dxuuu.xyz> wrote:
> > >
> > > For bpf_object__pin_programs() there is bpf_object__unpin_programs().
> > > Likewise bpf_object__unpin_maps() for bpf_object__pin_maps().
> > >
> > > But no bpf_object__unpin() for bpf_object__pin(). Adding the former adds
> > > symmetry to the API.
> > >
> > > It's also convenient for cleanup in application code. It's an API I
> > > would've used if it was available for a repro I was writing earlier.
> > >
> > > Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
> > > ---
> > >  tools/lib/bpf/libbpf.c   | 15 +++++++++++++++
> > >  tools/lib/bpf/libbpf.h   |  1 +
> > >  tools/lib/bpf/libbpf.map |  1 +
> > >  3 files changed, 17 insertions(+)
> > >
> > > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > > index 4c3967d94b6d..96ff1aa4bf6a 100644
> > > --- a/tools/lib/bpf/libbpf.c
> > > +++ b/tools/lib/bpf/libbpf.c
> > > @@ -8376,6 +8376,21 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
> > >         return 0;
> > >  }
> > >
> > > +int bpf_object__unpin(struct bpf_object *obj, const char *path)
> > > +{
> > > +       int err;
> > > +
> > > +       err = bpf_object__unpin_programs(obj, path);
> > > +       if (err)
> > > +               return libbpf_err(err);
> > > +
> > > +       err = bpf_object__unpin_maps(obj, path);
> > > +       if (err)
> > > +               return libbpf_err(err);
> > > +
> > > +       return 0;
> > > +}
> > > +
> >
> > pin APIs predate me, and I barely ever use them, but I wonder if
> > people feel fine with the fact that if any single unpin fails, all the
> > other programs/maps will not be unpinned? I also wonder if the best
> > effort unpinning of everything (while propagating first/last error) is
> > more practical? Looking at bpf_object__pin_programs, we try unpin
> > everything, even if some unpins fail.
> >
> > Any thoughts or preferences?
>
> Yeah, I noticed bpf_object__pin_programs() tries to simulate some
> transactionality. However, bpf_object__unpin_programs() and
> bpf_object__unpin_maps() both do not try rollbacks and have already been
> exposed as public API. So I thought it would be best to stay consistent.

yep, makes sense. I guess if I were to rely heavily on
pinning/unpinning, I always have an option to pin/unpin individually.
Ok, please address the other feedback and resubmit.

>
> I also figured it's unlikely only a single unpin() fails. For pin(), you
> could have name collisions. But not for unpin(). I suppose the main
> error case is if some 3rd party (or yourself) comes in and messes with
> your objects in bpffs.
>
> In general, though, there are other places where transactionality would
> be a nice property. For example, if I have a TC prog that I want to
> attach to, say, _all_ ethernet interfaces, I have to be careful about
> rollbacks in the event of failure on a single iface.
>
> It would be really nice if the kernel  had a general way to provide
> atomicity w.r.t. multiple operations. But I suppose that's a hard
> problem.
>
> [...]
>
> Thanks,
> Daniel
diff mbox series

Patch

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 4c3967d94b6d..96ff1aa4bf6a 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -8376,6 +8376,21 @@  int bpf_object__pin(struct bpf_object *obj, const char *path)
 	return 0;
 }
 
+int bpf_object__unpin(struct bpf_object *obj, const char *path)
+{
+	int err;
+
+	err = bpf_object__unpin_programs(obj, path);
+	if (err)
+		return libbpf_err(err);
+
+	err = bpf_object__unpin_maps(obj, path);
+	if (err)
+		return libbpf_err(err);
+
+	return 0;
+}
+
 static void bpf_map__destroy(struct bpf_map *map)
 {
 	if (map->inner_map) {
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 2e3eb3614c40..0e52621cba43 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -266,6 +266,7 @@  LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj,
 LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj,
 					  const char *path);
 LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
+LIBBPF_API int bpf_object__unpin(struct bpf_object *object, const char *path);
 
 LIBBPF_API const char *bpf_object__name(const struct bpf_object *obj);
 LIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj);
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 841a2f9c6fef..abf8fea3988e 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -399,4 +399,5 @@  LIBBPF_1.3.0 {
 		bpf_program__attach_netfilter;
 		bpf_program__attach_tcx;
 		bpf_program__attach_uprobe_multi;
+		bpf_object__unpin;
 } LIBBPF_1.2.0;