aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Klassert <steffen.klassert@secunet.com>2013-01-21 19:01:28 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-22 14:23:17 -0500
commitb44108dbdbaa07c609bb5755e8dd6c2035236251 (patch)
treef5c9450d05411d8d76c97ac96d9d91243c1ea5bd
parent0c8729c9b914cc0360ab87171472ca7653b2aa0e (diff)
ipv4: Fix route refcount on pmtu discovery
git commit 9cb3a50c (ipv4: Invalidate the socket cached route on pmtu events if possible) introduced a refcount problem. We don't get a refcount on the route if we get it from__sk_dst_get(), but we need one if we want to reuse this route because __sk_dst_set() releases the refcount of the old route. This patch adds proper refcount handling for that case. We introduce a 'new' flag to indicate that we are going to use a new route and we release the old route only if we replace it by a new one. Reported-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/route.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 132737a7c83a..a0fcc47fee73 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -985,6 +985,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
985 struct flowi4 fl4; 985 struct flowi4 fl4;
986 struct rtable *rt; 986 struct rtable *rt;
987 struct dst_entry *dst; 987 struct dst_entry *dst;
988 bool new = false;
988 989
989 bh_lock_sock(sk); 990 bh_lock_sock(sk);
990 rt = (struct rtable *) __sk_dst_get(sk); 991 rt = (struct rtable *) __sk_dst_get(sk);
@@ -1000,20 +1001,26 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
1000 rt = ip_route_output_flow(sock_net(sk), &fl4, sk); 1001 rt = ip_route_output_flow(sock_net(sk), &fl4, sk);
1001 if (IS_ERR(rt)) 1002 if (IS_ERR(rt))
1002 goto out; 1003 goto out;
1004
1005 new = true;
1003 } 1006 }
1004 1007
1005 __ip_rt_update_pmtu((struct rtable *) rt->dst.path, &fl4, mtu); 1008 __ip_rt_update_pmtu((struct rtable *) rt->dst.path, &fl4, mtu);
1006 1009
1007 dst = dst_check(&rt->dst, 0); 1010 dst = dst_check(&rt->dst, 0);
1008 if (!dst) { 1011 if (!dst) {
1012 if (new)
1013 dst_release(&rt->dst);
1014
1009 rt = ip_route_output_flow(sock_net(sk), &fl4, sk); 1015 rt = ip_route_output_flow(sock_net(sk), &fl4, sk);
1010 if (IS_ERR(rt)) 1016 if (IS_ERR(rt))
1011 goto out; 1017 goto out;
1012 1018
1013 dst = &rt->dst; 1019 new = true;
1014 } 1020 }
1015 1021
1016 __sk_dst_set(sk, dst); 1022 if (new)
1023 __sk_dst_set(sk, &rt->dst);
1017 1024
1018out: 1025out:
1019 bh_unlock_sock(sk); 1026 bh_unlock_sock(sk);