Commit 4335cd2d authored by David S. Miller's avatar David S. Miller

pkt_sched: Simplify dev_deactivate() polling loop.

The condition under which the previous qdisc has no more references
after we've attached &noop_qdisc is that both RUNNING and SCHED
are both seen clear while holding the root lock.

So just make specifically that check in the polling loop, instead
of this overly complex "check without then check with lock held"
sequence.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent def82a1d
...@@ -653,7 +653,7 @@ static void dev_deactivate_queue(struct net_device *dev, ...@@ -653,7 +653,7 @@ static void dev_deactivate_queue(struct net_device *dev,
} }
} }
static bool some_qdisc_is_busy(struct net_device *dev, int lock) static bool some_qdisc_is_busy(struct net_device *dev)
{ {
unsigned int i; unsigned int i;
...@@ -667,13 +667,11 @@ static bool some_qdisc_is_busy(struct net_device *dev, int lock) ...@@ -667,13 +667,11 @@ static bool some_qdisc_is_busy(struct net_device *dev, int lock)
q = dev_queue->qdisc_sleeping; q = dev_queue->qdisc_sleeping;
root_lock = qdisc_lock(q); root_lock = qdisc_lock(q);
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)); test_bit(__QDISC_STATE_SCHED, &q->state));
if (lock)
spin_unlock_bh(root_lock); spin_unlock_bh(root_lock);
if (val) if (val)
...@@ -684,8 +682,6 @@ static bool some_qdisc_is_busy(struct net_device *dev, int lock) ...@@ -684,8 +682,6 @@ static bool some_qdisc_is_busy(struct net_device *dev, int lock)
void dev_deactivate(struct net_device *dev) void dev_deactivate(struct net_device *dev)
{ {
bool running;
netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc); netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc);
dev_deactivate_queue(dev, &dev->rx_queue, &noop_qdisc); dev_deactivate_queue(dev, &dev->rx_queue, &noop_qdisc);
...@@ -695,25 +691,8 @@ void dev_deactivate(struct net_device *dev) ...@@ -695,25 +691,8 @@ void dev_deactivate(struct net_device *dev)
synchronize_rcu(); synchronize_rcu();
/* Wait for outstanding qdisc_run calls. */ /* Wait for outstanding qdisc_run calls. */
do { while (some_qdisc_is_busy(dev))
while (some_qdisc_is_busy(dev, 0))
yield(); yield();
/*
* Double-check inside queue lock to ensure that all effects
* of the queue run are visible when we return.
*/
running = some_qdisc_is_busy(dev, 1);
/*
* The running flag should never be set at this point because
* we've already set dev->qdisc to noop_qdisc *inside* the same
* pair of spin locks. That is, if any qdisc_run starts after
* our initial test it should see the noop_qdisc and then
* clear the RUNNING bit before dropping the queue lock. So
* if it is set here then we've found a bug.
*/
} while (WARN_ON_ONCE(running));
} }
static void dev_init_scheduler_queue(struct net_device *dev, static void dev_init_scheduler_queue(struct net_device *dev,
......
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