Commit b9a3b110 authored by David S. Miller's avatar David S. Miller

pkt_sched: Fix queue quiescence testing in dev_deactivate().

Based upon discussions with Jarek P. and Herbert Xu.

First, we're testing the wrong qdisc.  We just reset the device
queue qdiscs to &noop_qdisc and checking it's state is completely
pointless here.

We want to wait until the previous qdisc that was sitting at
the ->qdisc pointer is not busy any more.  And that would be
->qdisc_sleeping.

Because of how we propagate the samples qdisc pointer down into
qdisc_run and friends via per-cpu ->output_queue and netif_schedule,
we have to wait also for the __QDISC_STATE_SCHED bit to clear as
well.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 26b284de
...@@ -647,7 +647,7 @@ static void dev_deactivate_queue(struct net_device *dev, ...@@ -647,7 +647,7 @@ static void dev_deactivate_queue(struct net_device *dev,
} }
} }
static bool some_qdisc_is_running(struct net_device *dev, int lock) static bool some_qdisc_is_busy(struct net_device *dev, int lock)
{ {
unsigned int i; unsigned int i;
...@@ -658,13 +658,14 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock) ...@@ -658,13 +658,14 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock)
int val; int val;
dev_queue = netdev_get_tx_queue(dev, i); dev_queue = netdev_get_tx_queue(dev, i);
q = dev_queue->qdisc; q = dev_queue->qdisc_sleeping;
root_lock = qdisc_lock(q); root_lock = qdisc_lock(q);
if (lock) if (lock)
spin_lock_bh(root_lock); spin_lock_bh(root_lock);
val = test_bit(__QDISC_STATE_RUNNING, &q->state); val = (test_bit(__QDISC_STATE_RUNNING, &q->state) ||
test_bit(__QDISC_STATE_SCHED, &q->state));
if (lock) if (lock)
spin_unlock_bh(root_lock); spin_unlock_bh(root_lock);
...@@ -689,14 +690,14 @@ void dev_deactivate(struct net_device *dev) ...@@ -689,14 +690,14 @@ void dev_deactivate(struct net_device *dev)
/* Wait for outstanding qdisc_run calls. */ /* Wait for outstanding qdisc_run calls. */
do { do {
while (some_qdisc_is_running(dev, 0)) while (some_qdisc_is_busy(dev, 0))
yield(); yield();
/* /*
* Double-check inside queue lock to ensure that all effects * Double-check inside queue lock to ensure that all effects
* of the queue run are visible when we return. * of the queue run are visible when we return.
*/ */
running = some_qdisc_is_running(dev, 1); running = some_qdisc_is_busy(dev, 1);
/* /*
* The running flag should never be set at this point because * The running flag should never be set at this point because
......
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