tcp: avoid indirect calls to sock_rfree
TCP uses sk_eat_skb() when skbs can be removed from receive queue. However, the call to skb_orphan() from __kfree_skb() incurs an indirect call so sock_rfee(), which is more expensive than a direct call, especially for CONFIG_RETPOLINE=y. Add tcp_eat_recv_skb() function to make the call before __kfree_skb(). Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
b96c51bd3b
commit
3df684c1a3
|
@ -1580,6 +1580,16 @@ void tcp_cleanup_rbuf(struct sock *sk, int copied)
|
|||
tcp_send_ack(sk);
|
||||
}
|
||||
|
||||
static void tcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
if (likely(skb->destructor == sock_rfree)) {
|
||||
sock_rfree(skb);
|
||||
skb->destructor = NULL;
|
||||
skb->sk = NULL;
|
||||
}
|
||||
sk_eat_skb(sk, skb);
|
||||
}
|
||||
|
||||
static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
@ -1599,7 +1609,7 @@ static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
|
|||
* splitted a fat GRO packet, while we released socket lock
|
||||
* in skb_splice_bits()
|
||||
*/
|
||||
sk_eat_skb(sk, skb);
|
||||
tcp_eat_recv_skb(sk, skb);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1665,11 +1675,11 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|||
continue;
|
||||
}
|
||||
if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) {
|
||||
sk_eat_skb(sk, skb);
|
||||
tcp_eat_recv_skb(sk, skb);
|
||||
++seq;
|
||||
break;
|
||||
}
|
||||
sk_eat_skb(sk, skb);
|
||||
tcp_eat_recv_skb(sk, skb);
|
||||
if (!desc->count)
|
||||
break;
|
||||
WRITE_ONCE(tp->copied_seq, seq);
|
||||
|
@ -2481,14 +2491,14 @@ static int tcp_recvmsg_locked(struct sock *sk, struct msghdr *msg, size_t len,
|
|||
if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
|
||||
goto found_fin_ok;
|
||||
if (!(flags & MSG_PEEK))
|
||||
sk_eat_skb(sk, skb);
|
||||
tcp_eat_recv_skb(sk, skb);
|
||||
continue;
|
||||
|
||||
found_fin_ok:
|
||||
/* Process the FIN. */
|
||||
WRITE_ONCE(*seq, *seq + 1);
|
||||
if (!(flags & MSG_PEEK))
|
||||
sk_eat_skb(sk, skb);
|
||||
tcp_eat_recv_skb(sk, skb);
|
||||
break;
|
||||
} while (len > 0);
|
||||
|
||||
|
|
Loading…
Reference in New Issue