All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next v2 0/2] Update a struct_ops link through a pinned path
@ 2024-04-18 16:35 Kui-Feng Lee
  2024-04-18 16:35 ` [PATCH bpf-next v2 1/2] bpf: enable the "open" operator on a pinned path of a struct_osp link Kui-Feng Lee
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Kui-Feng Lee @ 2024-04-18 16:35 UTC (permalink / raw)
  To: bpf, ast, martin.lau, song, kernel-team, andrii
  Cc: sinquersw, kuifeng, Kui-Feng Lee

Applications already have the ability to update a struct_ops link with
another struct_ops map. However, they were unable to open pinned paths
of the links. This implies that updating a link through its pinned
paths was not feasible. By allowing the "open" operator on pinned
paths, applications can pin a struct_ops link and update the link
through the pinned path later.

---
Changes from v1:

 - Fix a link time error for the case that CONFIG_BPF_JIT is not
   enabled. (Reported by kernel test robot)

v1: https://lore.kernel.org/all/20240417002513.1534535-1-thinker.li@gmail.com/

Kui-Feng Lee (2):
  bpf: enable the "open" operator on a pinned path of a struct_osp link.
  selftests/bpf: open a pinned path of a struct_ops link.

 include/linux/bpf.h                           |  6 ++
 kernel/bpf/bpf_struct_ops.c                   | 10 ++++
 kernel/bpf/inode.c                            | 11 +++-
 kernel/bpf/syscall.c                          | 16 +++++-
 .../selftests/bpf/bpf_testmod/bpf_testmod.c   |  6 ++
 .../bpf/prog_tests/test_struct_ops_module.c   | 56 +++++++++++++++++++
 6 files changed, 101 insertions(+), 4 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH bpf-next v2 1/2] bpf: enable the "open" operator on a pinned path of a struct_osp link.
  2024-04-18 16:35 [PATCH bpf-next v2 0/2] Update a struct_ops link through a pinned path Kui-Feng Lee
@ 2024-04-18 16:35 ` Kui-Feng Lee
  2024-04-25  0:09   ` Andrii Nakryiko
  2024-04-18 16:35 ` [PATCH bpf-next v2 2/2] selftests/bpf: open a pinned path of a struct_ops link Kui-Feng Lee
  2024-04-18 21:37 ` [PATCH bpf-next v2 0/2] Update a struct_ops link through a pinned path Eduard Zingerman
  2 siblings, 1 reply; 5+ messages in thread
From: Kui-Feng Lee @ 2024-04-18 16:35 UTC (permalink / raw)
  To: bpf, ast, martin.lau, song, kernel-team, andrii
  Cc: sinquersw, kuifeng, Kui-Feng Lee

Add the "open" operator for the inodes of BPF links to allow applications
to obtain a file descriptor of a struct_ops link from a pinned path.

Applications have the ability to update a struct_ops link with another
struct_ops map. However, they were unable to open pinned paths of the links
with this patch. This implies that updating a link through its pinned paths
was not feasible.

This patch adds the "open" operator to bpf_link_ops and uses bpf_link_ops
as the i_fop for inodes of struct_ops links. "open" will be called to open
the pinned path represented by an inode. Additionally, bpf_link_ops will be
used as the f->f_ops of the opened "file" to provide operators for the
"file".

Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
---
 include/linux/bpf.h         |  6 ++++++
 kernel/bpf/bpf_struct_ops.c | 10 ++++++++++
 kernel/bpf/inode.c          | 11 ++++++++---
 kernel/bpf/syscall.c        | 16 +++++++++++++++-
 4 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 5034c1b4ded7..a0c0234d754b 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -2160,6 +2160,12 @@ extern const struct super_operations bpf_super_ops;
 extern const struct file_operations bpf_map_fops;
 extern const struct file_operations bpf_prog_fops;
 extern const struct file_operations bpf_iter_fops;
+extern const struct file_operations bpf_link_fops;
+
+#ifdef CONFIG_BPF_JIT
+/* Required by bpf_link_open() */
+int bpffs_struct_ops_link_open(struct inode *inode, struct file *filp);
+#endif
 
 #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \
 	extern const struct bpf_prog_ops _name ## _prog_ops; \
diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
index 86c7884abaf8..8be4f755a182 100644
--- a/kernel/bpf/bpf_struct_ops.c
+++ b/kernel/bpf/bpf_struct_ops.c
@@ -1198,3 +1198,13 @@ void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struct bpf_map *map
 
 	info->btf_vmlinux_id = btf_obj_id(st_map->btf);
 }
+
+int bpffs_struct_ops_link_open(struct inode *inode, struct file *filp)
+{
+	struct bpf_struct_ops_link *link = inode->i_private;
+
+	/* Paired with bpf_link_put_direct() in bpf_link_release(). */
+	bpf_link_inc(&link->link);
+	filp->private_data = link;
+	return 0;
+}
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index af5d2ffadd70..b020d761ab0a 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -360,11 +360,16 @@ static int bpf_mkmap(struct dentry *dentry, umode_t mode, void *arg)
 
 static int bpf_mklink(struct dentry *dentry, umode_t mode, void *arg)
 {
+	const struct file_operations *fops;
 	struct bpf_link *link = arg;
 
-	return bpf_mkobj_ops(dentry, mode, arg, &bpf_link_iops,
-			     bpf_link_is_iter(link) ?
-			     &bpf_iter_fops : &bpffs_obj_fops);
+	if (bpf_link_is_iter(link))
+		fops = &bpf_iter_fops;
+	else if (link->type == BPF_LINK_TYPE_STRUCT_OPS)
+		fops = &bpf_link_fops;
+	else
+		fops = &bpffs_obj_fops;
+	return bpf_mkobj_ops(dentry, mode, arg, &bpf_link_iops, fops);
 }
 
 static struct dentry *
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 7d392ec83655..265e2faf317d 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3108,7 +3108,21 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
 }
 #endif
 
-static const struct file_operations bpf_link_fops = {
+/* Support opening pinned links */
+static int bpf_link_open(struct inode *inode, struct file *filp)
+{
+#ifdef CONFIG_BPF_JIT
+	struct bpf_link *link = inode->i_private;
+
+	if (link->type == BPF_LINK_TYPE_STRUCT_OPS)
+		return bpffs_struct_ops_link_open(inode, filp);
+#endif
+
+	return -EOPNOTSUPP;
+}
+
+const struct file_operations bpf_link_fops = {
+	.open = bpf_link_open,
 #ifdef CONFIG_PROC_FS
 	.show_fdinfo	= bpf_link_show_fdinfo,
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH bpf-next v2 2/2] selftests/bpf: open a pinned path of a struct_ops link.
  2024-04-18 16:35 [PATCH bpf-next v2 0/2] Update a struct_ops link through a pinned path Kui-Feng Lee
  2024-04-18 16:35 ` [PATCH bpf-next v2 1/2] bpf: enable the "open" operator on a pinned path of a struct_osp link Kui-Feng Lee
