Skip to content

Commit d114dde

Browse files
Alexei Starovoitovborkmann
authored andcommitted
bpf: Change bpf_mem_cache draining process.
The next patch will introduce cross-cpu llist access and existing irq_work_sync() + drain_mem_cache() + rcu_barrier_tasks_trace() mechanism will not be enough, since irq_work_sync() + drain_mem_cache() on cpu A won't guarantee that llist on cpu A are empty. The free_bulk() on cpu B might add objects back to llist of cpu A. Add 'bool draining' flag. The modified sequence looks like: for_each_cpu: WRITE_ONCE(c->draining, true); // do_call_rcu_ttrace() won't be doing call_rcu() any more irq_work_sync(); // wait for irq_work callback (free_bulk) to finish drain_mem_cache(); // free all objects rcu_barrier_tasks_trace(); // wait for RCU callbacks to execute Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Hou Tao <houtao1@huawei.com> Link: https://lore.kernel.org/bpf/20230706033447.54696-8-alexei.starovoitov@gmail.com
1 parent 7468048 commit d114dde

File tree

1 file changed

+9
-9
lines changed

1 file changed

+9
-9
lines changed

kernel/bpf/memalloc.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ struct bpf_mem_cache {
9898
int free_cnt;
9999
int low_watermark, high_watermark, batch;
100100
int percpu_size;
101+
bool draining;
101102

102103
/* list of objects to be freed after RCU tasks trace GP */
103104
struct llist_head free_by_rcu_ttrace;
@@ -301,6 +302,12 @@ static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
301302
* from __free_rcu() and from drain_mem_cache().
302303
*/
303304
__llist_add(llnode, &c->waiting_for_gp_ttrace);
305+
306+
if (unlikely(READ_ONCE(c->draining))) {
307+
__free_rcu(&c->rcu_ttrace);
308+
return;
309+
}
310+
304311
/* Use call_rcu_tasks_trace() to wait for sleepable progs to finish.
305312
* If RCU Tasks Trace grace period implies RCU grace period, free
306313
* these elements directly, else use call_rcu() to wait for normal
@@ -544,15 +551,7 @@ void bpf_mem_alloc_destroy(struct bpf_mem_alloc *ma)
544551
rcu_in_progress = 0;
545552
for_each_possible_cpu(cpu) {
546553
c = per_cpu_ptr(ma->cache, cpu);
547-
/*
548-
* refill_work may be unfinished for PREEMPT_RT kernel
549-
* in which irq work is invoked in a per-CPU RT thread.
550-
* It is also possible for kernel with
551-
* arch_irq_work_has_interrupt() being false and irq
552-
* work is invoked in timer interrupt. So waiting for
553-
* the completion of irq work to ease the handling of
554-
* concurrency.
555-
*/
554+
WRITE_ONCE(c->draining, true);
556555
irq_work_sync(&c->refill_work);
557556
drain_mem_cache(c);
558557
rcu_in_progress += atomic_read(&c->call_rcu_ttrace_in_progress);
@@ -568,6 +567,7 @@ void bpf_mem_alloc_destroy(struct bpf_mem_alloc *ma)
568567
cc = per_cpu_ptr(ma->caches, cpu);
569568
for (i = 0; i < NUM_CACHES; i++) {
570569
c = &cc->cache[i];
570+
WRITE_ONCE(c->draining, true);
571571
irq_work_sync(&c->refill_work);
572572
drain_mem_cache(c);
573573
rcu_in_progress += atomic_read(&c->call_rcu_ttrace_in_progress);

0 commit comments

Comments
 (0)