diff options
Diffstat (limited to 'net/ipv4/tcp_metrics.c')
-rw-r--r-- | net/ipv4/tcp_metrics.c | 21 |
1 files changed, 11 insertions, 10 deletions
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 0d07e14f2ca5..baccb070427d 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c | |||
@@ -1051,18 +1051,19 @@ static void tcp_metrics_flush_all(struct net *net) | |||
1051 | unsigned int row; | 1051 | unsigned int row; |
1052 | 1052 | ||
1053 | for (row = 0; row < max_rows; row++, hb++) { | 1053 | for (row = 0; row < max_rows; row++, hb++) { |
1054 | struct tcp_metrics_block __rcu **pp; | ||
1054 | spin_lock_bh(&tcp_metrics_lock); | 1055 | spin_lock_bh(&tcp_metrics_lock); |
1055 | tm = deref_locked_genl(hb->chain); | 1056 | pp = &hb->chain; |
1056 | if (tm) | 1057 | for (tm = deref_locked_genl(*pp); tm; |
1057 | hb->chain = NULL; | 1058 | tm = deref_locked_genl(*pp)) { |
1058 | spin_unlock_bh(&tcp_metrics_lock); | 1059 | if (net_eq(tm_net(tm), net)) { |
1059 | while (tm) { | 1060 | *pp = tm->tcpm_next; |
1060 | struct tcp_metrics_block *next; | 1061 | kfree_rcu(tm, rcu_head); |
1061 | 1062 | } else { | |
1062 | next = deref_genl(tm->tcpm_next); | 1063 | pp = &tm->tcpm_next; |
1063 | kfree_rcu(tm, rcu_head); | 1064 | } |
1064 | tm = next; | ||
1065 | } | 1065 | } |
1066 | spin_unlock_bh(&tcp_metrics_lock); | ||
1066 | } | 1067 | } |
1067 | } | 1068 | } |
1068 | 1069 | ||