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 980030d4..68cee35 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, static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old) { - u32 *p = kmalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC); + struct rtable *rt = (struct rtable *) dst; + struct inet_peer *peer; + u32 *p = NULL; + + if (!rt->peer) + rt_bind_peer(rt, 1); - if (p) { + peer = rt->peer; + if (peer) { u32 *old_p = __DST_METRICS_PTR(old); unsigned long prev, new; - memcpy(p, old_p, sizeof(u32) * RTAX_MAX); + p = peer->metrics; + if (inet_metrics_new(peer)) + memcpy(p, old_p, sizeof(u32) * RTAX_MAX); new = (unsigned long) p; prev = cmpxchg(&dst->_metrics, old, new); if (prev != old) { - kfree(p); p = __DST_METRICS_PTR(prev); if (prev & DST_METRICS_READ_ONLY) p = NULL; } else { - struct rtable *rt = (struct rtable *) dst; - if (rt->fi) { fib_info_put(rt->fi); rt->fi = NULL; @@ -1753,7 +1758,6 @@ static void ipv4_dst_destroy(struct dst_entry *dst) struct rtable *rt = (struct rtable *) dst; struct inet_peer *peer = rt->peer; - dst_destroy_metrics_generic(dst); if (rt->fi) { fib_info_put(rt->fi); rt->fi = NULL; |