diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 7719f65284456..bacb6bc2e27bd 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1376,6 +1376,11 @@ struct bpf_tramp_image { struct rcu_head rcu; struct work_struct work; }; +#ifdef CONFIG_PREEMPTION + /* Programs called from this image must outlive deferred image freeing. */ + struct bpf_prog *progs[BPF_MAX_TRAMP_LINKS]; + int nr_progs; +#endif }; struct bpf_trampoline { diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index 1a721fc4bef56..ff6b331c965b7 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -531,6 +531,13 @@ bpf_trampoline_get_progs(const struct bpf_trampoline *tr, int *total, bool *ip_a static void bpf_tramp_image_free(struct bpf_tramp_image *im) { +#ifdef CONFIG_PREEMPTION + int i; + + for (i = 0; i < im->nr_progs; i++) + bpf_prog_put(im->progs[i]); +#endif + bpf_image_ksym_del(&im->ksym); arch_free_bpf_trampoline(im->image, im->size); bpf_jit_uncharge_modmem(im->size); @@ -678,6 +685,9 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut u32 orig_flags = tr->flags; bool ip_arg = false; int err, total, size; +#ifdef CONFIG_PREEMPTION + int i, kind; +#endif tnodes = bpf_trampoline_get_progs(tr, &total, &ip_arg); if (IS_ERR(tnodes)) @@ -740,6 +750,16 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut goto out; } +#ifdef CONFIG_PREEMPTION + for (kind = 0; kind < BPF_TRAMP_MAX; kind++) + for (i = 0; i < tnodes[kind].nr_nodes; i++) { + struct bpf_prog *prog = tnodes[kind].nodes[i]->link->prog; + + bpf_prog_inc(prog); + im->progs[im->nr_progs++] = prog; + } +#endif + err = arch_prepare_bpf_trampoline(im, im->image, im->image + size, &tr->func.model, tr->flags, tnodes, tr->func.addr);