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

Commit 41a23b07 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

[NET_SCHED]: Avoid requeue warning on dev_deactivate



When we relinquish queue_lock in qdisc_restart and then retake it for
requeueing, we might race against dev_deactivate and end up requeueing
onto noop_qdisc.  This causes a warning to be printed.

This patch fixes this by checking this before we requeue.  As an added
bonus, we can remove the same check in __qdisc_run which was added to
prevent dev->gso_skb from being requeued when we're shutting down.

Even though we've had to add a new conditional in its place, it's better
because it only happens on requeues rather than every single time that
qdisc_run is called.

For this to work we also need to move the clearing of gso_skb up in
dev_deactivate as now qdisc_restart can occur even after we wait for
__LINK_STATE_QDISC_RUNNING to clear (but it won't do anything as long
as the queue and gso_skb is already clear).

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cce1fa36
Loading
Loading
Loading
Loading
+8 −10
Original line number Diff line number Diff line
@@ -162,7 +162,9 @@ static inline int qdisc_restart(struct net_device *dev)
		 */

requeue:
		if (skb->next)
		if (unlikely(q == &noop_qdisc))
			kfree_skb(skb);
		else if (skb->next)
			dev->gso_skb = skb;
		else
			q->ops->requeue(skb, q);
@@ -177,15 +179,11 @@ out:

void __qdisc_run(struct net_device *dev)
{
	if (unlikely(dev->qdisc == &noop_qdisc))
		goto out;

	do {
		if (!qdisc_restart(dev))
			break;
	} while (!netif_queue_stopped(dev));

out:
	clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
}

@@ -547,6 +545,7 @@ void dev_activate(struct net_device *dev)
void dev_deactivate(struct net_device *dev)
{
	struct Qdisc *qdisc;
	struct sk_buff *skb;

	spin_lock_bh(&dev->queue_lock);
	qdisc = dev->qdisc;
@@ -554,8 +553,12 @@ void dev_deactivate(struct net_device *dev)

	qdisc_reset(qdisc);

	skb = dev->gso_skb;
	dev->gso_skb = NULL;
	spin_unlock_bh(&dev->queue_lock);

	kfree_skb(skb);

	dev_watchdog_down(dev);

	/* Wait for outstanding dev_queue_xmit calls. */
@@ -564,11 +567,6 @@ void dev_deactivate(struct net_device *dev)
	/* Wait for outstanding qdisc_run calls. */
	while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
		yield();

	if (dev->gso_skb) {
		kfree_skb(dev->gso_skb);
		dev->gso_skb = NULL;
	}
}

void dev_init_scheduler(struct net_device *dev)