packet: don't unconditionally schedule() in case of MSG_DONTWAIT
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>
This commit is contained in:
committed by
David S. Miller
parent
902fefb82e
commit
87a2fd286a
@@ -2156,6 +2156,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
|
|||||||
int err, reserve = 0;
|
int err, reserve = 0;
|
||||||
void *ph;
|
void *ph;
|
||||||
struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name;
|
struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name;
|
||||||
|
bool need_wait = !(msg->msg_flags & MSG_DONTWAIT);
|
||||||
int tp_len, size_max;
|
int tp_len, size_max;
|
||||||
unsigned char *addr;
|
unsigned char *addr;
|
||||||
int len_sum = 0;
|
int len_sum = 0;
|
||||||
@@ -2198,10 +2199,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
ph = packet_current_frame(po, &po->tx_ring,
|
ph = packet_current_frame(po, &po->tx_ring,
|
||||||
TP_STATUS_SEND_REQUEST);
|
TP_STATUS_SEND_REQUEST);
|
||||||
|
|
||||||
if (unlikely(ph == NULL)) {
|
if (unlikely(ph == NULL)) {
|
||||||
schedule();
|
if (need_wait && need_resched())
|
||||||
|
schedule();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2255,10 +2256,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
|
|||||||
}
|
}
|
||||||
packet_increment_head(&po->tx_ring);
|
packet_increment_head(&po->tx_ring);
|
||||||
len_sum += tp_len;
|
len_sum += tp_len;
|
||||||
} while (likely((ph != NULL) ||
|
} while (likely((ph != NULL) || (need_wait &&
|
||||||
((!(msg->msg_flags & MSG_DONTWAIT)) &&
|
atomic_read(&po->tx_ring.pending))));
|
||||||
(atomic_read(&po->tx_ring.pending))))
|
|
||||||
);
|
|
||||||
|
|
||||||
err = len_sum;
|
err = len_sum;
|
||||||
goto out_put;
|
goto out_put;
|
||||||
|
Reference in New Issue
Block a user