diff options
author | David S. Miller <davem@davemloft.net> | 2008-08-13 18:18:38 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-08-13 18:18:38 -0400 |
commit | b9a3b1102bc80b4044224494100f67de132d5448 (patch) | |
tree | 26d693207ad5c5e9ea79a2b21de48b1e409f628e /net/sched | |
parent | 26b284de54a5ca3dfbe2fd9a51ac1923e80085a2 (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')
-rw-r--r-- | net/sched/sch_generic.c | 11 |
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 | ||
650 | static bool some_qdisc_is_running(struct net_device *dev, int lock) | 650 | static 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 |