diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 3f9bc3f0bba0..7881b96d2b72 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1559,7 +1559,17 @@ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) | |||
1559 | skb_queue_len(&tp->ucopy.prequeue) == 0) | 1559 | skb_queue_len(&tp->ucopy.prequeue) == 0) |
1560 | return false; | 1560 | return false; |
1561 | 1561 | ||
1562 | skb_dst_force(skb); | 1562 | /* Before escaping RCU protected region, we need to take care of skb |
1563 | * dst. Prequeue is only enabled for established sockets. | ||
1564 | * For such sockets, we might need the skb dst only to set sk->sk_rx_dst | ||
1565 | * Instead of doing full sk_rx_dst validity here, let's perform | ||
1566 | * an optimistic check. | ||
1567 | */ | ||
1568 | if (likely(sk->sk_rx_dst)) | ||
1569 | skb_dst_drop(skb); | ||
1570 | else | ||
1571 | skb_dst_force(skb); | ||
1572 | |||
1563 | __skb_queue_tail(&tp->ucopy.prequeue, skb); | 1573 | __skb_queue_tail(&tp->ucopy.prequeue, skb); |
1564 | tp->ucopy.memory += skb->truesize; | 1574 | tp->ucopy.memory += skb->truesize; |
1565 | if (tp->ucopy.memory > sk->sk_rcvbuf) { | 1575 | 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) | |||
1765 | { | 1775 | { |
1766 | struct dst_entry *dst = skb_dst(skb); | 1776 | struct dst_entry *dst = skb_dst(skb); |
1767 | 1777 | ||
1768 | dst_hold(dst); | 1778 | if (dst) { |
1769 | sk->sk_rx_dst = dst; | 1779 | dst_hold(dst); |
1770 | inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; | 1780 | sk->sk_rx_dst = dst; |
1781 | inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; | ||
1782 | } | ||
1771 | } | 1783 | } |
1772 | EXPORT_SYMBOL(inet_sk_rx_dst_set); | 1784 | EXPORT_SYMBOL(inet_sk_rx_dst_set); |
1773 | 1785 | ||