|
26 | 26 | #include <linux/stddef.h> |
27 | 27 | #include <linux/bpfptr.h> |
28 | 28 | #include <linux/btf.h> |
| 29 | +#include <linux/rcupdate_trace.h> |
29 | 30 |
|
30 | 31 | struct bpf_verifier_env; |
31 | 32 | struct bpf_verifier_log; |
@@ -1343,6 +1344,8 @@ extern struct bpf_empty_prog_array bpf_empty_prog_array; |
1343 | 1344 |
|
1344 | 1345 | struct bpf_prog_array *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags); |
1345 | 1346 | void bpf_prog_array_free(struct bpf_prog_array *progs); |
| 1347 | +/* Use when traversal over the bpf_prog_array uses tasks_trace rcu */ |
| 1348 | +void bpf_prog_array_free_sleepable(struct bpf_prog_array *progs); |
1346 | 1349 | int bpf_prog_array_length(struct bpf_prog_array *progs); |
1347 | 1350 | bool bpf_prog_array_is_empty(struct bpf_prog_array *array); |
1348 | 1351 | int bpf_prog_array_copy_to_user(struct bpf_prog_array *progs, |
@@ -1428,6 +1431,60 @@ bpf_prog_run_array(const struct bpf_prog_array *array, |
1428 | 1431 | return ret; |
1429 | 1432 | } |
1430 | 1433 |
|
| 1434 | +/** |
| 1435 | + * Notes on RCU design for bpf_prog_arrays containing sleepable programs: |
| 1436 | + * |
| 1437 | + * We use the tasks_trace rcu flavor read section to protect the bpf_prog_array |
| 1438 | + * overall. As a result, we must use the bpf_prog_array_free_sleepable |
| 1439 | + * in order to use the tasks_trace rcu grace period. |
| 1440 | + * |
| 1441 | + * When a non-sleepable program is inside the array, we take the rcu read |
| 1442 | + * section and disable preemption for that program alone, so it can access |
| 1443 | + * rcu-protected dynamically sized maps. |
| 1444 | + */ |
| 1445 | +static __always_inline u32 |
| 1446 | +bpf_prog_run_array_sleepable(const struct bpf_prog_array __rcu *array_rcu, |
| 1447 | + const void *ctx, bpf_prog_run_fn run_prog) |
| 1448 | +{ |
| 1449 | + const struct bpf_prog_array_item *item; |
| 1450 | + const struct bpf_prog *prog; |
| 1451 | + const struct bpf_prog_array *array; |
| 1452 | + struct bpf_run_ctx *old_run_ctx; |
| 1453 | + struct bpf_trace_run_ctx run_ctx; |
| 1454 | + u32 ret = 1; |
| 1455 | + |
| 1456 | + might_fault(); |
| 1457 | + |
| 1458 | + migrate_disable(); |
| 1459 | + rcu_read_lock_trace(); |
| 1460 | + |
| 1461 | + array = rcu_dereference_check(array_rcu, rcu_read_lock_trace_held()); |
| 1462 | + if (unlikely(!array)) |
| 1463 | + goto out; |
| 1464 | + old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx); |
| 1465 | + item = &array->items[0]; |
| 1466 | + while ((prog = READ_ONCE(item->prog))) { |
| 1467 | + if (!prog->aux->sleepable) { |
| 1468 | + preempt_disable(); |
| 1469 | + rcu_read_lock(); |
| 1470 | + } |
| 1471 | + |
| 1472 | + run_ctx.bpf_cookie = item->bpf_cookie; |
| 1473 | + ret &= run_prog(prog, ctx); |
| 1474 | + item++; |
| 1475 | + |
| 1476 | + if (!prog->aux->sleepable) { |
| 1477 | + rcu_read_unlock(); |
| 1478 | + preempt_enable(); |
| 1479 | + } |
| 1480 | + } |
| 1481 | + bpf_reset_run_ctx(old_run_ctx); |
| 1482 | +out: |
| 1483 | + rcu_read_unlock_trace(); |
| 1484 | + migrate_enable(); |
| 1485 | + return ret; |
| 1486 | +} |
| 1487 | + |
1431 | 1488 | #ifdef CONFIG_BPF_SYSCALL |
1432 | 1489 | DECLARE_PER_CPU(int, bpf_prog_active); |
1433 | 1490 | extern struct mutex bpf_stats_enabled_mutex; |
|
0 commit comments