aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/tcp_ipv4.c20
-rw-r--r--net/ipv6/tcp_ipv6.c15
2 files changed, 25 insertions, 10 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}
1772EXPORT_SYMBOL(inet_sk_rx_dst_set); 1784EXPORT_SYMBOL(inet_sk_rx_dst_set);
1773 1785
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 5b3c70ff7a72..1835480336ac 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -93,13 +93,16 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
93static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) 93static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
94{ 94{
95 struct dst_entry *dst = skb_dst(skb); 95 struct dst_entry *dst = skb_dst(skb);
96 const struct rt6_info *rt = (const struct rt6_info *)dst;
97 96
98 dst_hold(dst); 97 if (dst) {
99 sk->sk_rx_dst = dst; 98 const struct rt6_info *rt = (const struct rt6_info *)dst;
100 inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; 99
101 if (rt->rt6i_node) 100 dst_hold(dst);
102 inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum; 101 sk->sk_rx_dst = dst;
102 inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
103 if (rt->rt6i_node)
104 inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
105 }
103} 106}
104 107
105static void tcp_v6_hash(struct sock *sk) 108static void tcp_v6_hash(struct sock *sk)