net: Optimize hard_start_xmit() return checking
authorJarek Poplawski <jarkao2@gmail.com>
Sun, 15 Nov 2009 07:20:12 +0000 (07:20 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 16 Nov 2009 06:08:33 +0000 (22:08 -0800)
Recent changes in the TX error propagation require additional checking
and masking of values returned from hard_start_xmit(), mainly to
separate cases where skb was consumed. This aim can be simplified by
changing the order of NETDEV_TX and NET_XMIT codes, because the latter
are treated similarly to negative (ERRNO) values.

After this change much simpler dev_xmit_complete() is also used in
sch_direct_xmit(), so it is moved to netdevice.h.

Additionally NET_RX definitions in netdevice.h are moved up from
between TX codes to avoid confusion while reading the TX comment.

Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/netdevice.h
net/core/dev.c
net/sched/sch_generic.c

index 61425d0..7043f85 100644 (file)
@@ -63,6 +63,10 @@ struct wireless_dev;
 #define HAVE_FREE_NETDEV               /* free_netdev() */
 #define HAVE_NETDEV_PRIV               /* netdev_priv() */
 
+/* Backlog congestion levels */
+#define NET_RX_SUCCESS         0       /* keep 'em coming, baby */
+#define NET_RX_DROP            1       /* packet dropped */
+
 /*
  * Transmit return codes: transmit return codes originate from three different
  * namespaces:
@@ -82,14 +86,10 @@ struct wireless_dev;
 
 /* qdisc ->enqueue() return codes. */
 #define NET_XMIT_SUCCESS       0x00
-#define NET_XMIT_DROP          0x10    /* skb dropped                  */
-#define NET_XMIT_CN            0x20    /* congestion notification      */
-#define NET_XMIT_POLICED       0x30    /* skb is shot by police        */
-#define NET_XMIT_MASK          0xf0    /* qdisc flags in net/sch_generic.h */
-
-/* Backlog congestion levels */
-#define NET_RX_SUCCESS         0       /* keep 'em coming, baby */
-#define NET_RX_DROP            1       /* packet dropped */
+#define NET_XMIT_DROP          0x01    /* skb dropped                  */
+#define NET_XMIT_CN            0x02    /* congestion notification      */
+#define NET_XMIT_POLICED       0x03    /* skb is shot by police        */
+#define NET_XMIT_MASK          0x0f    /* qdisc flags in net/sch_generic.h */
 
 /* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It
  * indicates that the device will soon be dropping packets, or already drops
@@ -98,16 +98,34 @@ struct wireless_dev;
 #define net_xmit_errno(e)      ((e) != NET_XMIT_CN ? -ENOBUFS : 0)
 
 /* Driver transmit return codes */
-#define NETDEV_TX_MASK         0xf
+#define NETDEV_TX_MASK         0xf0
 
 enum netdev_tx {
        __NETDEV_TX_MIN  = INT_MIN,     /* make sure enum is signed */
-       NETDEV_TX_OK     = 0,           /* driver took care of packet */
-       NETDEV_TX_BUSY   = 1,           /* driver tx path was busy*/
-       NETDEV_TX_LOCKED = 2,           /* driver tx lock was already taken */
+       NETDEV_TX_OK     = 0x00,        /* driver took care of packet */
+       NETDEV_TX_BUSY   = 0x10,        /* driver tx path was busy*/
+       NETDEV_TX_LOCKED = 0x20,        /* driver tx lock was already taken */
 };
 typedef enum netdev_tx netdev_tx_t;
 
+/*
+ * Current order: NETDEV_TX_MASK > NET_XMIT_MASK >= 0 is significant;
+ * hard_start_xmit() return < NET_XMIT_MASK means skb was consumed.
+ */
+static inline bool dev_xmit_complete(int rc)
+{
+       /*
+        * Positive cases with an skb consumed by a driver:
+        * - successful transmission (rc == NETDEV_TX_OK)
+        * - error while transmitting (rc < 0)
+        * - error while queueing to a different device (rc & NET_XMIT_MASK)
+        */
+       if (likely(rc < NET_XMIT_MASK))
+               return true;
+
+       return false;
+}
+
 #endif
 
 #define MAX_ADDR_LEN   32              /* Largest hardware address length */
index 32045df..4b24d79 100644 (file)
@@ -1924,23 +1924,6 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
        return rc;
 }
 
-static inline bool dev_xmit_complete(int rc)
-{
-       /* successful transmission */
-       if (rc == NETDEV_TX_OK)
-               return true;
-
-       /* error while transmitting, driver consumed skb */
-       if (rc < 0)
-               return true;
-
-       /* error while queueing to a different device, driver consumed skb */
-       if (rc & NET_XMIT_MASK)
-               return true;
-
-       return false;
-}
-
 /**
  *     dev_queue_xmit - transmit a buffer
  *     @skb: buffer to transmit
index b13821a..5173c1e 100644 (file)
@@ -119,39 +119,26 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
        spin_unlock(root_lock);
 
        HARD_TX_LOCK(dev, txq, smp_processor_id());
-       if (!netif_tx_queue_stopped(txq) &&
-           !netif_tx_queue_frozen(txq)) {
+       if (!netif_tx_queue_stopped(txq) && !netif_tx_queue_frozen(txq))
                ret = dev_hard_start_xmit(skb, dev, txq);
 
-               /* an error implies that the skb was consumed */
-               if (ret < 0)
-                       ret = NETDEV_TX_OK;
-               /* all NET_XMIT codes map to NETDEV_TX_OK */
-               ret &= ~NET_XMIT_MASK;
-       }
        HARD_TX_UNLOCK(dev, txq);
 
        spin_lock(root_lock);
 
-       switch (ret) {
-       case NETDEV_TX_OK:
-               /* Driver sent out skb successfully */
+       if (dev_xmit_complete(ret)) {
+               /* Driver sent out skb successfully or skb was consumed */
                ret = qdisc_qlen(q);
-               break;
-
-       case NETDEV_TX_LOCKED:
+       } else if (ret == NETDEV_TX_LOCKED) {
                /* Driver try lock failed */
                ret = handle_dev_cpu_collision(skb, txq, q);
-               break;
-
-       default:
+       } else {
                /* Driver returned NETDEV_TX_BUSY - requeue skb */
                if (unlikely (ret != NETDEV_TX_BUSY && net_ratelimit()))
                        printk(KERN_WARNING "BUG %s code %d qlen %d\n",
                               dev->name, ret, q->q.qlen);
 
                ret = dev_requeue_skb(skb, q);
-               break;
        }
 
        if (ret && (netif_tx_queue_stopped(txq) ||