aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-08-02 23:02:43 -0400
committerDavid S. Miller <davem@davemloft.net>2008-08-02 23:02:43 -0400
commit5fb662297b8a4bdadd60371c34b760efca948ebc (patch)
treeef1def70cfa440ab3d367f6f67d466227ffdf0ef
parent82f97b8d3cb3982ec97e081598c671fab2c321b0 (diff)
pkt_sched: Use qdisc_lock() on already sampled root qdisc.
Based upon a bug report by Jeff Kirsher. Don't use qdisc_root_lock() in these cases as the root qdisc could have been changed, and we'd thus lock the wrong object. Tested by Emil S Tantilov who confirms that this seems to fix the problem. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/core/dev.c4
-rw-r--r--net/sched/sch_generic.c12
2 files changed, 8 insertions, 8 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 69320a56a084..da7acacf02b5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1796,7 +1796,7 @@ gso:
1796 skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS); 1796 skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS);
1797#endif 1797#endif
1798 if (q->enqueue) { 1798 if (q->enqueue) {
1799 spinlock_t *root_lock = qdisc_root_lock(q); 1799 spinlock_t *root_lock = qdisc_lock(q);
1800 1800
1801 spin_lock(root_lock); 1801 spin_lock(root_lock);
1802 1802
@@ -1995,7 +1995,7 @@ static void net_tx_action(struct softirq_action *h)
1995 smp_mb__before_clear_bit(); 1995 smp_mb__before_clear_bit();
1996 clear_bit(__QDISC_STATE_SCHED, &q->state); 1996 clear_bit(__QDISC_STATE_SCHED, &q->state);
1997 1997
1998 root_lock = qdisc_root_lock(q); 1998 root_lock = qdisc_lock(q);
1999 if (spin_trylock(root_lock)) { 1999 if (spin_trylock(root_lock)) {
2000 qdisc_run(q); 2000 qdisc_run(q);
2001 spin_unlock(root_lock); 2001 spin_unlock(root_lock);
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 9c9cd4d94890..7cf83b37459d 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -29,7 +29,7 @@
29/* Main transmission queue. */ 29/* Main transmission queue. */
30 30
31/* Modifications to data participating in scheduling must be protected with 31/* Modifications to data participating in scheduling must be protected with
32 * qdisc_root_lock(qdisc) spinlock. 32 * qdisc_lock(qdisc) spinlock.
33 * 33 *
34 * The idea is the following: 34 * The idea is the following:
35 * - enqueue, dequeue are serialized via qdisc root lock 35 * - enqueue, dequeue are serialized via qdisc root lock
@@ -126,7 +126,7 @@ static inline int qdisc_restart(struct Qdisc *q)
126 if (unlikely((skb = dequeue_skb(q)) == NULL)) 126 if (unlikely((skb = dequeue_skb(q)) == NULL))
127 return 0; 127 return 0;
128 128
129 root_lock = qdisc_root_lock(q); 129 root_lock = qdisc_lock(q);
130 130
131 /* And release qdisc */ 131 /* And release qdisc */
132 spin_unlock(root_lock); 132 spin_unlock(root_lock);
@@ -507,7 +507,7 @@ errout:
507} 507}
508EXPORT_SYMBOL(qdisc_create_dflt); 508EXPORT_SYMBOL(qdisc_create_dflt);
509 509
510/* Under qdisc_root_lock(qdisc) and BH! */ 510/* Under qdisc_lock(qdisc) and BH! */
511 511
512void qdisc_reset(struct Qdisc *qdisc) 512void qdisc_reset(struct Qdisc *qdisc)
513{ 513{
@@ -543,7 +543,7 @@ static void __qdisc_destroy(struct rcu_head *head)
543 kfree((char *) qdisc - qdisc->padded); 543 kfree((char *) qdisc - qdisc->padded);
544} 544}
545 545
546/* Under qdisc_root_lock(qdisc) and BH! */ 546/* Under qdisc_lock(qdisc) and BH! */
547 547
548void qdisc_destroy(struct Qdisc *qdisc) 548void qdisc_destroy(struct Qdisc *qdisc)
549{ 549{
@@ -659,7 +659,7 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock)
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;
662 root_lock = qdisc_root_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);
@@ -735,7 +735,7 @@ static void shutdown_scheduler_queue(struct net_device *dev,
735 struct Qdisc *qdisc_default = _qdisc_default; 735 struct Qdisc *qdisc_default = _qdisc_default;
736 736
737 if (qdisc) { 737 if (qdisc) {
738 spinlock_t *root_lock = qdisc_root_lock(qdisc); 738 spinlock_t *root_lock = qdisc_lock(qdisc);
739 739
740 dev_queue->qdisc = qdisc_default; 740 dev_queue->qdisc = qdisc_default;
741 dev_queue->qdisc_sleeping = qdisc_default; 741 dev_queue->qdisc_sleeping = qdisc_default;