Commit 5fb66229 authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarDavid S. Miller <davem@davemloft.net>
parent 82f97b8d
...@@ -1796,7 +1796,7 @@ gso: ...@@ -1796,7 +1796,7 @@ gso:
skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS); skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS);
#endif #endif
if (q->enqueue) { if (q->enqueue) {
spinlock_t *root_lock = qdisc_root_lock(q); spinlock_t *root_lock = qdisc_lock(q);
spin_lock(root_lock); spin_lock(root_lock);
...@@ -1995,7 +1995,7 @@ static void net_tx_action(struct softirq_action *h) ...@@ -1995,7 +1995,7 @@ static void net_tx_action(struct softirq_action *h)
smp_mb__before_clear_bit(); smp_mb__before_clear_bit();
clear_bit(__QDISC_STATE_SCHED, &q->state); clear_bit(__QDISC_STATE_SCHED, &q->state);
root_lock = qdisc_root_lock(q); root_lock = qdisc_lock(q);
if (spin_trylock(root_lock)) { if (spin_trylock(root_lock)) {
qdisc_run(q); qdisc_run(q);
spin_unlock(root_lock); spin_unlock(root_lock);
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
/* Main transmission queue. */ /* Main transmission queue. */
/* Modifications to data participating in scheduling must be protected with /* Modifications to data participating in scheduling must be protected with
* qdisc_root_lock(qdisc) spinlock. * qdisc_lock(qdisc) spinlock.
* *
* The idea is the following: * The idea is the following:
* - enqueue, dequeue are serialized via qdisc root lock * - enqueue, dequeue are serialized via qdisc root lock
...@@ -126,7 +126,7 @@ static inline int qdisc_restart(struct Qdisc *q) ...@@ -126,7 +126,7 @@ static inline int qdisc_restart(struct Qdisc *q)
if (unlikely((skb = dequeue_skb(q)) == NULL)) if (unlikely((skb = dequeue_skb(q)) == NULL))
return 0; return 0;
root_lock = qdisc_root_lock(q); root_lock = qdisc_lock(q);
/* And release qdisc */ /* And release qdisc */
spin_unlock(root_lock); spin_unlock(root_lock);
...@@ -507,7 +507,7 @@ errout: ...@@ -507,7 +507,7 @@ errout:
} }
EXPORT_SYMBOL(qdisc_create_dflt); EXPORT_SYMBOL(qdisc_create_dflt);
/* Under qdisc_root_lock(qdisc) and BH! */ /* Under qdisc_lock(qdisc) and BH! */
void qdisc_reset(struct Qdisc *qdisc) void qdisc_reset(struct Qdisc *qdisc)
{ {
...@@ -543,7 +543,7 @@ static void __qdisc_destroy(struct rcu_head *head) ...@@ -543,7 +543,7 @@ static void __qdisc_destroy(struct rcu_head *head)
kfree((char *) qdisc - qdisc->padded); kfree((char *) qdisc - qdisc->padded);
} }
/* Under qdisc_root_lock(qdisc) and BH! */ /* Under qdisc_lock(qdisc) and BH! */
void qdisc_destroy(struct Qdisc *qdisc) void qdisc_destroy(struct Qdisc *qdisc)
{ {
...@@ -659,7 +659,7 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock) ...@@ -659,7 +659,7 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock)
dev_queue = netdev_get_tx_queue(dev, i); dev_queue = netdev_get_tx_queue(dev, i);
q = dev_queue->qdisc; q = dev_queue->qdisc;
root_lock = qdisc_root_lock(q); root_lock = qdisc_lock(q);
if (lock) if (lock)
spin_lock_bh(root_lock); spin_lock_bh(root_lock);
...@@ -735,7 +735,7 @@ static void shutdown_scheduler_queue(struct net_device *dev, ...@@ -735,7 +735,7 @@ static void shutdown_scheduler_queue(struct net_device *dev,
struct Qdisc *qdisc_default = _qdisc_default; struct Qdisc *qdisc_default = _qdisc_default;
if (qdisc) { if (qdisc) {
spinlock_t *root_lock = qdisc_root_lock(qdisc); spinlock_t *root_lock = qdisc_lock(qdisc);
dev_queue->qdisc = qdisc_default; dev_queue->qdisc = qdisc_default;
dev_queue->qdisc_sleeping = qdisc_default; dev_queue->qdisc_sleeping = qdisc_default;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment