diff options
author | David S. Miller <davem@davemloft.net> | 2008-08-02 23:02:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-08-02 23:02:43 -0400 |
commit | 5fb662297b8a4bdadd60371c34b760efca948ebc (patch) | |
tree | ef1def70cfa440ab3d367f6f67d466227ffdf0ef | |
parent | 82f97b8d3cb3982ec97e081598c671fab2c321b0 (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.c | 4 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 12 |
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 | } |
508 | EXPORT_SYMBOL(qdisc_create_dflt); | 508 | EXPORT_SYMBOL(qdisc_create_dflt); |
509 | 509 | ||
510 | /* Under qdisc_root_lock(qdisc) and BH! */ | 510 | /* Under qdisc_lock(qdisc) and BH! */ |
511 | 511 | ||
512 | void qdisc_reset(struct Qdisc *qdisc) | 512 | void 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 | ||
548 | void qdisc_destroy(struct Qdisc *qdisc) | 548 | void 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; |