tcp_metrics: Rewrite tcp_metrics_flush_all
authorEric W. Biederman <ebiederm@xmission.com>
Fri, 13 Mar 2015 05:07:10 +0000 (00:07 -0500)
committerDavid S. Miller <davem@davemloft.net>
Fri, 13 Mar 2015 05:57:07 +0000 (01:57 -0400)
Rewrite tcp_metrics_flush_all so that it can cope with entries from
different network namespaces on it's hash chain.

This is based on the logic in tcp_metrics_nl_cmd_del for deleting
a selection of entries from a tcp metrics hash chain.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/tcp_metrics.c

index 0d07e14f2ca5c4da1461570e99a26f3a70aaaa76..baccb070427d8cdd91eb78f3bcf6b5ddd516155b 100644 (file)
@@ -1051,18 +1051,19 @@ static void tcp_metrics_flush_all(struct net *net)
        unsigned int row;
 
        for (row = 0; row < max_rows; row++, hb++) {
+               struct tcp_metrics_block __rcu **pp;
                spin_lock_bh(&tcp_metrics_lock);
-               tm = deref_locked_genl(hb->chain);
-               if (tm)
-                       hb->chain = NULL;
-               spin_unlock_bh(&tcp_metrics_lock);
-               while (tm) {
-                       struct tcp_metrics_block *next;
-
-                       next = deref_genl(tm->tcpm_next);
-                       kfree_rcu(tm, rcu_head);
-                       tm = next;
+               pp = &hb->chain;
+               for (tm = deref_locked_genl(*pp); tm;
+                    tm = deref_locked_genl(*pp)) {
+                       if (net_eq(tm_net(tm), net)) {
+                               *pp = tm->tcpm_next;
+                               kfree_rcu(tm, rcu_head);
+                       } else {
+                               pp = &tm->tcpm_next;
+                       }
                }
+               spin_unlock_bh(&tcp_metrics_lock);
        }
 }