Add epoll support to bpf struct_ops links to trigger EPOLLHUP event upon detachment. Signed-off-by: Kui-Feng Lee <thinker.li@xxxxxxxxx> --- include/linux/bpf.h | 2 ++ kernel/bpf/bpf_struct_ops.c | 14 ++++++++++++++ kernel/bpf/syscall.c | 15 +++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index eeeed4b1bd32..a4550b927352 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1574,6 +1574,7 @@ struct bpf_link { const struct bpf_link_ops *ops; struct bpf_prog *prog; struct work_struct work; + wait_queue_head_t wait_hup; }; struct bpf_link_ops { @@ -1587,6 +1588,7 @@ struct bpf_link_ops { struct bpf_link_info *info); int (*update_map)(struct bpf_link *link, struct bpf_map *new_map, struct bpf_map *old_map); + __poll_t (*poll)(struct file *file, struct poll_table_struct *pts); }; struct bpf_tramp_link { diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 4a8a7e5ffc56..f19b6a76591a 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -12,6 +12,7 @@ #include <linux/mutex.h> #include <linux/btf_ids.h> #include <linux/rcupdate_wait.h> +#include <linux/poll.h> struct bpf_struct_ops_value { struct bpf_struct_ops_common_value common; @@ -1149,6 +1150,8 @@ bool bpf_struct_ops_kvalue_unreg(void *data) */ bpf_map_put(&st_map->map); + wake_up_interruptible_poll(&st_link->link.wait_hup, EPOLLHUP); + ret = true; fail_unlock: @@ -1276,15 +1279,26 @@ static int bpf_struct_ops_map_link_detach(struct bpf_link *link) mutex_unlock(&update_mutex); + wake_up_interruptible_poll(&st_link->link.wait_hup, EPOLLHUP); + return 0; } +static __poll_t bpf_struct_ops_map_link_poll(struct file *file, + struct poll_table_struct *ptrs) +{ + struct bpf_struct_ops_link *st_link = file->private_data; + + return (st_link->map) ? 0 : EPOLLHUP | EPOLLERR; +} + static const struct bpf_link_ops bpf_struct_ops_map_lops = { .dealloc = bpf_struct_ops_map_link_dealloc, .detach = bpf_struct_ops_map_link_detach, .show_fdinfo = bpf_struct_ops_map_link_show_fdinfo, .fill_link_info = bpf_struct_ops_map_link_fill_link_info, .update_map = bpf_struct_ops_map_link_update, + .poll = bpf_struct_ops_map_link_poll, }; int bpf_struct_ops_link_create(union bpf_attr *attr) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 4a2f95c4b2ac..b4dbca04d4f5 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2990,6 +2990,7 @@ void bpf_link_init(struct bpf_link *link, enum bpf_link_type type, link->id = 0; link->ops = ops; link->prog = prog; + init_waitqueue_head(&link->wait_hup); } static void bpf_link_free_id(int id) @@ -3108,6 +3109,19 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp) } #endif +static __poll_t bpf_link_poll(struct file *file, struct poll_table_struct *pts) +{ + struct bpf_link *link = file->private_data; + + if (link->ops->poll) { + poll_wait(file, &link->wait_hup, pts); + + return link->ops->poll(file, pts); + } + + return 0; +} + static const struct file_operations bpf_link_fops = { #ifdef CONFIG_PROC_FS .show_fdinfo = bpf_link_show_fdinfo, @@ -3115,6 +3129,7 @@ static const struct file_operations bpf_link_fops = { .release = bpf_link_release, .read = bpf_dummy_read, .write = bpf_dummy_write, + .poll = bpf_link_poll, }; static int bpf_link_alloc_id(struct bpf_link *link) -- 2.34.1