]> Pileus Git - ~andy/linux/blobdiff - net/ipv4/tcp_metrics.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[~andy/linux] / net / ipv4 / tcp_metrics.c
index 699a42faab9ceebaf638f96d60670df689f3e677..fa950941de65c811897f24b6fe64f71be413940f 100644 (file)
 
 int sysctl_tcp_nometrics_save __read_mostly;
 
+static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *saddr,
+                                                  const struct inetpeer_addr *daddr,
+                                                  struct net *net, unsigned int hash);
+
 struct tcp_fastopen_metrics {
        u16     mss;
        u16     syn_loss:10;            /* Recurring Fast Open SYN losses */
@@ -131,17 +135,42 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, struct dst_entry *dst,
        }
 }
 
+#define TCP_METRICS_TIMEOUT            (60 * 60 * HZ)
+
+static void tcpm_check_stamp(struct tcp_metrics_block *tm, struct dst_entry *dst)
+{
+       if (tm && unlikely(time_after(jiffies, tm->tcpm_stamp + TCP_METRICS_TIMEOUT)))
+               tcpm_suck_dst(tm, dst, false);
+}
+
+#define TCP_METRICS_RECLAIM_DEPTH      5
+#define TCP_METRICS_RECLAIM_PTR                (struct tcp_metrics_block *) 0x1UL
+
 static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst,
                                          struct inetpeer_addr *saddr,
                                          struct inetpeer_addr *daddr,
-                                         unsigned int hash,
-                                         bool reclaim)
+                                         unsigned int hash)
 {
        struct tcp_metrics_block *tm;
        struct net *net;
+       bool reclaim = false;
 
        spin_lock_bh(&tcp_metrics_lock);
        net = dev_net(dst->dev);
+
+       /* While waiting for the spin-lock the cache might have been populated
+        * with this entry and so we have to check again.
+        */
+       tm = __tcp_get_metrics(saddr, daddr, net, hash);
+       if (tm == TCP_METRICS_RECLAIM_PTR) {
+               reclaim = true;
+               tm = NULL;
+       }
+       if (tm) {
+               tcpm_check_stamp(tm, dst);
+               goto out_unlock;
+       }
+
        if (unlikely(reclaim)) {
                struct tcp_metrics_block *oldest;
 
@@ -172,17 +201,6 @@ out_unlock:
        return tm;
 }
 
-#define TCP_METRICS_TIMEOUT            (60 * 60 * HZ)
-
-static void tcpm_check_stamp(struct tcp_metrics_block *tm, struct dst_entry *dst)
-{
-       if (tm && unlikely(time_after(jiffies, tm->tcpm_stamp + TCP_METRICS_TIMEOUT)))
-               tcpm_suck_dst(tm, dst, false);
-}
-
-#define TCP_METRICS_RECLAIM_DEPTH      5
-#define TCP_METRICS_RECLAIM_PTR                (struct tcp_metrics_block *) 0x1UL
-
 static struct tcp_metrics_block *tcp_get_encode(struct tcp_metrics_block *tm, int depth)
 {
        if (tm)
@@ -295,7 +313,6 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk,
        struct inetpeer_addr saddr, daddr;
        unsigned int hash;
        struct net *net;
-       bool reclaim;
 
        saddr.family = sk->sk_family;
        daddr.family = sk->sk_family;
@@ -320,13 +337,10 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk,
        hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log);
 
        tm = __tcp_get_metrics(&saddr, &daddr, net, hash);
-       reclaim = false;
-       if (tm == TCP_METRICS_RECLAIM_PTR) {
-               reclaim = true;
+       if (tm == TCP_METRICS_RECLAIM_PTR)
                tm = NULL;
-       }
        if (!tm && create)
-               tm = tcpm_new(dst, &saddr, &daddr, hash, reclaim);
+               tm = tcpm_new(dst, &saddr, &daddr, hash);
        else
                tcpm_check_stamp(tm, dst);