summaryrefslogtreecommitdiffstats
path: root/net/ipv4/route.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-01-27 22:01:53 -0800
committerDavid S. Miller <davem@davemloft.net>2011-01-27 22:01:53 -0800
commita4daad6b0923030fbd3b00a01f570e4c3eef446b (patch)
treeb8e5b9a2110628503e57149f0bb2a4bb1bf3f027 /net/ipv4/route.c
parent8571a19c4ac140f1a507f3e7eb716892afa27109 (diff)
downloadlinux-a4daad6b0923030fbd3b00a01f570e4c3eef446b.tar.bz2
net: Pre-COW metrics for TCP.
TCP is going to record metrics for the connection, so pre-COW the route metrics at route cache entry creation time. This avoids several atomic operations that have to occur if we COW the metrics after the entry reaches global visibility. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r--net/ipv4/route.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 68cee358d9a3..dd57f4896736 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1857,6 +1857,28 @@ static unsigned int ipv4_default_mtu(const struct dst_entry *dst)
return mtu;
}
+static void rt_init_metrics(struct rtable *rt, struct fib_info *fi)
+{
+ if (!(rt->fl.flags & FLOWI_FLAG_PRECOW_METRICS)) {
+ no_cow:
+ rt->fi = fi;
+ atomic_inc(&fi->fib_clntref);
+ dst_init_metrics(&rt->dst, fi->fib_metrics, true);
+ } else {
+ struct inet_peer *peer;
+
+ if (!rt->peer)
+ rt_bind_peer(rt, 1);
+ peer = rt->peer;
+ if (!peer)
+ goto no_cow;
+ if (inet_metrics_new(peer))
+ memcpy(peer->metrics, fi->fib_metrics,
+ sizeof(u32) * RTAX_MAX);
+ dst_init_metrics(&rt->dst, peer->metrics, false);
+ }
+}
+
static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
{
struct dst_entry *dst = &rt->dst;
@@ -1866,9 +1888,7 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
if (FIB_RES_GW(*res) &&
FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
rt->rt_gateway = FIB_RES_GW(*res);
- rt->fi = fi;
- atomic_inc(&fi->fib_clntref);
- dst_init_metrics(dst, fi->fib_metrics, true);
+ rt_init_metrics(rt, fi);
#ifdef CONFIG_IP_ROUTE_CLASSID
dst->tclassid = FIB_RES_NH(*res).nh_tclassid;
#endif