Skip to content

Commit

Permalink
[NET_SCHED]: Avoid requeue warning on dev_deactivate
Browse files Browse the repository at this point in the history
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: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Herbert Xu authored and David S. Miller committed May 11, 2007
1 parent cce1fa3 commit 41a23b0
Showing 1 changed file with 8 additions and 10 deletions.
18 changes: 8 additions & 10 deletions net/sched/sch_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -177,15 +179,11 @@ static inline int qdisc_restart(struct net_device *dev)

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);
}

Expand Down Expand Up @@ -547,15 +545,20 @@ 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;
dev->qdisc = &noop_qdisc;

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. */
Expand All @@ -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)
Expand Down

0 comments on commit 41a23b0

Please sign in to comment.