X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsched%2Fsch_generic.c;fp=net%2Fsched%2Fsch_generic.c;h=0326752bd0ec1a47837da0cbc64d4e448bd0a5f4;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=88c6a99ce53cfb675c9fb1198ca7f5328be3577e;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 88c6a99ce..0326752bd 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -70,9 +71,9 @@ void qdisc_unlock_tree(struct net_device *dev) dev->queue_lock serializes queue accesses for this device AND dev->qdisc pointer itself. - netif_tx_lock serializes accesses to device driver. + dev->xmit_lock serializes accesses to device driver. - dev->queue_lock and netif_tx_lock are mutually exclusive, + dev->queue_lock and dev->xmit_lock are mutually exclusive, if one is grabbed, another must be free. */ @@ -88,17 +89,14 @@ void qdisc_unlock_tree(struct net_device *dev) NOTE: Called under dev->queue_lock with locally disabled BH. */ -static inline int qdisc_restart(struct net_device *dev) +int qdisc_restart(struct net_device *dev) { struct Qdisc *q = dev->qdisc; struct sk_buff *skb; /* Dequeue packet */ - if (((skb = dev->gso_skb)) || ((skb = q->dequeue(q)))) { + if ((skb = q->dequeue(q)) != NULL) { unsigned nolock = (dev->features & NETIF_F_LLTX); - - dev->gso_skb = NULL; - /* * When the driver has LLTX set it does its own locking * in start_xmit. No need to add additional overhead by @@ -109,7 +107,7 @@ static inline int qdisc_restart(struct net_device *dev) * will be requeued. */ if (!nolock) { - if (!netif_tx_trylock(dev)) { + if (!spin_trylock(&dev->xmit_lock)) { collision: /* So, someone grabbed the driver. */ @@ -127,6 +125,8 @@ static inline int qdisc_restart(struct net_device *dev) __get_cpu_var(netdev_rx_stat).cpu_collision++; goto requeue; } + /* Remember that the driver is grabbed by us. */ + dev->xmit_lock_owner = smp_processor_id(); } { @@ -135,11 +135,14 @@ static inline int qdisc_restart(struct net_device *dev) if (!netif_queue_stopped(dev)) { int ret; + if (netdev_nit) + dev_queue_xmit_nit(skb, dev); - ret = dev_hard_start_xmit(skb, dev); + ret = dev->hard_start_xmit(skb, dev); if (ret == NETDEV_TX_OK) { if (!nolock) { - netif_tx_unlock(dev); + dev->xmit_lock_owner = -1; + spin_unlock(&dev->xmit_lock); } spin_lock(&dev->queue_lock); return -1; @@ -153,7 +156,8 @@ static inline int qdisc_restart(struct net_device *dev) /* NETDEV_TX_BUSY - we need to requeue */ /* Release the driver */ if (!nolock) { - netif_tx_unlock(dev); + dev->xmit_lock_owner = -1; + spin_unlock(&dev->xmit_lock); } spin_lock(&dev->queue_lock); q = dev->qdisc; @@ -170,10 +174,7 @@ static inline int qdisc_restart(struct net_device *dev) */ requeue: - if (skb->next) - dev->gso_skb = skb; - else - q->ops->requeue(skb, q); + q->ops->requeue(skb, q); netif_schedule(dev); return 1; } @@ -181,39 +182,25 @@ requeue: return q->q.qlen; } -void __qdisc_run(struct net_device *dev) -{ - if (unlikely(dev->qdisc == &noop_qdisc)) - goto out; - - while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev)) - /* NOTHING */; - -out: - clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state); -} - static void dev_watchdog(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; - netif_tx_lock(dev); + spin_lock(&dev->xmit_lock); if (dev->qdisc != &noop_qdisc) { if (netif_device_present(dev) && netif_running(dev) && netif_carrier_ok(dev)) { if (netif_queue_stopped(dev) && - time_after(jiffies, dev->trans_start + dev->watchdog_timeo)) { - - printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", - dev->name); + (jiffies - dev->trans_start) > dev->watchdog_timeo) { + printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", dev->name); dev->tx_timeout(dev); } if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo)) dev_hold(dev); } } - netif_tx_unlock(dev); + spin_unlock(&dev->xmit_lock); dev_put(dev); } @@ -237,15 +224,17 @@ void __netdev_watchdog_up(struct net_device *dev) static void dev_watchdog_up(struct net_device *dev) { + spin_lock_bh(&dev->xmit_lock); __netdev_watchdog_up(dev); + spin_unlock_bh(&dev->xmit_lock); } static void dev_watchdog_down(struct net_device *dev) { - netif_tx_lock_bh(dev); + spin_lock_bh(&dev->xmit_lock); if (del_timer(&dev->watchdog_timer)) - dev_put(dev); - netif_tx_unlock_bh(dev); + __dev_put(dev); + spin_unlock_bh(&dev->xmit_lock); } void netif_carrier_on(struct net_device *dev) @@ -429,9 +418,10 @@ struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops) size = QDISC_ALIGN(sizeof(*sch)); size += ops->priv_size + (QDISC_ALIGNTO - 1); - p = kzalloc(size, GFP_KERNEL); + p = kmalloc(size, GFP_KERNEL); if (!p) goto errout; + memset(p, 0, size); sch = (struct Qdisc *) QDISC_ALIGN((unsigned long) p); sch->padded = (char *) sch - (char *) p; @@ -563,17 +553,10 @@ void dev_deactivate(struct net_device *dev) dev_watchdog_down(dev); - /* Wait for outstanding dev_queue_xmit calls. */ - synchronize_rcu(); - - /* Wait for outstanding qdisc_run calls. */ - while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state)) + while (test_bit(__LINK_STATE_SCHED, &dev->state)) yield(); - if (dev->gso_skb) { - kfree_skb(dev->gso_skb); - dev->gso_skb = NULL; - } + spin_unlock_wait(&dev->xmit_lock); } void dev_init_scheduler(struct net_device *dev) @@ -615,5 +598,6 @@ EXPORT_SYMBOL(qdisc_create_dflt); EXPORT_SYMBOL(qdisc_alloc); EXPORT_SYMBOL(qdisc_destroy); EXPORT_SYMBOL(qdisc_reset); +EXPORT_SYMBOL(qdisc_restart); EXPORT_SYMBOL(qdisc_lock_tree); EXPORT_SYMBOL(qdisc_unlock_tree);