diff options
| author | Jakub Kicinski <jakub.kicinski@netronome.com> | 2017-12-27 21:39:06 -0500 |
|---|---|---|
| committer | Daniel Borkmann <daniel@iogearbox.net> | 2017-12-31 10:12:23 -0500 |
| commit | ce3b9db4db0e0e2b9761c56d08615ea0159e4a1b (patch) | |
| tree | 082f0709593e9d271c3dfddcfea1a4c0454654f7 | |
| parent | cae1927c0b4a93ae15de824faca1f6f611a44fcd (diff) | |
bpf: offload: free prog->aux->offload when device disappears
All bpf offload operations should now be under bpf_devs_lock,
it's safe to free and clear the entire offload structure,
not only the netdev pointer.
__bpf_prog_offload_destroy() will no longer be called multiple
times.
Suggested-by: Alexei Starovoitov <ast@kernel.org>
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>
| -rw-r--r-- | kernel/bpf/offload.c | 23 |
1 files changed, 9 insertions, 14 deletions
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c index 69ddc3899bab..3126e1a842e6 100644 --- a/kernel/bpf/offload.c +++ b/kernel/bpf/offload.c | |||
| @@ -70,12 +70,14 @@ err_free: | |||
| 70 | static int __bpf_offload_ndo(struct bpf_prog *prog, enum bpf_netdev_command cmd, | 70 | static int __bpf_offload_ndo(struct bpf_prog *prog, enum bpf_netdev_command cmd, |
| 71 | struct netdev_bpf *data) | 71 | struct netdev_bpf *data) |
| 72 | { | 72 | { |
| 73 | struct net_device *netdev = prog->aux->offload->netdev; | 73 | struct bpf_dev_offload *offload = prog->aux->offload; |
| 74 | struct net_device *netdev; | ||
| 74 | 75 | ||
| 75 | ASSERT_RTNL(); | 76 | ASSERT_RTNL(); |
| 76 | 77 | ||
| 77 | if (!netdev) | 78 | if (!offload) |
| 78 | return -ENODEV; | 79 | return -ENODEV; |
| 80 | netdev = offload->netdev; | ||
| 79 | if (!netdev->netdev_ops->ndo_bpf) | 81 | if (!netdev->netdev_ops->ndo_bpf) |
| 80 | return -EOPNOTSUPP; | 82 | return -EOPNOTSUPP; |
| 81 | 83 | ||
| @@ -111,7 +113,7 @@ int bpf_prog_offload_verify_insn(struct bpf_verifier_env *env, | |||
| 111 | 113 | ||
| 112 | down_read(&bpf_devs_lock); | 114 | down_read(&bpf_devs_lock); |
| 113 | offload = env->prog->aux->offload; | 115 | offload = env->prog->aux->offload; |
| 114 | if (offload->netdev) | 116 | if (offload) |
| 115 | ret = offload->dev_ops->insn_hook(env, insn_idx, prev_insn_idx); | 117 | ret = offload->dev_ops->insn_hook(env, insn_idx, prev_insn_idx); |
| 116 | up_read(&bpf_devs_lock); | 118 | up_read(&bpf_devs_lock); |
| 117 | 119 | ||
| @@ -123,31 +125,24 @@ static void __bpf_prog_offload_destroy(struct bpf_prog *prog) | |||
| 123 | struct bpf_dev_offload *offload = prog->aux->offload; | 125 | struct bpf_dev_offload *offload = prog->aux->offload; |
| 124 | struct netdev_bpf data = {}; | 126 | struct netdev_bpf data = {}; |
| 125 | 127 | ||
| 126 | /* Caution - if netdev is destroyed before the program, this function | ||
| 127 | * will be called twice. | ||
| 128 | */ | ||
| 129 | |||
| 130 | data.offload.prog = prog; | 128 | data.offload.prog = prog; |
| 131 | 129 | ||
| 132 | if (offload->dev_state) | 130 | if (offload->dev_state) |
| 133 | WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data)); | 131 | WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data)); |
| 134 | 132 | ||
| 135 | offload->dev_state = false; | ||
| 136 | list_del_init(&offload->offloads); | 133 | list_del_init(&offload->offloads); |
| 137 | offload->netdev = NULL; | 134 | kfree(offload); |
| 135 | prog->aux->offload = NULL; | ||
| 138 | } | 136 | } |
| 139 | 137 | ||
| 140 | void bpf_prog_offload_destroy(struct bpf_prog *prog) | 138 | void bpf_prog_offload_destroy(struct bpf_prog *prog) |
| 141 | { | 139 | { |
| 142 | struct bpf_dev_offload *offload = prog->aux->offload; | ||
| 143 | |||
| 144 | rtnl_lock(); | 140 | rtnl_lock(); |
| 145 | down_write(&bpf_devs_lock); | 141 | down_write(&bpf_devs_lock); |
| 146 | __bpf_prog_offload_destroy(prog); | 142 | if (prog->aux->offload) |
| 143 | __bpf_prog_offload_destroy(prog); | ||
| 147 | up_write(&bpf_devs_lock); | 144 | up_write(&bpf_devs_lock); |
| 148 | rtnl_unlock(); | 145 | rtnl_unlock(); |
| 149 | |||
| 150 | kfree(offload); | ||
| 151 | } | 146 | } |
| 152 | 147 | ||
| 153 | static int bpf_prog_offload_translate(struct bpf_prog *prog) | 148 | static int bpf_prog_offload_translate(struct bpf_prog *prog) |
