diff mbox series

[RFC,bpf-next,3/4] bpf: Introduce bpf iterator for file system mount

Message ID 20230507040107.3755166-4-houtao@huaweicloud.com (mailing list archive)
State Mainlined, archived
Headers show
Series Introduce bpf iterators for file-system | expand

Commit Message

Hou Tao May 7, 2023, 4:01 a.m. UTC
From: Hou Tao <houtao1@huawei.com>

Now the only way to query the information about a specific mount is to
parse the content of /proc/pid/mountinfo, find the specific mount and
return the needed information.

There is no way to query for a specific mount directly, so introduce bpf
iterator for fs mount to support that. By passing a fd to bpf iterator,
the bpf program will get the mount of the specific file and it can
output the necessary information for the mount in bpf iterator fd.

The following is the output from "test_progs -t bpf_iter_fs/fs_mnt"
which shows the basic information of a tmpfs mount:

  dev 0:31 id 40 parent_id 24 mnt_flags 0x1003 shared:17

Signed-off-by: Hou Tao <houtao1@huawei.com>
---
 include/linux/btf_ids.h        |  3 +-
 include/uapi/linux/bpf.h       |  1 +
 kernel/bpf/fs_iter.c           | 60 +++++++++++++++++++++++++++++-----
 tools/include/uapi/linux/bpf.h |  1 +
 4 files changed, 55 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/include/linux/btf_ids.h b/include/linux/btf_ids.h
index 9e036d1360e7..48537adee9fc 100644
--- a/include/linux/btf_ids.h
+++ b/include/linux/btf_ids.h
@@ -257,7 +257,8 @@  extern u32 btf_sock_ids[];
 	BTF_TRACING_TYPE(BTF_TRACING_TYPE_FILE, file)		\
 	BTF_TRACING_TYPE(BTF_TRACING_TYPE_VMA, vm_area_struct)	\
 	BTF_TRACING_TYPE(BTF_TRACING_TYPE_INODE, inode)		\
