diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 980030d4e4ae..68cee358d9a3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -154,25 +154,30 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | |||
154 | 154 | ||
155 | static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old) | 155 | static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old) |
156 | { | 156 | { |
157 | u32 *p = kmalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC); | 157 | struct rtable *rt = (struct rtable *) dst; |
158 | struct inet_peer *peer; | ||
159 | u32 *p = NULL; | ||
160 | |||
161 | if (!rt->peer) | ||
162 | rt_bind_peer(rt, 1); | ||
158 | 163 | ||
159 | if (p) { | 164 | peer = rt->peer; |
165 | if (peer) { | ||
160 | u32 *old_p = __DST_METRICS_PTR(old); | 166 | u32 *old_p = __DST_METRICS_PTR(old); |
161 | unsigned long prev, new; | 167 | unsigned long prev, new; |
162 | 168 | ||
163 | memcpy(p, old_p, sizeof(u32) * RTAX_MAX); | 169 | p = peer->metrics; |
170 | if (inet_metrics_new(peer)) | ||
171 | memcpy(p, old_p, sizeof(u32) * RTAX_MAX); | ||
164 | 172 | ||
165 | new = (unsigned long) p; | 173 | new = (unsigned long) p; |
166 | prev = cmpxchg(&dst->_metrics, old, new); | 174 | prev = cmpxchg(&dst->_metrics, old, new); |
167 | 175 | ||
168 | if (prev != old) { | 176 | if (prev != old) { |
169 | kfree(p); | ||
170 | p = __DST_METRICS_PTR(prev); | 177 | p = __DST_METRICS_PTR(prev); |
171 | if (prev & DST_METRICS_READ_ONLY) | 178 | if (prev & DST_METRICS_READ_ONLY) |
172 | p = NULL; | 179 | p = NULL; |
173 | } else { | 180 | } else { |
174 | struct rtable *rt = (struct rtable *) dst; | ||
175 | |||
176 | if (rt->fi) { | 181 | if (rt->fi) { |
177 | fib_info_put(rt->fi); | 182 | fib_info_put(rt->fi); |
178 | rt->fi = NULL; | 183 | rt->fi = NULL; |
@@ -1753,7 +1758,6 @@ static void ipv4_dst_destroy(struct dst_entry *dst) | |||
1753 | struct rtable *rt = (struct rtable *) dst; | 1758 | struct rtable *rt = (struct rtable *) dst; |
1754 | struct inet_peer *peer = rt->peer; | 1759 | struct inet_peer *peer = rt->peer; |
1755 | 1760 | ||
1756 | dst_destroy_metrics_generic(dst); | ||
1757 | if (rt->fi) { | 1761 | if (rt->fi) { |
1758 | fib_info_put(rt->fi); | 1762 | fib_info_put(rt->fi); |
1759 | rt->fi = NULL; | 1763 | rt->fi = NULL; |