diff options
author | Wang Nan <wangnan0@huawei.com> | 2015-08-06 03:02:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-10 01:50:05 -0400 |
commit | 2a36f0b92eb638dd023870574eb471b1c56be9ad (patch) | |
tree | 74d714e1fc1e2daa98d61fdf948d9b7fae0e4378 | |
parent | ffe8690c85b8426db7783064724d106702f1b1e8 (diff) |
bpf: Make the bpf_prog_array_map more generic
All the map backends are of generic nature. In order to avoid
adding much special code into the eBPF core, rewrite part of
the bpf_prog_array map code and make it more generic. So the
new perf_event_array map type can reuse most of code with
bpf_prog_array map and add fewer lines of special code.
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: Kaixu Xia <xiakaixu@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | arch/x86/net/bpf_jit_comp.c | 6 | ||||
-rw-r--r-- | include/linux/bpf.h | 8 | ||||
-rw-r--r-- | kernel/bpf/arraymap.c | 80 | ||||
-rw-r--r-- | kernel/bpf/core.c | 2 | ||||
-rw-r--r-- | kernel/bpf/syscall.c | 2 |
5 files changed, 60 insertions, 38 deletions
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index ec5214f39aa8..70efcd0940f9 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c | |||
@@ -246,7 +246,7 @@ static void emit_prologue(u8 **pprog) | |||
246 | * goto out; | 246 | * goto out; |
247 | * if (++tail_call_cnt > MAX_TAIL_CALL_CNT) | 247 | * if (++tail_call_cnt > MAX_TAIL_CALL_CNT) |
248 | * goto out; | 248 | * goto out; |
249 | * prog = array->prog[index]; | 249 | * prog = array->ptrs[index]; |
250 | * if (prog == NULL) | 250 | * if (prog == NULL) |
251 | * goto out; | 251 | * goto out; |
252 | * goto *(prog->bpf_func + prologue_size); | 252 | * goto *(prog->bpf_func + prologue_size); |
@@ -284,9 +284,9 @@ static void emit_bpf_tail_call(u8 **pprog) | |||
284 | EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */ | 284 | EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */ |
285 | EMIT2_off32(0x89, 0x85, -STACKSIZE + 36); /* mov dword ptr [rbp - 516], eax */ | 285 | EMIT2_off32(0x89, 0x85, -STACKSIZE + 36); /* mov dword ptr [rbp - 516], eax */ |
286 | 286 | ||
287 | /* prog = array->prog[index]; */ | 287 | /* prog = array->ptrs[index]; */ |
288 | EMIT4_off32(0x48, 0x8D, 0x84, 0xD6, /* lea rax, [rsi + rdx * 8 + offsetof(...)] */ | 288 | EMIT4_off32(0x48, 0x8D, 0x84, 0xD6, /* lea rax, [rsi + rdx * 8 + offsetof(...)] */ |
289 | offsetof(struct bpf_array, prog)); | 289 | offsetof(struct bpf_array, ptrs)); |
290 | EMIT3(0x48, 0x8B, 0x00); /* mov rax, qword ptr [rax] */ | 290 | EMIT3(0x48, 0x8B, 0x00); /* mov rax, qword ptr [rax] */ |
291 | 291 | ||
292 | /* if (prog == NULL) | 292 | /* if (prog == NULL) |
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 139d6d2e123f..d495211d63d1 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h | |||
@@ -24,6 +24,10 @@ struct bpf_map_ops { | |||
24 | void *(*map_lookup_elem)(struct bpf_map *map, void *key); | 24 | void *(*map_lookup_elem)(struct bpf_map *map, void *key); |
25 | int (*map_update_elem)(struct bpf_map *map, void *key, void *value, u64 flags); | 25 | int (*map_update_elem)(struct bpf_map *map, void *key, void *value, u64 flags); |
26 | int (*map_delete_elem)(struct bpf_map *map, void *key); | 26 | int (*map_delete_elem)(struct bpf_map *map, void *key); |
27 | |||
28 | /* funcs called by prog_array and perf_event_array map */ | ||
29 | void *(*map_fd_get_ptr) (struct bpf_map *map, int fd); | ||
30 | void (*map_fd_put_ptr) (void *ptr); | ||
27 | }; | 31 | }; |
28 | 32 | ||
29 | struct bpf_map { | 33 | struct bpf_map { |
@@ -142,13 +146,13 @@ struct bpf_array { | |||
142 | bool owner_jited; | 146 | bool owner_jited; |
143 | union { | 147 | union { |
144 | char value[0] __aligned(8); | 148 | char value[0] __aligned(8); |
145 | struct bpf_prog *prog[0] __aligned(8); | 149 | void *ptrs[0] __aligned(8); |
146 | }; | 150 | }; |
147 | }; | 151 | }; |
148 | #define MAX_TAIL_CALL_CNT 32 | 152 | #define MAX_TAIL_CALL_CNT 32 |
149 | 153 | ||
150 | u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5); | 154 | u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5); |
151 | void bpf_prog_array_map_clear(struct bpf_map *map); | 155 | void bpf_fd_array_map_clear(struct bpf_map *map); |
152 | bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp); | 156 | bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp); |
153 | const struct bpf_func_proto *bpf_get_trace_printk_proto(void); | 157 | const struct bpf_func_proto *bpf_get_trace_printk_proto(void); |
154 | 158 | ||
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index cb31229a6fa4..45df6572ecfd 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c | |||
@@ -150,15 +150,15 @@ static int __init register_array_map(void) | |||
150 | } | 150 | } |
151 | late_initcall(register_array_map); | 151 | late_initcall(register_array_map); |
152 | 152 | ||
153 | static struct bpf_map *prog_array_map_alloc(union bpf_attr *attr) | 153 | static struct bpf_map *fd_array_map_alloc(union bpf_attr *attr) |
154 | { | 154 | { |
155 | /* only bpf_prog file descriptors can be stored in prog_array map */ | 155 | /* only file descriptors can be stored in this type of map */ |
156 | if (attr->value_size != sizeof(u32)) | 156 | if (attr->value_size != sizeof(u32)) |
157 | return ERR_PTR(-EINVAL); | 157 | return ERR_PTR(-EINVAL); |
158 | return array_map_alloc(attr); | 158 | return array_map_alloc(attr); |
159 | } | 159 | } |
160 | 160 | ||
161 | static void prog_array_map_free(struct bpf_map *map) | 161 | static void fd_array_map_free(struct bpf_map *map) |
162 | { | 162 | { |
163 | struct bpf_array *array = container_of(map, struct bpf_array, map); | 163 | struct bpf_array *array = container_of(map, struct bpf_array, map); |
164 | int i; | 164 | int i; |
@@ -167,21 +167,21 @@ static void prog_array_map_free(struct bpf_map *map) | |||
167 | 167 | ||
168 | /* make sure it's empty */ | 168 | /* make sure it's empty */ |
169 | for (i = 0; i < array->map.max_entries; i++) | 169 | for (i = 0; i < array->map.max_entries; i++) |
170 | BUG_ON(array->prog[i] != NULL); | 170 | BUG_ON(array->ptrs[i] != NULL); |
171 | kvfree(array); | 171 | kvfree(array); |
172 | } | 172 | } |
173 | 173 | ||
174 | static void *prog_array_map_lookup_elem(struct bpf_map *map, void *key) | 174 | static void *fd_array_map_lookup_elem(struct bpf_map *map, void *key) |
175 | { | 175 | { |
176 | return NULL; | 176 | return NULL; |
177 | } | 177 | } |
178 | 178 | ||
179 | /* only called from syscall */ | 179 | /* only called from syscall */ |
180 | static int prog_array_map_update_elem(struct bpf_map *map, void *key, | 180 | static int fd_array_map_update_elem(struct bpf_map *map, void *key, |
181 | void *value, u64 map_flags) | 181 | void *value, u64 map_flags) |
182 | { | 182 | { |
183 | struct bpf_array *array = container_of(map, struct bpf_array, map); | 183 | struct bpf_array *array = container_of(map, struct bpf_array, map); |
184 | struct bpf_prog *prog, *old_prog; | 184 | void *new_ptr, *old_ptr; |
185 | u32 index = *(u32 *)key, ufd; | 185 | u32 index = *(u32 *)key, ufd; |
186 | 186 | ||
187 | if (map_flags != BPF_ANY) | 187 | if (map_flags != BPF_ANY) |
@@ -191,57 +191,75 @@ static int prog_array_map_update_elem(struct bpf_map *map, void *key, | |||
191 | return -E2BIG; | 191 | return -E2BIG; |
192 | 192 | ||
193 | ufd = *(u32 *)value; | 193 | ufd = *(u32 *)value; |
194 | prog = bpf_prog_get(ufd); | 194 | new_ptr = map->ops->map_fd_get_ptr(map, ufd); |
195 | if (IS_ERR(prog)) | 195 | if (IS_ERR(new_ptr)) |
196 | return PTR_ERR(prog); | 196 | return PTR_ERR(new_ptr); |
197 | |||
198 | if (!bpf_prog_array_compatible(array, prog)) { | ||
199 | bpf_prog_put(prog); | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | 197 | ||
203 | old_prog = xchg(array->prog + index, prog); | 198 | old_ptr = xchg(array->ptrs + index, new_ptr); |
204 | if (old_prog) | 199 | if (old_ptr) |
205 | bpf_prog_put_rcu(old_prog); | 200 | map->ops->map_fd_put_ptr(old_ptr); |
206 | 201 | ||
207 | return 0; | 202 | return 0; |
208 | } | 203 | } |
209 | 204 | ||
210 | static int prog_array_map_delete_elem(struct bpf_map *map, void *key) | 205 | static int fd_array_map_delete_elem(struct bpf_map *map, void *key) |
211 | { | 206 | { |
212 | struct bpf_array *array = container_of(map, struct bpf_array, map); | 207 | struct bpf_array *array = container_of(map, struct bpf_array, map); |
213 | struct bpf_prog *old_prog; | 208 | void *old_ptr; |
214 | u32 index = *(u32 *)key; | 209 | u32 index = *(u32 *)key; |
215 | 210 | ||
216 | if (index >= array->map.max_entries) | 211 | if (index >= array->map.max_entries) |
217 | return -E2BIG; | 212 | return -E2BIG; |
218 | 213 | ||
219 | old_prog = xchg(array->prog + index, NULL); | 214 | old_ptr = xchg(array->ptrs + index, NULL); |
220 | if (old_prog) { | 215 | if (old_ptr) { |
221 | bpf_prog_put_rcu(old_prog); | 216 | map->ops->map_fd_put_ptr(old_ptr); |
222 | return 0; | 217 | return 0; |
223 | } else { | 218 | } else { |
224 | return -ENOENT; | 219 | return -ENOENT; |
225 | } | 220 | } |
226 | } | 221 | } |
227 | 222 | ||
223 | static void *prog_fd_array_get_ptr(struct bpf_map *map, int fd) | ||
224 | { | ||
225 | struct bpf_array *array = container_of(map, struct bpf_array, map); | ||
226 | struct bpf_prog *prog = bpf_prog_get(fd); | ||
227 | if (IS_ERR(prog)) | ||
228 | return prog; | ||
229 | |||
230 | if (!bpf_prog_array_compatible(array, prog)) { | ||
231 | bpf_prog_put(prog); | ||
232 | return ERR_PTR(-EINVAL); | ||
233 | } | ||
234 | return prog; | ||
235 | } | ||
236 | |||
237 | static void prog_fd_array_put_ptr(void *ptr) | ||
238 | { | ||
239 | struct bpf_prog *prog = ptr; | ||
240 | |||
241 | bpf_prog_put_rcu(prog); | ||
242 | } | ||
243 | |||
228 | /* decrement refcnt of all bpf_progs that are stored in this map */ | 244 | /* decrement refcnt of all bpf_progs that are stored in this map */ |
229 | void bpf_prog_array_map_clear(struct bpf_map *map) | 245 | void bpf_fd_array_map_clear(struct bpf_map *map) |
230 | { | 246 | { |
231 | struct bpf_array *array = container_of(map, struct bpf_array, map); | 247 | struct bpf_array *array = container_of(map, struct bpf_array, map); |
232 | int i; | 248 | int i; |
233 | 249 | ||
234 | for (i = 0; i < array->map.max_entries; i++) | 250 | for (i = 0; i < array->map.max_entries; i++) |
235 | prog_array_map_delete_elem(map, &i); | 251 | fd_array_map_delete_elem(map, &i); |
236 | } | 252 | } |
237 | 253 | ||
238 | static const struct bpf_map_ops prog_array_ops = { | 254 | static const struct bpf_map_ops prog_array_ops = { |
239 | .map_alloc = prog_array_map_alloc, | 255 | .map_alloc = fd_array_map_alloc, |
240 | .map_free = prog_array_map_free, | 256 | .map_free = fd_array_map_free, |
241 | .map_get_next_key = array_map_get_next_key, | 257 | .map_get_next_key = array_map_get_next_key, |
242 | .map_lookup_elem = prog_array_map_lookup_elem, | 258 | .map_lookup_elem = fd_array_map_lookup_elem, |
243 | .map_update_elem = prog_array_map_update_elem, | 259 | .map_update_elem = fd_array_map_update_elem, |
244 | .map_delete_elem = prog_array_map_delete_elem, | 260 | .map_delete_elem = fd_array_map_delete_elem, |
261 | .map_fd_get_ptr = prog_fd_array_get_ptr, | ||
262 | .map_fd_put_ptr = prog_fd_array_put_ptr, | ||
245 | }; | 263 | }; |
246 | 264 | ||
247 | static struct bpf_map_type_list prog_array_type __read_mostly = { | 265 | static struct bpf_map_type_list prog_array_type __read_mostly = { |
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index fafa74161445..67c380cfa9ca 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c | |||
@@ -450,7 +450,7 @@ select_insn: | |||
450 | 450 | ||
451 | tail_call_cnt++; | 451 | tail_call_cnt++; |
452 | 452 | ||
453 | prog = READ_ONCE(array->prog[index]); | 453 | prog = READ_ONCE(array->ptrs[index]); |
454 | if (unlikely(!prog)) | 454 | if (unlikely(!prog)) |
455 | goto out; | 455 | goto out; |
456 | 456 | ||
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index a1b14d197a4f..dc9b464fefa9 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -72,7 +72,7 @@ static int bpf_map_release(struct inode *inode, struct file *filp) | |||
72 | /* prog_array stores refcnt-ed bpf_prog pointers | 72 | /* prog_array stores refcnt-ed bpf_prog pointers |
73 | * release them all when user space closes prog_array_fd | 73 | * release them all when user space closes prog_array_fd |
74 | */ | 74 | */ |
75 | bpf_prog_array_map_clear(map); | 75 | bpf_fd_array_map_clear(map); |
76 | 76 | ||
77 | bpf_map_put(map); | 77 | bpf_map_put(map); |
78 | return 0; | 78 | return 0; |