-	BTF_TRACING_TYPE(BTF_TRACING_TYPE_DENTRY, dentry)
+	BTF_TRACING_TYPE(BTF_TRACING_TYPE_DENTRY, dentry)	\
+	BTF_TRACING_TYPE(BTF_TRACING_TYPE_MOUNT, mount)
 
 
 enum {
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 099048ba3edc..62bed6e603a5 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -97,6 +97,7 @@  enum bpf_cgroup_iter_order {
 
 enum bpf_fs_iter_type {
 	BPF_FS_ITER_INODE = 0,	/* a specific inode */
+	BPF_FS_ITER_MNT,	/* a specific mount */
 };
 
 union bpf_iter_link_info {
diff --git a/kernel/bpf/fs_iter.c b/kernel/bpf/fs_iter.c
index cd7f10ea00ab..19f83211ccc4 100644
--- a/kernel/bpf/fs_iter.c
+++ b/kernel/bpf/fs_iter.c
@@ -9,7 +9,11 @@ 
 #include <linux/btf_ids.h>
 #include <linux/seq_file.h>
 
+/* TODO: move fs_iter.c to fs directory ? */
+#include "../../fs/mount.h"
+
 DEFINE_BPF_ITER_FUNC(fs_inode, struct bpf_iter_meta *meta, struct inode *inode, struct dentry *dentry);
+DEFINE_BPF_ITER_FUNC(fs_mnt, struct bpf_iter_meta *meta, struct mount *mnt);
 
 struct bpf_iter__fs_inode {
 	__bpf_md_ptr(struct bpf_iter_meta *, meta);
@@ -17,6 +21,11 @@  struct bpf_iter__fs_inode {
 	__bpf_md_ptr(struct dentry *, dentry);
 };
 
+struct bpf_iter__fs_mnt {
+	__bpf_md_ptr(struct bpf_iter_meta *, meta);
+	__bpf_md_ptr(struct mount *, mnt);
+};
+
 struct bpf_fs_iter_aux_info {
 	atomic_t count;
 	enum bpf_fs_iter_type type;
@@ -47,7 +56,7 @@  static int bpf_iter_attach_fs(struct bpf_prog *prog, union bpf_iter_link_info *l
 	struct bpf_fs_iter_aux_info *fs;
 	struct file *filp;
 
-	if (linfo->fs.type > BPF_FS_ITER_INODE)
+	if (linfo->fs.type > BPF_FS_ITER_MNT)
 		return -EINVAL;
 	/* TODO: The file-system is pinned */
 	filp = fget(linfo->fs.fd);
@@ -99,12 +108,14 @@  static void *fs_iter_seq_start(struct seq_file *m, loff_t *pos)
 	if (*pos == 0)
 		++*pos;
 
-	return file_inode(info->fs->filp);
+	if (info->fs->type == BPF_FS_ITER_INODE)
+		return file_inode(info->fs->filp);
+	return real_mount(info->fs->filp->f_path.mnt);
 }
 
 static int __fs_iter_seq_show(struct seq_file *m, void *v, bool stop)
 {
-	struct bpf_iter__fs_inode ctx;
+	struct bpf_iter_seq_fs_info *info = m->private;
 	struct bpf_iter_meta meta;
 	struct bpf_prog *prog;
 	int err;
@@ -114,11 +125,21 @@  static int __fs_iter_seq_show(struct seq_file *m, void *v, bool stop)
 	if (!prog)
 		return 0;
 
-	ctx.meta = &meta;
-	ctx.inode = v;
-	ctx.dentry = v ? d_find_alias(v) : NULL;
-	err = bpf_iter_run_prog(prog, &ctx);
-	dput(ctx.dentry);
+	if (info->fs->type == BPF_FS_ITER_INODE) {
+		struct bpf_iter__fs_inode ino_ctx;
+
+		ino_ctx.meta = &meta;
+		ino_ctx.inode = v;
+		ino_ctx.dentry = v ? d_find_alias(v) : NULL;
+		err = bpf_iter_run_prog(prog, &ino_ctx);
+		dput(ino_ctx.dentry);
+	} else {
+		struct bpf_iter__fs_mnt mnt_ctx;
+
+		mnt_ctx.meta = &meta;
+		mnt_ctx.mnt = v;
+		err = bpf_iter_run_prog(prog, &mnt_ctx);
+	}
 	return err;
 }
 
@@ -165,10 +186,31 @@  static struct bpf_iter_reg fs_inode_reg_info = {
 	.seq_info = &fs_iter_seq_info,
 };
 
+static struct bpf_iter_reg fs_mnt_reg_info = {
+	.target = "fs_mnt",
+	.attach_target = bpf_iter_attach_fs,
+	.detach_target = bpf_iter_detach_fs,
+	.ctx_arg_info_size = 1,
+	.ctx_arg_info = {
+		{ offsetof(struct bpf_iter__fs_mnt, mnt), PTR_TO_BTF_ID_OR_NULL },
+	},
+	.seq_info = &fs_iter_seq_info,
+};
+
 static int __init fs_iter_init(void)
 {
+	int err;
+
 	fs_inode_reg_info.ctx_arg_info[0].btf_id = btf_tracing_ids[BTF_TRACING_TYPE_INODE];
 	fs_inode_reg_info.ctx_arg_info[1].btf_id = btf_tracing_ids[BTF_TRACING_TYPE_DENTRY];
-	return bpf_iter_reg_target(&fs_inode_reg_info);
+	err = bpf_iter_reg_target(&fs_inode_reg_info);
+	if (err)
+		return err;
+
+	fs_mnt_reg_info.ctx_arg_info[0].btf_id = btf_tracing_ids[BTF_TRACING_TYPE_MOUNT];
+	err = bpf_iter_reg_target(&fs_mnt_reg_info);
+	if (err)
+		bpf_iter_unreg_target(&fs_inode_reg_info);
+	return err;
 }
 late_initcall(fs_iter_init);
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 099048ba3edc..62bed6e603a5 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -97,6 +97,7 @@  enum bpf_cgroup_iter_order {
 
 enum bpf_fs_iter_type {
 	BPF_FS_ITER_INODE = 0,	/* a specific inode */
+	BPF_FS_ITER_MNT,	/* a specific mount */
 };
 
 union bpf_iter_link_info {