Commit 70f50965 authored by Cong Wang's avatar Cong Wang Committed by David S. Miller

net_sched: avoid resetting active qdisc for multiple times

Except for sch_mq and sch_mqprio, each dev queue points to the
same root qdisc, so when we reset the dev queues with
netdev_for_each_tx_queue() we end up resetting the same instance
of the root qdisc for multiple times.

Avoid this by checking the __QDISC_STATE_DEACTIVATED bit in
each iteration, so for sch_mq/sch_mqprio, we still reset all
of them like before, for the rest, we only reset it once.
Reported-by: default avatarVáclav Zindulka <vaclav.zindulka@tlapnet.cz>
Tested-by: default avatarVáclav Zindulka <vaclav.zindulka@tlapnet.cz>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f5a7833e
...@@ -1128,30 +1128,39 @@ void dev_activate(struct net_device *dev) ...@@ -1128,30 +1128,39 @@ void dev_activate(struct net_device *dev)
} }
EXPORT_SYMBOL(dev_activate); EXPORT_SYMBOL(dev_activate);
static void dev_deactivate_queue(struct net_device *dev, static void qdisc_deactivate(struct Qdisc *qdisc)
struct netdev_queue *dev_queue,
void *_qdisc_default)
{ {
struct Qdisc *qdisc_default = _qdisc_default;
struct Qdisc *qdisc;
qdisc = rtnl_dereference(dev_queue->qdisc);
if (qdisc) {
bool nolock = qdisc->flags & TCQ_F_NOLOCK; bool nolock = qdisc->flags & TCQ_F_NOLOCK;
if (qdisc->flags & TCQ_F_BUILTIN)
return;
if (test_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state))
return;
if (nolock) if (nolock)
spin_lock_bh(&qdisc->seqlock); spin_lock_bh(&qdisc->seqlock);
spin_lock_bh(qdisc_lock(qdisc)); spin_lock_bh(qdisc_lock(qdisc));
if (!(qdisc->flags & TCQ_F_BUILTIN))
set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state); set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state);
rcu_assign_pointer(dev_queue->qdisc, qdisc_default);
qdisc_reset(qdisc); qdisc_reset(qdisc);
spin_unlock_bh(qdisc_lock(qdisc)); spin_unlock_bh(qdisc_lock(qdisc));
if (nolock) if (nolock)
spin_unlock_bh(&qdisc->seqlock); spin_unlock_bh(&qdisc->seqlock);
}
static void dev_deactivate_queue(struct net_device *dev,
struct netdev_queue *dev_queue,
void *_qdisc_default)
{
struct Qdisc *qdisc_default = _qdisc_default;
struct Qdisc *qdisc;
qdisc = rtnl_dereference(dev_queue->qdisc);
if (qdisc) {
qdisc_deactivate(qdisc);
rcu_assign_pointer(dev_queue->qdisc, qdisc_default);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment