diff options
author | David S. Miller | 2017-11-03 13:57:35 +0100 |
---|---|---|
committer | David S. Miller | 2017-11-03 13:57:35 +0100 |
commit | 6ee79b6ebf6613f1c5bf2be0c3dca4e51817f2ca (patch) | |
tree | 54915d3a3f2af715f1681da274e3a98f6198e71b /net/sched/sch_generic.c | |
parent | Merge branch 'hns3-ethtool-ksettings' (diff) | |
parent | net: core: introduce mini_Qdisc and eliminate usage of tp->q for clsact fastpath (diff) | |
download | kernel-qcow2-linux-6ee79b6ebf6613f1c5bf2be0c3dca4e51817f2ca.tar.gz kernel-qcow2-linux-6ee79b6ebf6613f1c5bf2be0c3dca4e51817f2ca.tar.xz kernel-qcow2-linux-6ee79b6ebf6613f1c5bf2be0c3dca4e51817f2ca.zip |
Merge branch 'net-mini_Qdisc'
Jiri Pirko says:
====================
net: core: introduce mini_Qdisc and eliminate usage of tp->q for clsact fastpath
This patchset's main patch is patch number 2. It carries the
description. Patch 1 is just a dependency.
---
v3->v4:
- rebased to be applicable on top of the current net-next
v2->v3:
- Using head change callback to replace miniq pointer every time tp head
changes. This eliminates one rcu dereference and makes the claim "without
added overhead" valid.
v1->v2:
- Use dev instead of skb->dev in sch_handle_egress as pointed out by Daniel
- Fixed synchronize_rcu_bh() in mini_qdisc_disable and commented
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/sch_generic.c')
-rw-r--r-- | net/sched/sch_generic.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index aa74aa42b5d7..3839cbbdc32b 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -1024,3 +1024,49 @@ void psched_ratecfg_precompute(struct psched_ratecfg *r, } } EXPORT_SYMBOL(psched_ratecfg_precompute); + +static void mini_qdisc_rcu_func(struct rcu_head *head) +{ +} + +void mini_qdisc_pair_swap(struct mini_Qdisc_pair *miniqp, + struct tcf_proto *tp_head) +{ + struct mini_Qdisc *miniq_old = rtnl_dereference(*miniqp->p_miniq); + struct mini_Qdisc *miniq; + + if (!tp_head) { + RCU_INIT_POINTER(*miniqp->p_miniq, NULL); + return; + } + + miniq = !miniq_old || miniq_old == &miniqp->miniq2 ? + &miniqp->miniq1 : &miniqp->miniq2; + + /* We need to make sure that readers won't see the miniq + * we are about to modify. So wait until previous call_rcu_bh callback + * is done. + */ + rcu_barrier_bh(); + miniq->filter_list = tp_head; + rcu_assign_pointer(*miniqp->p_miniq, miniq); + + if (miniq_old) + /* This is counterpart of the rcu barrier above. We need to + * block potential new user of miniq_old until all readers + * are not seeing it. + */ + call_rcu_bh(&miniq_old->rcu, mini_qdisc_rcu_func); +} +EXPORT_SYMBOL(mini_qdisc_pair_swap); + +void mini_qdisc_pair_init(struct mini_Qdisc_pair *miniqp, struct Qdisc *qdisc, + struct mini_Qdisc __rcu **p_miniq) +{ + miniqp->miniq1.cpu_bstats = qdisc->cpu_bstats; + miniqp->miniq1.cpu_qstats = qdisc->cpu_qstats; + miniqp->miniq2.cpu_bstats = qdisc->cpu_bstats; + miniqp->miniq2.cpu_qstats = qdisc->cpu_qstats; + miniqp->p_miniq = p_miniq; +} +EXPORT_SYMBOL(mini_qdisc_pair_init); |