David S. Miller a écrit :
No, all of your cpus are racing to get the transmit lock
of the tg3 driver.  Whoever wins the race gets to queue
the packet, the others have to back off.


I believe the tg3_tx() holds the tx_lock for too long, in the case 200 or so 
skb are delivered

Maybe adding a netif_stop_queue(dev) at the beginning of this function would 
help ?
Or adding yet another bit in to tell that one qdisc_restart() is in flight..

int qdisc_restart(struct net_device *dev)
{
        struct Qdisc *q = dev->qdisc;
        struct sk_buff *skb;

+       if (dev->qrestart_active)
+               return 1;
        /* Dequeue packet */
        if ((skb = q->dequeue(q)) != NULL) {

...
                {
+                       dev->qrestart_active = 1;
                        /* And release queue */
                        spin_unlock(&dev->queue_lock);

                        if (!netif_queue_stopped(dev)) {
                                int ret;

                                if (netdev_nit)
                                        dev_queue_xmit_nit(skb, dev);

                                ret = dev->hard_start_xmit(skb, dev);
                                if (ret == NETDEV_TX_OK) {
                                        if (!nolock) {
                                                dev->xmit_lock_owner = -1;
                                                spin_unlock(&dev->xmit_lock);
                                        }
                                        spin_lock(&dev->queue_lock);
+                                       dev->qrestart_active = 0;
                                        return -1;
                                }
                                if (ret == NETDEV_TX_LOCKED && nolock) {
                                        spin_lock(&dev->queue_lock);
+                                       dev->qrestart_active = 0;
                                        goto collision;
                                }
                        }

                        /* NETDEV_TX_BUSY - we need to requeue */
                        /* Release the driver */
                        if (!nolock) {
                                dev->xmit_lock_owner = -1;
                                spin_unlock(&dev->xmit_lock);
                        }
                        spin_lock(&dev->queue_lock);
+                       dev->qrestart_active = 0;
                        q = dev->qdisc;

It does indeed look stupid that we resend the packet to
network taps repeatedly if we need to requeue.    I wonder
what a clean way is to fix that.  Probably the best idea
is to grab a reference to the SKB if netdev_nit, before
we send it off the the driver, and if the transmit succeeds
we actually call dev_queue_xmit_nit().

Actually, that won't work due to skb_header_cloned().  If
we pass the packet, or will, to the network taps, we have
to make sure skb_header_cloned() returns one else TSO mangling
of the TCP and IP headers by the driver will be seen by the
network taps.

So, this isn't easy to fix at all :)

Oh well ... :(

Given that only one skb (the first in the queue) could have the property 
'already given to taps', I believe
we could use one bit at queue level : If set (by a previous requeue), then the 
first packet *should not* be resent to taps.

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to