packet: don't unconditionally schedule() in case of MSG_DONTWAIT
authorDaniel Borkmann <dborkman@redhat.com>
Wed, 15 Jan 2014 15:25:35 +0000 (16:25 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 17 Jan 2014 00:17:11 +0000 (16:17 -0800)
In tpacket_snd(), when we've discovered a first frame that is
not in status TP_STATUS_SEND_REQUEST, and return a NULL buffer,
we exit the send routine in case of MSG_DONTWAIT, since we've
finished traversing the mmaped send ring buffer and don't care
about pending frames.

While doing so, we still unconditionally call an expensive
schedule() in the packet_current_frame() "error" path, which
is unnecessary in this case since it's enough to just quit
the function.

Also, in case MSG_DONTWAIT is not set, we should rather test
for need_resched() first and do schedule() only if necessary
since meanwhile pending frames could already have finished
processing and called skb destructor.

Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/packet/af_packet.c

index 85bb38cb56fd28acd8b18e95b345da085b2cd7ad..d5495d87f399db7b9e0b3e7c12457832fd1bdf5d 100644 (file)
@@ -2156,6 +2156,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        int err, reserve = 0;
        void *ph;
        struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name;
+       bool need_wait = !(msg->msg_flags & MSG_DONTWAIT);
        int tp_len, size_max;
        unsigned char *addr;
        int len_sum = 0;
@@ -2198,10 +2199,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
 
        do {
                ph = packet_current_frame(po, &po->tx_ring,
-                               TP_STATUS_SEND_REQUEST);
-
+                                         TP_STATUS_SEND_REQUEST);
                if (unlikely(ph == NULL)) {
-                       schedule();
+                       if (need_wait && need_resched())
+                               schedule();
                        continue;
                }
 
@@ -2255,10 +2256,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                }
                packet_increment_head(&po->tx_ring);
                len_sum += tp_len;
-       } while (likely((ph != NULL) ||
-                       ((!(msg->msg_flags & MSG_DONTWAIT)) &&
-                        (atomic_read(&po->tx_ring.pending))))
-               );
+       } while (likely((ph != NULL) || (need_wait &&
+                                        atomic_read(&po->tx_ring.pending))));
 
        err = len_sum;
        goto out_put;