@ 2024-04-18 16:35 ` Kui-Feng Lee
  2024-04-18 21:37 ` [PATCH bpf-next v2 0/2] Update a struct_ops link through a pinned path Eduard Zingerman
  2 siblings, 0 replies; 5+ messages in thread
From: Kui-Feng Lee @ 2024-04-18 16:35 UTC (permalink / raw)
  To: bpf, ast, martin.lau, song, kernel-team, andrii
  Cc: sinquersw, kuifeng, Kui-Feng Lee

Ensure that a pinned path of a struct_ops link can be opened to obtain a
file descriptor, which applications can then utilize to update the link.

Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
---
 .../selftests/bpf/bpf_testmod/bpf_testmod.c   |  6 ++
 .../bpf/prog_tests/test_struct_ops_module.c   | 56 +++++++++++++++++++
 2 files changed, 62 insertions(+)

diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
index 39ad96a18123..c4acd4ec630c 100644
--- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
+++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
@@ -579,6 +579,11 @@ static void bpf_dummy_unreg(void *kdata)
 {
 }
 
+static int bpf_dummy_update(void *kdata, void *old_kdata)
+{
+	return bpf_dummy_reg(kdata);
+}
+
 static int bpf_testmod_test_1(void)
 {
 	return 0;
@@ -606,6 +611,7 @@ struct bpf_struct_ops bpf_bpf_testmod_ops = {
 	.init_member = bpf_testmod_ops_init_member,
 	.reg = bpf_dummy_reg,
 	.unreg = bpf_dummy_unreg,
+	.update = bpf_dummy_update,
 	.cfi_stubs = &__bpf_testmod_ops,
 	.name = "bpf_testmod_ops",
 	.owner = THIS_MODULE,
diff --git a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c
index 7cf2b9ddd3e1..47b965c4c3e1 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c
@@ -160,6 +160,60 @@ static void test_struct_ops_incompatible(void)
 	struct_ops_module__destroy(skel);
 }
 
+/* Applications should be able to open a pinned path of a struct_ops link
+ * to get a file descriptor of the link and to update the link through the
+ * file descriptor.
+ */
+static void test_struct_ops_pinning_and_open(void)
+{
+	DECLARE_LIBBPF_OPTS(bpf_link_update_opts, opts);
+	struct struct_ops_module *skel;
+	int err, link_fd = -1, map_fd;
+	struct bpf_link *link;
+
+	/* Create and pin a struct_ops link */
+	skel = struct_ops_module__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "open_and_load"))
+		return;
+
+	link = bpf_map__attach_struct_ops(skel->maps.testmod_1);
+	if (!ASSERT_OK_PTR(link, "attach_struct_ops"))
+		goto cleanup;
+
+	err = bpf_link__pin(link, "/sys/fs/bpf/test_struct_ops_pinning");
+	if (!ASSERT_OK(err, "bpf_link__pin"))
+		goto cleanup;
+
+	/* Open the pinned path */
+	link_fd = open("/sys/fs/bpf/test_struct_ops_pinning", O_RDONLY);
+	bpf_link__unpin(link);
+	if (!ASSERT_GE(link_fd, 0, "open_pinned"))
+		goto cleanup;
+
+	skel->bss->test_1_result = 0;
+	skel->bss->test_2_result = 0;
+
+	map_fd = bpf_map__fd(skel->maps.testmod_1);
+	if (!ASSERT_GE(map_fd, 0, "map_fd"))
+		goto cleanup;
+
+	/* Update the link. test_1 and test_2 should be called again. */
+	err = bpf_link_update(link_fd, map_fd, &opts);
+	if (!ASSERT_OK(err, "bpf_link_update"))
+		goto cleanup;
+
+	/* Check if test_1 and test_2 have been called */
+	ASSERT_EQ(skel->bss->test_1_result, 0xdeadbeef,
+		  "bpf_link_update_test_1_result");
+	ASSERT_EQ(skel->bss->test_2_result, 5,
+		  "bpf_link_update_test_2_result");
+
+cleanup:
+	close(link_fd);
+	bpf_link__destroy(link);
+	struct_ops_module__destroy(skel);
+}
+
 void serial_test_struct_ops_module(void)
 {
 	if (test__start_subtest("test_struct_ops_load"))
@@ -168,5 +222,7 @@ void serial_test_struct_ops_module(void)
 		test_struct_ops_not_zeroed();
 	if (test__start_subtest("test_struct_ops_incompatible"))
 		test_struct_ops_incompatible();
+	if (test__start_subtest("test_struct_ops_pinning_and_open"))
+		test_struct_ops_pinning_and_open();
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH bpf-next v2 0/2] Update a struct_ops link through a pinned path
  2024-04-18 16:35 [PATCH bpf-next v2 0/2] Update a struct_ops link through a pinned path Kui-Feng Lee
  2024-04-18 16:35 ` [PATCH bpf-next v2 1/2] bpf: enable the "open" operator on a pinned path of a struct_osp link Kui-Feng Lee
  2024-04-18 16:35 ` [PATCH bpf-next v2 2/2] selftests/bpf: open a pinned path of a struct_ops link Kui-Feng Lee
