OSDN Git Service

net: no longer stop all TX queues in dev_watchdog()
authorEric Dumazet <edumazet@google.com>
Wed, 17 Nov 2021 03:29:24 +0000 (19:29 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 17 Nov 2021 14:56:16 +0000 (14:56 +0000)
There is no reason for stopping all TX queues from dev_watchdog()

Not only this stops feeding the NIC, it also migrates all qdiscs
to be serviced on the cpu calling netif_tx_unlock(), causing
a potential latency artifact.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/sch_generic.c

index 389e0d8..d33804d 100644 (file)
@@ -500,7 +500,7 @@ static void dev_watchdog(struct timer_list *t)
 {
        struct net_device *dev = from_timer(dev, t, watchdog_timer);
 
-       netif_tx_lock(dev);
+       spin_lock(&dev->tx_global_lock);
        if (!qdisc_tx_is_noop(dev)) {
                if (netif_device_present(dev) &&
                    netif_running(dev) &&
@@ -523,11 +523,13 @@ static void dev_watchdog(struct timer_list *t)
                                }
                        }
 
-                       if (some_queue_timedout) {
+                       if (unlikely(some_queue_timedout)) {
                                trace_net_dev_xmit_timeout(dev, i);
                                WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n",
                                       dev->name, netdev_drivername(dev), i);
+                               netif_freeze_queues(dev);
                                dev->netdev_ops->ndo_tx_timeout(dev, i);
+                               netif_unfreeze_queues(dev);
                        }
                        if (!mod_timer(&dev->watchdog_timer,
                                       round_jiffies(jiffies +
@@ -535,7 +537,7 @@ static void dev_watchdog(struct timer_list *t)
                                dev_hold(dev);
                }
        }
-       netif_tx_unlock(dev);
+       spin_unlock(&dev->tx_global_lock);
 
        dev_put(dev);
 }