aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_generic.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-08-13 18:18:38 -0400
committerDavid S. Miller <davem@davemloft.net>2008-08-13 18:18:38 -0400
commitb9a3b1102bc80b4044224494100f67de132d5448 (patch)
tree26d693207ad5c5e9ea79a2b21de48b1e409f628e /net/sched/sch_generic.c
parent26b284de54a5ca3dfbe2fd9a51ac1923e80085a2 (diff)
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>
Diffstat (limited to 'net/sched/sch_generic.c')
-rw-r--r--net/sched/sch_generic.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 7cf83b37459d..468574682caa 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -647,7 +647,7 @@ static void dev_deactivate_queue(struct net_device *dev,
647 } 647 }
648} 648}
649 649
650static bool some_qdisc_is_running(struct net_device *dev, int lock) 650static bool some_qdisc_is_busy(struct net_device *dev, int lock)
651{ 651{
652 unsigned int i; 652 unsigned int i;
653 653
@@ -658,13 +658,14 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock)
658 int val; 658 int val;
659 659
660 dev_queue = netdev_get_tx_queue(dev, i); 660 dev_queue = netdev_get_tx_queue(dev, i);
661 q = dev_queue->qdisc; 661 q = dev_queue->qdisc_sleeping;
662 root_lock = qdisc_lock(q); 662 root_lock = qdisc_lock(q);
663 663
664 if (lock) 664 if (lock)
665 spin_lock_bh(root_lock); 665 spin_lock_bh(root_lock);
666 666
667 val = test_bit(__QDISC_STATE_RUNNING, &q->state); 667 val = (test_bit(__QDISC_STATE_RUNNING, &q->state) ||
668 test_bit(__QDISC_STATE_SCHED, &q->state));
668 669
669 if (lock) 670 if (lock)
670 spin_unlock_bh(root_lock); 671 spin_unlock_bh(root_lock);
@@ -689,14 +690,14 @@ void dev_deactivate(struct net_device *dev)
689 690
690 /* Wait for outstanding qdisc_run calls. */ 691 /* Wait for outstanding qdisc_run calls. */
691 do { 692 do {
692 while (some_qdisc_is_running(dev, 0)) 693 while (some_qdisc_is_busy(dev, 0))
693 yield(); 694 yield();
694 695
695 /* 696 /*
696 * Double-check inside queue lock to ensure that all effects 697 * Double-check inside queue lock to ensure that all effects
697 * of the queue run are visible when we return. 698 * of the queue run are visible when we return.
698 */ 699 */
699 running = some_qdisc_is_running(dev, 1); 700 running = some_qdisc_is_busy(dev, 1);
700 701
701 /* 702 /*
702 * The running flag should never be set at this point because 703 * The running flag should never be set at this point because