[NET]: Disable queueing when carrier is lost.
authorTommy S. Christensen <tommy.christensen@tpack.net>
Tue, 3 May 2005 23:18:52 +0000 (16:18 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 3 May 2005 23:18:52 +0000 (16:18 -0700)
Some network drivers call netif_stop_queue() when detecting loss of
carrier. This leads to packets being queued up at the qdisc level for
an unbound period of time. In order to prevent this effect, the core
networking stack will now cease to queue packets for any device, that
is operationally down (i.e. the queue is flushed and disabled).

Signed-off-by: Tommy S. Christensen <tommy.christensen@tpack.net>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/link_watch.c
net/sched/sch_generic.c

index 4859b7446c6fce484b92d53a853b0a5c9e31d02e..d43d1201275c19bf7aaf5a45126586d01b0f3960 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/netdevice.h>
 #include <linux/if.h>
 #include <net/sock.h>
+#include <net/pkt_sched.h>
 #include <linux/rtnetlink.h>
 #include <linux/jiffies.h>
 #include <linux/spinlock.h>
@@ -74,6 +75,12 @@ void linkwatch_run_queue(void)
                clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
 
                if (dev->flags & IFF_UP) {
+                       if (netif_carrier_ok(dev)) {
+                               WARN_ON(dev->qdisc_sleeping == &noop_qdisc);
+                               dev_activate(dev);
+                       } else
+                               dev_deactivate(dev);
+
                        netdev_state_change(dev);
                }
 
index 8c01e023f02e7988c788732c77adb449a707eff5..9a2f8e41a26ee9684fdea46adf684e9e88727ed9 100644 (file)
@@ -539,6 +539,10 @@ void dev_activate(struct net_device *dev)
                write_unlock_bh(&qdisc_tree_lock);
        }
 
+       if (!netif_carrier_ok(dev))
+               /* Delay activation until next carrier-on event */
+               return;
+
        spin_lock_bh(&dev->queue_lock);
        rcu_assign_pointer(dev->qdisc, dev->qdisc_sleeping);
        if (dev->qdisc != &noqueue_qdisc) {