From: John Fastabend <john.fastabend@gmail.com> Date: 2017-12-20 20:09:35
RCU grace period is needed for lockless qdiscs added in the commit
c5ad119fb6c09 ("net: sched: pfifo_fast use skb_array").
It is needed now that qdiscs may be lockless otherwise we risk
free'ing a qdisc that is still in use from datapath. Additionally,
push list cleanup into RCU callback. Otherwise we risk the datapath
adding skbs during removal.
Fixes: c5ad119fb6c09 ("net: sched: pfifo_fast use skb_array")
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
include/net/sch_generic.h | 1 +
net/sched/sch_generic.c | 50 ++++++++++++++++++++++++---------------------
2 files changed, 28 insertions(+), 23 deletions(-)
@@ -873,31 +873,15 @@ void qdisc_reset(struct Qdisc *qdisc)}EXPORT_SYMBOL(qdisc_reset);-staticvoidqdisc_free(structQdisc*qdisc)+staticvoidqdisc_rcu_free(structrcu_head*head){-if(qdisc_is_percpu_stats(qdisc)){-free_percpu(qdisc->cpu_bstats);-free_percpu(qdisc->cpu_qstats);-}--kfree((char*)qdisc-qdisc->padded);-}--voidqdisc_destroy(structQdisc*qdisc)-{-conststructQdisc_ops*ops=qdisc->ops;+structQdisc*qdisc=container_of(head,structQdisc,rcu_head);+conststructQdisc_ops*ops=qdisc->ops;structsk_buff*skb,*tmp;-if(qdisc->flags&TCQ_F_BUILTIN||-!refcount_dec_and_test(&qdisc->refcnt))-return;--#ifdef CONFIG_NET_SCHED-qdisc_hash_del(qdisc);--qdisc_put_stab(rtnl_dereference(qdisc->stab));-#endif-gen_kill_estimator(&qdisc->rate_est);+/* At this point no outstanding references to this Qdisc should+*existinthedatapathsoitssafetocleanupskblists,etc.+*/if(ops->reset)ops->reset(qdisc);if(ops->destroy)
From: Jakub Kicinski <hidden> Date: 2017-12-20 22:00:11
On Wed, 20 Dec 2017 12:09:19 -0800, John Fastabend wrote:
RCU grace period is needed for lockless qdiscs added in the commit
c5ad119fb6c09 ("net: sched: pfifo_fast use skb_array").
It is needed now that qdiscs may be lockless otherwise we risk
free'ing a qdisc that is still in use from datapath. Additionally,
push list cleanup into RCU callback. Otherwise we risk the datapath
adding skbs during removal.
Fixes: c5ad119fb6c09 ("net: sched: pfifo_fast use skb_array")
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Seems like this revert may be too heavy handed:
# ./tools/testing/selftests/bpf/test_offload.py --log /tmp/log
Test destruction of generic XDP...
Test TC non-offloaded...
Test TC non-offloaded isn't getting bound...
Test TC offloads are off by default...
Test TC offload by default...
Test TC cBPF bytcode tries offload by default...
Test TC cBPF unbound bytecode doesn't offload...
Test TC offloads work...
FAIL: TC filter did not load with TC offloads enabled
And it's triggering:
WARNING: CPU: 15 PID: 1853 at ../drivers/net/netdevsim/bpf.c:372 nsim_bpf_uninit+0x2e/0x41 [netdevsim]
Which is:
368 void nsim_bpf_uninit(struct netdevsim *ns)
369 {
370 WARN_ON(!list_empty(&ns->bpf_bound_progs));
371 WARN_ON(ns->xdp_prog);
quoted
372 WARN_ON(ns->bpf_offloaded);
373 }
(Meaning the offload was not stopped by the stack before ndo_uninit.)
From: Cong Wang <hidden> Date: 2017-12-20 22:42:04
On Wed, Dec 20, 2017 at 12:09 PM, John Fastabend
[off-list ref] wrote:
RCU grace period is needed for lockless qdiscs added in the commit
c5ad119fb6c09 ("net: sched: pfifo_fast use skb_array").
It is needed now that qdiscs may be lockless otherwise we risk
free'ing a qdisc that is still in use from datapath. Additionally,
push list cleanup into RCU callback. Otherwise we risk the datapath
adding skbs during removal.
What about qdisc_graft() -> dev_deactivate() -> synchronize_net() ?
It doesn't work with your "lockless" patches?
From: John Fastabend <john.fastabend@gmail.com> Date: 2017-12-20 23:05:28
On 12/20/2017 02:41 PM, Cong Wang wrote:
On Wed, Dec 20, 2017 at 12:09 PM, John Fastabend
[off-list ref] wrote:
quoted
RCU grace period is needed for lockless qdiscs added in the commit
c5ad119fb6c09 ("net: sched: pfifo_fast use skb_array").
It is needed now that qdiscs may be lockless otherwise we risk
free'ing a qdisc that is still in use from datapath. Additionally,
push list cleanup into RCU callback. Otherwise we risk the datapath
adding skbs during removal.
What about qdisc_graft() -> dev_deactivate() -> synchronize_net() ?
It doesn't work with your "lockless" patches?
Well this is only in the 'parent == NULL' case otherwise we call
cops->graft(). Most sch_* seem to use qdisc_replace and this uses
sch_tree_lock().
The only converted qdisc mq and mqprio at this point don't care
though and do their own dev_deactivate/activate. So its not fixing
anything in the above mentioned commit.
I still think it will need to be done eventually. If it resolves
the miniq case it seems like a good idea. Although per Jakub's comment
perhaps I pulled too much into the RCU handler.
From: Cong Wang <hidden> Date: 2017-12-20 23:24:10
On Wed, Dec 20, 2017 at 3:05 PM, John Fastabend
[off-list ref] wrote:
On 12/20/2017 02:41 PM, Cong Wang wrote:
quoted
On Wed, Dec 20, 2017 at 12:09 PM, John Fastabend
[off-list ref] wrote:
quoted
RCU grace period is needed for lockless qdiscs added in the commit
c5ad119fb6c09 ("net: sched: pfifo_fast use skb_array").
It is needed now that qdiscs may be lockless otherwise we risk
free'ing a qdisc that is still in use from datapath. Additionally,
push list cleanup into RCU callback. Otherwise we risk the datapath
adding skbs during removal.
What about qdisc_graft() -> dev_deactivate() -> synchronize_net() ?
It doesn't work with your "lockless" patches?
Well this is only in the 'parent == NULL' case otherwise we call
cops->graft(). Most sch_* seem to use qdisc_replace and this uses
sch_tree_lock().
The only converted qdisc mq and mqprio at this point don't care
though and do their own dev_deactivate/activate. So its not fixing
anything in the above mentioned commit.
Sure, removing a class does not impact the whole device,
but removing the root qdisc does.
After your "lockless", skb_array_consume_bh() is called in
pfifo_fast_reset() and ptr_ring_cleanup() is called in
pfifo_fast_destroy(), assuming skb_array is not buggy, what race
do we have here with datapath?
I still think it will need to be done eventually. If it resolves
the miniq case it seems like a good idea. Although per Jakub's comment
perhaps I pulled too much into the RCU handler.
The case Jakub reported is a RCU callback missing a rcu
barrier. I don't understand why you keep believing it is RCU
readers on datapath.
Not even to mention ingress is not affected by your "lockless"
thing.
From: John Fastabend <john.fastabend@gmail.com> Date: 2017-12-20 23:34:21
On 12/20/2017 03:23 PM, Cong Wang wrote:
On Wed, Dec 20, 2017 at 3:05 PM, John Fastabend
[off-list ref] wrote:
quoted
On 12/20/2017 02:41 PM, Cong Wang wrote:
quoted
On Wed, Dec 20, 2017 at 12:09 PM, John Fastabend
[off-list ref] wrote:
quoted
RCU grace period is needed for lockless qdiscs added in the commit
c5ad119fb6c09 ("net: sched: pfifo_fast use skb_array").
It is needed now that qdiscs may be lockless otherwise we risk
free'ing a qdisc that is still in use from datapath. Additionally,
push list cleanup into RCU callback. Otherwise we risk the datapath
adding skbs during removal.
What about qdisc_graft() -> dev_deactivate() -> synchronize_net() ?
It doesn't work with your "lockless" patches?
Well this is only in the 'parent == NULL' case otherwise we call
cops->graft(). Most sch_* seem to use qdisc_replace and this uses
sch_tree_lock().
The only converted qdisc mq and mqprio at this point don't care
though and do their own dev_deactivate/activate. So its not fixing
anything in the above mentioned commit.
Sure, removing a class does not impact the whole device,
but removing the root qdisc does.
After your "lockless", skb_array_consume_bh() is called in
pfifo_fast_reset() and ptr_ring_cleanup() is called in
pfifo_fast_destroy(), assuming skb_array is not buggy, what race
do we have here with datapath?
None at the moment.
quoted
I still think it will need to be done eventually. If it resolves
the miniq case it seems like a good idea. Although per Jakub's comment
perhaps I pulled too much into the RCU handler.
The case Jakub reported is a RCU callback missing a rcu
barrier. I don't understand why you keep believing it is RCU
readers on datapath.>
Not even to mention ingress is not affected by your "lockless"
thing.
I was thinking about the case where we want a lockless qdisc
with classes. Doing the qdisc destroy after a grace period would
solve this. Also we could start to cleanup a lot of the locking
and extra bits around 'running' qdisc and such by doing a clean
xchg on the qdisc layer. It seems that a dev_activate/deactivate
just to install a new qdisc is not needed.
Anyways future work. However if it resolves the miniq issue, as
Jiri indicated, seems like a clean fix. Although Jakub's issue
with the patch would need to be addressed. Seems he gets a WARN_ON
if the offload is not disabled but the device is unitialized.
.John
From: John Fastabend <john.fastabend@gmail.com> Date: 2017-12-20 23:41:04
On 12/20/2017 01:59 PM, Jakub Kicinski wrote:
On Wed, 20 Dec 2017 12:09:19 -0800, John Fastabend wrote:
quoted
RCU grace period is needed for lockless qdiscs added in the commit
c5ad119fb6c09 ("net: sched: pfifo_fast use skb_array").
It is needed now that qdiscs may be lockless otherwise we risk
free'ing a qdisc that is still in use from datapath. Additionally,
push list cleanup into RCU callback. Otherwise we risk the datapath
adding skbs during removal.
Fixes: c5ad119fb6c09 ("net: sched: pfifo_fast use skb_array")
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Seems like this revert may be too heavy handed:
# ./tools/testing/selftests/bpf/test_offload.py --log /tmp/log
Test destruction of generic XDP...
Test TC non-offloaded...
Test TC non-offloaded isn't getting bound...
Test TC offloads are off by default...
Test TC offload by default...
Test TC cBPF bytcode tries offload by default...
Test TC cBPF unbound bytecode doesn't offload...
Test TC offloads work...
FAIL: TC filter did not load with TC offloads enabled
And it's triggering:
WARNING: CPU: 15 PID: 1853 at ../drivers/net/netdevsim/bpf.c:372 nsim_bpf_uninit+0x2e/0x41 [netdevsim]
Which is:
368 void nsim_bpf_uninit(struct netdevsim *ns)
369 {
370 WARN_ON(!list_empty(&ns->bpf_bound_progs));
371 WARN_ON(ns->xdp_prog);
quoted
quoted
372 WARN_ON(ns->bpf_offloaded);
373 }
(Meaning the offload was not stopped by the stack before ndo_uninit.)
Dang. So offload code depends on destroy being called on a qdisc
to in turn destroy the filters and unbind any offloads.
I was hoping I could get away with tearing down live qdiscs without
too much work. Looks like not.
Note the fixes tag was bogus nothing is actually broken in current
code until a lockless qdisc with classes shows up.
.John
Thu, Dec 21, 2017 at 12:34:05AM CET, john.fastabend@gmail.com wrote:
On 12/20/2017 03:23 PM, Cong Wang wrote:
quoted
On Wed, Dec 20, 2017 at 3:05 PM, John Fastabend
[off-list ref] wrote:
quoted
On 12/20/2017 02:41 PM, Cong Wang wrote:
quoted
On Wed, Dec 20, 2017 at 12:09 PM, John Fastabend
[off-list ref] wrote:
quoted
RCU grace period is needed for lockless qdiscs added in the commit
c5ad119fb6c09 ("net: sched: pfifo_fast use skb_array").
It is needed now that qdiscs may be lockless otherwise we risk
free'ing a qdisc that is still in use from datapath. Additionally,
push list cleanup into RCU callback. Otherwise we risk the datapath
adding skbs during removal.
What about qdisc_graft() -> dev_deactivate() -> synchronize_net() ?
It doesn't work with your "lockless" patches?
Well this is only in the 'parent == NULL' case otherwise we call
cops->graft(). Most sch_* seem to use qdisc_replace and this uses
sch_tree_lock().
The only converted qdisc mq and mqprio at this point don't care
though and do their own dev_deactivate/activate. So its not fixing
anything in the above mentioned commit.
Sure, removing a class does not impact the whole device,
but removing the root qdisc does.
After your "lockless", skb_array_consume_bh() is called in
pfifo_fast_reset() and ptr_ring_cleanup() is called in
pfifo_fast_destroy(), assuming skb_array is not buggy, what race
do we have here with datapath?
None at the moment.
quoted
quoted
I still think it will need to be done eventually. If it resolves
the miniq case it seems like a good idea. Although per Jakub's comment
perhaps I pulled too much into the RCU handler.
The case Jakub reported is a RCU callback missing a rcu
barrier. I don't understand why you keep believing it is RCU
readers on datapath.>
Not even to mention ingress is not affected by your "lockless"
thing.
I was thinking about the case where we want a lockless qdisc
with classes. Doing the qdisc destroy after a grace period would
solve this. Also we could start to cleanup a lot of the locking
and extra bits around 'running' qdisc and such by doing a clean
xchg on the qdisc layer. It seems that a dev_activate/deactivate
just to install a new qdisc is not needed.
Anyways future work. However if it resolves the miniq issue, as
Jiri indicated, seems like a clean fix. Although Jakub's issue
with the patch would need to be addressed. Seems he gets a WARN_ON
if the offload is not disabled but the device is unitialized.
Why just moving qdisc_free to rcu is not enough? It would resolve this
issue and also avoid using synchronize net. Something like:
From: Cong Wang <hidden> Date: 2017-12-21 21:00:17
On Thu, Dec 21, 2017 at 12:39 AM, Jiri Pirko [off-list ref] wrote:
Why just moving qdisc_free to rcu is not enough? It would resolve this
issue and also avoid using synchronize net. Something like:
If you mean Jakub's issue, apparently not:
https://www.kernel.org/pub/linux/kernel/people/paulmck/Answers/RCU/RCUCBordering.html
Jiri, you have to use a rcu barrier to wait for a rcu callback, not
queuing another rcu callback, the ordering is simply NOT guaranteed.
What's more importantly, you already have one rcu barrier in the
same function. Why keep believing you don't need it?
Sure. But the ordering does not matter in this case. You just need to
make sure the reader does not see freed qdisc struct.
What's more importantly, you already have one rcu barrier in the
same function. Why keep believing you don't need it?
The rcu barrier is there for a different reason. It is there to avoid
reuse of old miniq that readers still might see in scenario
miniq1
miniq2
miniq1 again