@ 2024-04-18 21:37 ` Eduard Zingerman
  2 siblings, 0 replies; 5+ messages in thread
From: Eduard Zingerman @ 2024-04-18 21:37 UTC (permalink / raw)
  To: Kui-Feng Lee, bpf, ast, martin.lau, song, kernel-team, andrii
  Cc: sinquersw, kuifeng

On Thu, 2024-04-18 at 09:35 -0700, Kui-Feng Lee wrote:
> Applications already have the ability to update a struct_ops link with
> another struct_ops map. However, they were unable to open pinned paths
> of the links. This implies that updating a link through its pinned
> paths was not feasible. By allowing the "open" operator on pinned
> paths, applications can pin a struct_ops link and update the link
> through the pinned path later.
> 
> ---

Not an expert in how bpffs is tied together, but this patch-set seems to be fine.

Reviewed-by: Eduard Zingerman <eddyz87@gmail.com>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH bpf-next v2 1/2] bpf: enable the "open" operator on a pinned path of a struct_osp link.
  2024-04-18 16:35 ` [PATCH bpf-next v2 1/2] bpf: enable the "open" operator on a pinned path of a struct_osp link Kui-Feng Lee
@ 2024-04-25  0:09   ` Andrii Nakryiko
  0 siblings, 0 replies; 5+ messages in thread
From: Andrii Nakryiko @ 2024-04-25  0:09 UTC (permalink / raw)
  To: Kui-Feng Lee
  Cc: bpf, ast, martin.lau, song, kernel-team, andrii, sinquersw, kuifeng

On Thu, Apr 18, 2024 at 9:35 AM Kui-Feng Lee <thinker.li@gmail.com> wrote:
>
> Add the "open" operator for the inodes of BPF links to allow applications
> to obtain a file descriptor of a struct_ops link from a pinned path.
>
> Applications have the ability to update a struct_ops link with another
> struct_ops map. However, they were unable to open pinned paths of the links
> with this patch. This implies that updating a link through its pinned paths
> was not feasible.
>
> This patch adds the "open" operator to bpf_link_ops and uses bpf_link_ops
> as the i_fop for inodes of struct_ops links. "open" will be called to open
> the pinned path represented by an inode. Additionally, bpf_link_ops will be
> used as the f->f_ops of the opened "file" to provide operators for the
> "file".
>
> Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
> ---
>  include/linux/bpf.h         |  6 ++++++
>  kernel/bpf/bpf_struct_ops.c | 10 ++++++++++
>  kernel/bpf/inode.c          | 11 ++++++++---
>  kernel/bpf/syscall.c        | 16 +++++++++++++++-
>  4 files changed, 39 insertions(+), 4 deletions(-)
>

This is already supported, but you don't do it with open() syscall.
bpf() syscall provides BPF_OBJ_GET as a counterpart to BPF_OBJ_PIN. So
what you/your users want to do should be already supported through
libbpf's bpf_obj_get()/bpf_obj_get_ops() APIs. Have you tried that?

> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 5034c1b4ded7..a0c0234d754b 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -2160,6 +2160,12 @@ extern const struct super_operations bpf_super_ops;
>  extern const struct file_operations bpf_map_fops;
>  extern const struct file_operations bpf_prog_fops;
>  extern const struct file_operations bpf_iter_fops;
> +extern const struct file_operations bpf_link_fops;
> +

[...]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-04-25  0:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-18 16:35 [PATCH bpf-next v2 0/2] Update a struct_ops link through a pinned path Kui-Feng Lee
2024-04-18 16:35 ` [PATCH bpf-next v2 1/2] bpf: enable the "open" operator on a pinned path of a struct_osp link Kui-Feng Lee
2024-04-25  0:09   ` Andrii Nakryiko
2024-04-18 16:35 ` [PATCH bpf-next v2 2/2] selftests/bpf: open a pinned path of a struct_ops link Kui-Feng Lee
2024-04-18 21:37 ` [PATCH bpf-next v2 0/2] Update a struct_ops link through a pinned path Eduard Zingerman

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.