|
@@ -1559,7 +1559,17 @@ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb)
|
|
|
skb_queue_len(&tp->ucopy.prequeue) == 0)
|
|
|
return false;
|
|
|
|
|
|
- skb_dst_force(skb);
|
|
|
+ /* Before escaping RCU protected region, we need to take care of skb
|
|
|
+ * dst. Prequeue is only enabled for established sockets.
|
|
|
+ * For such sockets, we might need the skb dst only to set sk->sk_rx_dst
|
|
|
+ * Instead of doing full sk_rx_dst validity here, let's perform
|
|
|
+ * an optimistic check.
|
|
|
+ */
|
|
|
+ if (likely(sk->sk_rx_dst))
|
|
|
+ skb_dst_drop(skb);
|
|
|
+ else
|
|
|
+ skb_dst_force(skb);
|
|
|
+
|
|
|
__skb_queue_tail(&tp->ucopy.prequeue, skb);
|
|
|
tp->ucopy.memory += skb->truesize;
|
|
|
if (tp->ucopy.memory > sk->sk_rcvbuf) {
|
|
@@ -1765,9 +1775,11 @@ void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
|
|
|
{
|
|
|
struct dst_entry *dst = skb_dst(skb);
|
|
|
|
|
|
- dst_hold(dst);
|
|
|
- sk->sk_rx_dst = dst;
|
|
|
- inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
|
|
|
+ if (dst) {
|
|
|
+ dst_hold(dst);
|
|
|
+ sk->sk_rx_dst = dst;
|
|
|
+ inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
|
|
|
+ }
|
|
|
}
|
|
|
EXPORT_SYMBOL(inet_sk_rx_dst_set);
|
|
|
|