Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1796,7 +1796,7 @@ int dev_queue_xmit(struct sk_buff *skb)
	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);
+6 −6
Original line number Diff line number Diff line
@@ -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 @@ struct Qdisc * qdisc_create_dflt(struct net_device *dev,
}
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;