diff options
author | Jakub Kicinski <jakub.kicinski@netronome.com> | 2018-11-07 17:33:39 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-11-08 16:19:48 -0800 |
commit | 0c8d13ac96070000da33f394f45e9c19638483c5 (patch) | |
tree | 4cbfc90c4d5601a3fa76b2ab46fbeb36386c5f85 /net/sched | |
parent | 9da93ece59f4a3e1544dfa2aa53e91f9e724abc6 (diff) | |
download | linux-0c8d13ac96070000da33f394f45e9c19638483c5.tar.gz linux-0c8d13ac96070000da33f394f45e9c19638483c5.tar.bz2 linux-0c8d13ac96070000da33f394f45e9c19638483c5.zip |
net: sched: red: delay destroying child qdisc on replace
Move destroying of the old child qdisc outside of the sch_tree_lock()
section. This should improve the software qdisc replace but is even
more important for offloads. Firstly calling offloads under a spin
lock is best avoided. Secondly the destroy event of existing child
would have been sent to the offload device before the replace, causing
confusion.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: John Hurley <john.hurley@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_red.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 2bf1d2fabc48..7682f7a618a1 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -193,10 +193,10 @@ static const struct nla_policy red_policy[TCA_RED_MAX + 1] = { static int red_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { + struct Qdisc *old_child = NULL, *child = NULL; struct red_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_RED_MAX + 1]; struct tc_red_qopt *ctl; - struct Qdisc *child = NULL; int err; u32 max_P; @@ -233,7 +233,7 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt, if (child) { qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, q->qdisc->qstats.backlog); - qdisc_put(q->qdisc); + old_child = q->qdisc; q->qdisc = child; } @@ -252,7 +252,11 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt, red_start_of_idle_period(&q->vars); sch_tree_unlock(sch); + red_offload(sch, true); + + if (old_child) + qdisc_put(old_child); return 0; } |