Skip to content

Commit

Permalink
pkt_sched: Fix queue quiescence testing in dev_deactivate().
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David S. Miller committed Aug 13, 2008
1 parent 26b284d commit b9a3b11
Showing 1 changed file with 6 additions and 5 deletions.
11 changes: 6 additions & 5 deletions net/sched/sch_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -658,13 +658,14 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock)
int val;

dev_queue = netdev_get_tx_queue(dev, i);
q = dev_queue->qdisc;
q = dev_queue->qdisc_sleeping;
root_lock = qdisc_lock(q);

if (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)
spin_unlock_bh(root_lock);
Expand All @@ -689,14 +690,14 @@ void dev_deactivate(struct net_device *dev)

/* Wait for outstanding qdisc_run calls. */
do {
while (some_qdisc_is_running(dev, 0))
while (some_qdisc_is_busy(dev, 0))
yield();

/*
* Double-check inside queue lock to ensure that all effects
* 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
Expand Down

0 comments on commit b9a3b11

Please sign in to comment.