Skip to content

Commit 70ed506

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
bpf: Introduce pinnable bpf_link abstraction
Introduce bpf_link abstraction, representing an attachment of BPF program to a BPF hook point (e.g., tracepoint, perf event, etc). bpf_link encapsulates ownership of attached BPF program, reference counting of a link itself, when reference from multiple anonymous inodes, as well as ensures that release callback will be called from a process context, so that users can safely take mutex locks and sleep. Additionally, with a new abstraction it's now possible to generalize pinning of a link object in BPF FS, allowing to explicitly prevent BPF program detachment on process exit by pinning it in a BPF FS and let it open from independent other process to keep working with it. Convert two existing bpf_link-like objects (raw tracepoint and tracing BPF program attachments) into utilizing bpf_link framework, making them pinnable in BPF FS. More FD-based bpf_links will be added in follow up patches. Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 775a2be commit 70ed506

File tree

3 files changed

+232
-46
lines changed

3 files changed

+232
-46
lines changed

include/linux/bpf.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,19 @@ extern int sysctl_unprivileged_bpf_disabled;
10561056
int bpf_map_new_fd(struct bpf_map *map, int flags);
10571057
int bpf_prog_new_fd(struct bpf_prog *prog);
10581058

1059+
struct bpf_link;
1060+
1061+
struct bpf_link_ops {
1062+
void (*release)(struct bpf_link *link);
1063+
};
1064+
1065+
void bpf_link_init(struct bpf_link *link, const struct bpf_link_ops *ops,
1066+
struct bpf_prog *prog);
1067+
void bpf_link_inc(struct bpf_link *link);
1068+
void bpf_link_put(struct bpf_link *link);
1069+
int bpf_link_new_fd(struct bpf_link *link);
1070+
struct bpf_link *bpf_link_get_from_fd(u32 ufd);
1071+
10591072
int bpf_obj_pin_user(u32 ufd, const char __user *pathname);
10601073
int bpf_obj_get_user(const char __user *pathname, int flags);
10611074

kernel/bpf/inode.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ enum bpf_type {
2525
BPF_TYPE_UNSPEC = 0,
2626
BPF_TYPE_PROG,
2727
BPF_TYPE_MAP,
28+
BPF_TYPE_LINK,
2829
};
2930

3031
static void *bpf_any_get(void *raw, enum bpf_type type)
@@ -36,6 +37,9 @@ static void *bpf_any_get(void *raw, enum bpf_type type)
3637
case BPF_TYPE_MAP:
3738
bpf_map_inc_with_uref(raw);
3839
break;
40+
case BPF_TYPE_LINK:
41+
bpf_link_inc(raw);
42+
break;
3943
default:
4044
WARN_ON_ONCE(1);
4145
break;
@@ -53,6 +57,9 @@ static void bpf_any_put(void *raw, enum bpf_type type)
5357
case BPF_TYPE_MAP:
5458
bpf_map_put_with_uref(raw);
5559
break;
60+
case BPF_TYPE_LINK:
61+
bpf_link_put(raw);
62+
break;
5663
default:
5764
WARN_ON_ONCE(1);
5865
break;
@@ -63,20 +70,32 @@ static void *bpf_fd_probe_obj(u32 ufd, enum bpf_type *type)
6370
{
6471
void *raw;
6572

66-
*type = BPF_TYPE_MAP;
6773
raw = bpf_map_get_with_uref(ufd);
68-
if (IS_ERR(raw)) {
74+
if (!IS_ERR(raw)) {
75+
*type = BPF_TYPE_MAP;
76+
return raw;
77+
}
78+
79+
raw = bpf_prog_get(ufd);
80+
if (!IS_ERR(raw)) {
6981
*type = BPF_TYPE_PROG;
70-
raw = bpf_prog_get(ufd);
82+
return raw;
7183
}
7284

73-
return raw;
85+
raw = bpf_link_get_from_fd(ufd);
86+
if (!IS_ERR(raw)) {
87+
*type = BPF_TYPE_LINK;
88+
return raw;
89+
}
90+
91+
return ERR_PTR(-EINVAL);
7492
}
7593

7694
static const struct inode_operations bpf_dir_iops;
7795

7896
static const struct inode_operations bpf_prog_iops = { };
7997
static const struct inode_operations bpf_map_iops = { };
98+
static const struct inode_operations bpf_link_iops = { };
8099

81100
static struct inode *bpf_get_inode(struct super_block *sb,
82101
const struct inode *dir,
@@ -114,6 +133,8 @@ static int bpf_inode_type(const struct inode *inode, enum bpf_type *type)
114133
*type = BPF_TYPE_PROG;
115134
else if (inode->i_op == &bpf_map_iops)
116135
*type = BPF_TYPE_MAP;
136+
else if (inode->i_op == &bpf_link_iops)
137+
*type = BPF_TYPE_LINK;
117138
else
118139
return -EACCES;
119140

@@ -335,6 +356,12 @@ static int bpf_mkmap(struct dentry *dentry, umode_t mode, void *arg)
335356
&bpffs_map_fops : &bpffs_obj_fops);
336357
}
337358

359+
static int bpf_mklink(struct dentry *dentry, umode_t mode, void *arg)
360+
{
361+
return bpf_mkobj_ops(dentry, mode, arg, &bpf_link_iops,
362+
&bpffs_obj_fops);
363+
}
364+
338365
static struct dentry *
339366
bpf_lookup(struct inode *dir, struct dentry *dentry, unsigned flags)
340367
{
@@ -411,6 +438,9 @@ static int bpf_obj_do_pin(const char __user *pathname, void *raw,
411438
case BPF_TYPE_MAP:
412439
ret = vfs_mkobj(dentry, mode, bpf_mkmap, raw);
413440
break;
441+
case BPF_TYPE_LINK:
442+
ret = vfs_mkobj(dentry, mode, bpf_mklink, raw);
443+
break;
414444
default:
415445
ret = -EPERM;
416446
}
@@ -487,6 +517,8 @@ int bpf_obj_get_user(const char __user *pathname, int flags)
487517
ret = bpf_prog_new_fd(raw);
488518
else if (type == BPF_TYPE_MAP)
489519
ret = bpf_map_new_fd(raw, f_flags);
520+
else if (type == BPF_TYPE_LINK)
521+
ret = bpf_link_new_fd(raw);
490522
else
491523
return -ENOENT;
492524

@@ -504,6 +536,8 @@ static struct bpf_prog *__get_prog_inode(struct inode *inode, enum bpf_prog_type
504536

505537
if (inode->i_op == &bpf_map_iops)
506538
return ERR_PTR(-EINVAL);
539+
if (inode->i_op == &bpf_link_iops)
540+
return ERR_PTR(-EINVAL);
507541
if (inode->i_op != &bpf_prog_iops)
508542
return ERR_PTR(-EACCES);
509543

0 commit comments

Comments
 (0)