Hi, On 6/28/2023 8:56 AM, Alexei Starovoitov wrote: > On 6/25/23 4:15 AM, Hou Tao wrote: >> Hi, >> >> On 6/24/2023 11:13 AM, Alexei Starovoitov wrote: >>> From: Alexei Starovoitov <ast@xxxxxxxxxx> >>> >>> Introduce bpf_mem_[cache_]free_rcu() similar to kfree_rcu(). >>> Unlike bpf_mem_[cache_]free() that links objects for immediate reuse >>> into >>> per-cpu free list the _rcu() flavor waits for RCU grace period and >>> then moves >>> objects into free_by_rcu_ttrace list where they are waiting for RCU >>> task trace grace period to be freed into slab. >> SNIP >>> static void free_mem_alloc_no_barrier(struct bpf_mem_alloc *ma) >>> @@ -498,8 +566,8 @@ static void free_mem_alloc_no_barrier(struct >>> bpf_mem_alloc *ma) >>> static void free_mem_alloc(struct bpf_mem_alloc *ma) >>> { >>> - /* waiting_for_gp_ttrace lists was drained, but __free_rcu might >>> - * still execute. Wait for it now before we freeing percpu caches. >>> + /* waiting_for_gp[_ttrace] lists were drained, but RCU callbacks >>> + * might still execute. Wait for them. >>> * >>> * rcu_barrier_tasks_trace() doesn't imply >>> synchronize_rcu_tasks_trace(), >>> * but rcu_barrier_tasks_trace() and rcu_barrier() below are >>> only used >> I think an extra rcu_barrier() before rcu_barrier_tasks_trace() is still >> needed here, otherwise free_mem_alloc will not wait for inflight >> __free_by_rcu() and there will oops in rcu_do_batch(). > > Agree. I got confused by rcu_trace_implies_rcu_gp(). > rcu_barrier() is necessary. > > re: draining. > I'll switch to do if (draing) free_all; else call_rcu; scheme > to address potential memory leak though I wasn't able to repro it. For v2, it was also hard for me to reproduce the leak problem. But after I injected some delay by using udelay() in __free_by_rcu/__free_rcu() after reading c->draining, it was relatively easy to reproduce the problems.