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>
This commit is contained in:
parent
82f97b8d3c
commit
5fb662297b
|
@ -1796,7 +1796,7 @@ gso:
|
|||
skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS);
|
||||
#endif
|
||||
if (q->enqueue) {
|
||||
spinlock_t *root_lock = qdisc_root_lock(q);
|
||||
spinlock_t *root_lock = qdisc_lock(q);
|
||||
|
||||
spin_lock(root_lock);
|
||||
|
||||
|
@ -1995,7 +1995,7 @@ static void net_tx_action(struct softirq_action *h)
|
|||
smp_mb__before_clear_bit();
|
||||
clear_bit(__QDISC_STATE_SCHED, &q->state);
|
||||
|
||||
root_lock = qdisc_root_lock(q);
|
||||
root_lock = qdisc_lock(q);
|
||||
if (spin_trylock(root_lock)) {
|
||||
qdisc_run(q);
|
||||
spin_unlock(root_lock);
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
/* Main transmission queue. */
|
||||
|
||||
/* Modifications to data participating in scheduling must be protected with
|
||||
* qdisc_root_lock(qdisc) spinlock.
|
||||
* qdisc_lock(qdisc) spinlock.
|
||||
*
|
||||
* The idea is the following:
|
||||
* - enqueue, dequeue are serialized via qdisc root lock
|
||||
|
@ -126,7 +126,7 @@ static inline int qdisc_restart(struct Qdisc *q)
|
|||
if (unlikely((skb = dequeue_skb(q)) == NULL))
|
||||
return 0;
|
||||
|
||||
root_lock = qdisc_root_lock(q);
|
||||
root_lock = qdisc_lock(q);
|
||||
|
||||
/* And release qdisc */
|
||||
spin_unlock(root_lock);
|
||||
|
@ -507,7 +507,7 @@ errout:
|
|||
}
|
||||
EXPORT_SYMBOL(qdisc_create_dflt);
|
||||
|
||||
/* Under qdisc_root_lock(qdisc) and BH! */
|
||||
/* Under qdisc_lock(qdisc) and BH! */
|
||||
|
||||
void qdisc_reset(struct Qdisc *qdisc)
|
||||
{
|
||||
|
@ -543,7 +543,7 @@ static void __qdisc_destroy(struct rcu_head *head)
|
|||
kfree((char *) qdisc - qdisc->padded);
|
||||
}
|
||||
|
||||
/* Under qdisc_root_lock(qdisc) and BH! */
|
||||
/* Under qdisc_lock(qdisc) and BH! */
|
||||
|
||||
void qdisc_destroy(struct Qdisc *qdisc)
|
||||
{
|
||||
|
@ -659,7 +659,7 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock)
|
|||
|
||||
dev_queue = netdev_get_tx_queue(dev, i);
|
||||
q = dev_queue->qdisc;
|
||||
root_lock = qdisc_root_lock(q);
|
||||
root_lock = qdisc_lock(q);
|
||||
|
||||
if (lock)
|
||||
spin_lock_bh(root_lock);
|
||||
|
@ -735,7 +735,7 @@ static void shutdown_scheduler_queue(struct net_device *dev,
|
|||
struct Qdisc *qdisc_default = _qdisc_default;
|
||||
|
||||
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_sleeping = qdisc_default;
|
||||
|
|
Loading…
Reference in New Issue