mirror of https://gitee.com/openkylin/linux.git
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
26b284de54
commit
b9a3b1102b
|
@ -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)
|
||||||
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)
|
||||||
|
|
||||||
/* 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
|
||||||
|
|
Loading…
Reference in New Issue