Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: offload: free program id when device disappears

Bound programs are quite useless after their device disappears.
They are simply waiting for reference count to go to zero,
don't list them in BPF_PROG_GET_NEXT_ID by freeing their ID
early.

Note that orphaned offload programs will return -ENODEV on
BPF_OBJ_GET_INFO_BY_FD so user will never see ID 0.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>

authored by

Jakub Kicinski and committed by
Daniel Borkmann
ad8ad79f ce3b9db4

+12 -2
+2
include/linux/bpf.h
··· 357 357 int __bpf_prog_charge(struct user_struct *user, u32 pages); 358 358 void __bpf_prog_uncharge(struct user_struct *user, u32 pages); 359 359 360 + void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock); 361 + 360 362 struct bpf_map *bpf_map_get_with_uref(u32 ufd); 361 363 struct bpf_map *__bpf_map_get(struct fd f); 362 364 struct bpf_map * __must_check bpf_map_inc(struct bpf_map *map, bool uref);
+3
kernel/bpf/offload.c
··· 130 130 if (offload->dev_state) 131 131 WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data)); 132 132 133 + /* Make sure BPF_PROG_GET_NEXT_ID can't find this dead program */ 134 + bpf_prog_free_id(prog, true); 135 + 133 136 list_del_init(&offload->offloads); 134 137 kfree(offload); 135 138 prog->aux->offload = NULL;
+7 -2
kernel/bpf/syscall.c
··· 905 905 return id > 0 ? 0 : id; 906 906 } 907 907 908 - static void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock) 908 + void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock) 909 909 { 910 - /* cBPF to eBPF migrations are currently not in the idr store. */ 910 + /* cBPF to eBPF migrations are currently not in the idr store. 911 + * Offloaded programs are removed from the store when their device 912 + * disappears - even if someone grabs an fd to them they are unusable, 913 + * simply waiting for refcnt to drop to be freed. 914 + */ 911 915 if (!prog->aux->id) 912 916 return; 913 917 ··· 921 917 __acquire(&prog_idr_lock); 922 918 923 919 idr_remove(&prog_idr, prog->aux->id); 920 + prog->aux->id = 0; 924 921 925 922 if (do_idr_lock) 926 923 spin_unlock_bh(&prog_idr_lock);