aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_generic.c')
-rw-r--r--net/sched/sch_generic.c72
1 files changed, 21 insertions, 51 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 7cf83b37459..5f0ade7806a 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -518,15 +518,17 @@ void qdisc_reset(struct Qdisc *qdisc)
518} 518}
519EXPORT_SYMBOL(qdisc_reset); 519EXPORT_SYMBOL(qdisc_reset);
520 520
521/* this is the rcu callback function to clean up a qdisc when there 521void qdisc_destroy(struct Qdisc *qdisc)
522 * are no further references to it */
523
524static void __qdisc_destroy(struct rcu_head *head)
525{ 522{
526 struct Qdisc *qdisc = container_of(head, struct Qdisc, q_rcu);
527 const struct Qdisc_ops *ops = qdisc->ops; 523 const struct Qdisc_ops *ops = qdisc->ops;
528 524
525 if (qdisc->flags & TCQ_F_BUILTIN ||
526 !atomic_dec_and_test(&qdisc->refcnt))
527 return;
528
529#ifdef CONFIG_NET_SCHED 529#ifdef CONFIG_NET_SCHED
530 qdisc_list_del(qdisc);
531
530 qdisc_put_stab(qdisc->stab); 532 qdisc_put_stab(qdisc->stab);
531#endif 533#endif
532 gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est); 534 gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
@@ -542,20 +544,6 @@ static void __qdisc_destroy(struct rcu_head *head)
542 544
543 kfree((char *) qdisc - qdisc->padded); 545 kfree((char *) qdisc - qdisc->padded);
544} 546}
545
546/* Under qdisc_lock(qdisc) and BH! */
547
548void qdisc_destroy(struct Qdisc *qdisc)
549{
550 if (qdisc->flags & TCQ_F_BUILTIN ||
551 !atomic_dec_and_test(&qdisc->refcnt))
552 return;
553
554 if (qdisc->parent)
555 list_del(&qdisc->list);
556
557 call_rcu(&qdisc->q_rcu, __qdisc_destroy);
558}
559EXPORT_SYMBOL(qdisc_destroy); 547EXPORT_SYMBOL(qdisc_destroy);
560 548
561static bool dev_all_qdisc_sleeping_noop(struct net_device *dev) 549static bool dev_all_qdisc_sleeping_noop(struct net_device *dev)
@@ -597,6 +585,9 @@ static void transition_one_qdisc(struct net_device *dev,
597 struct Qdisc *new_qdisc = dev_queue->qdisc_sleeping; 585 struct Qdisc *new_qdisc = dev_queue->qdisc_sleeping;
598 int *need_watchdog_p = _need_watchdog; 586 int *need_watchdog_p = _need_watchdog;
599 587
588 if (!(new_qdisc->flags & TCQ_F_BUILTIN))
589 clear_bit(__QDISC_STATE_DEACTIVATED, &new_qdisc->state);
590
600 rcu_assign_pointer(dev_queue->qdisc, new_qdisc); 591 rcu_assign_pointer(dev_queue->qdisc, new_qdisc);
601 if (need_watchdog_p && new_qdisc != &noqueue_qdisc) 592 if (need_watchdog_p && new_qdisc != &noqueue_qdisc)
602 *need_watchdog_p = 1; 593 *need_watchdog_p = 1;
@@ -640,6 +631,9 @@ static void dev_deactivate_queue(struct net_device *dev,
640 if (qdisc) { 631 if (qdisc) {
641 spin_lock_bh(qdisc_lock(qdisc)); 632 spin_lock_bh(qdisc_lock(qdisc));
642 633
634 if (!(qdisc->flags & TCQ_F_BUILTIN))
635 set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state);
636
643 dev_queue->qdisc = qdisc_default; 637 dev_queue->qdisc = qdisc_default;
644 qdisc_reset(qdisc); 638 qdisc_reset(qdisc);
645 639
@@ -647,7 +641,7 @@ static void dev_deactivate_queue(struct net_device *dev,
647 } 641 }
648} 642}
649 643
650static bool some_qdisc_is_running(struct net_device *dev, int lock) 644static bool some_qdisc_is_busy(struct net_device *dev)
651{ 645{
652 unsigned int i; 646 unsigned int i;
653 647
@@ -658,16 +652,15 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock)
658 int val; 652 int val;
659 653
660 dev_queue = netdev_get_tx_queue(dev, i); 654 dev_queue = netdev_get_tx_queue(dev, i);
661 q = dev_queue->qdisc; 655 q = dev_queue->qdisc_sleeping;
662 root_lock = qdisc_lock(q); 656 root_lock = qdisc_lock(q);
663 657
664 if (lock) 658 spin_lock_bh(root_lock);
665 spin_lock_bh(root_lock);
666 659
667 val = test_bit(__QDISC_STATE_RUNNING, &q->state); 660 val = (test_bit(__QDISC_STATE_RUNNING, &q->state) ||
661 test_bit(__QDISC_STATE_SCHED, &q->state));
668 662
669 if (lock) 663 spin_unlock_bh(root_lock);
670 spin_unlock_bh(root_lock);
671 664
672 if (val) 665 if (val)
673 return true; 666 return true;
@@ -677,8 +670,6 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock)
677 670
678void dev_deactivate(struct net_device *dev) 671void dev_deactivate(struct net_device *dev)
679{ 672{
680 bool running;
681
682 netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc); 673 netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc);
683 dev_deactivate_queue(dev, &dev->rx_queue, &noop_qdisc); 674 dev_deactivate_queue(dev, &dev->rx_queue, &noop_qdisc);
684 675
@@ -688,25 +679,8 @@ void dev_deactivate(struct net_device *dev)
688 synchronize_rcu(); 679 synchronize_rcu();
689 680
690 /* Wait for outstanding qdisc_run calls. */ 681 /* Wait for outstanding qdisc_run calls. */
691 do { 682 while (some_qdisc_is_busy(dev))
692 while (some_qdisc_is_running(dev, 0)) 683 yield();
693 yield();
694
695 /*
696 * Double-check inside queue lock to ensure that all effects
697 * of the queue run are visible when we return.
698 */
699 running = some_qdisc_is_running(dev, 1);
700
701 /*
702 * The running flag should never be set at this point because
703 * we've already set dev->qdisc to noop_qdisc *inside* the same
704 * pair of spin locks. That is, if any qdisc_run starts after
705 * our initial test it should see the noop_qdisc and then
706 * clear the RUNNING bit before dropping the queue lock. So
707 * if it is set here then we've found a bug.
708 */
709 } while (WARN_ON_ONCE(running));
710} 684}
711 685
712static void dev_init_scheduler_queue(struct net_device *dev, 686static void dev_init_scheduler_queue(struct net_device *dev,
@@ -735,14 +709,10 @@ static void shutdown_scheduler_queue(struct net_device *dev,
735 struct Qdisc *qdisc_default = _qdisc_default; 709 struct Qdisc *qdisc_default = _qdisc_default;
736 710
737 if (qdisc) { 711 if (qdisc) {
738 spinlock_t *root_lock = qdisc_lock(qdisc);
739
740 dev_queue->qdisc = qdisc_default; 712 dev_queue->qdisc = qdisc_default;
741 dev_queue->qdisc_sleeping = qdisc_default; 713 dev_queue->qdisc_sleeping = qdisc_default;
742 714
743 spin_lock_bh(root_lock);
744 qdisc_destroy(qdisc); 715 qdisc_destroy(qdisc);
745 spin_unlock_bh(root_lock);
746 } 716 }
747} 717}
748 718