Commit f01821b7 authored by Paolo Abeni's avatar Paolo Abeni

Merge branch 'tcp_metrics-four-fixes'

Eric Dumazet says:

====================
tcp_metrics: four fixes

Looking at an inconclusive syzbot report, I was surprised
to see that tcp_metrics cache on my host was full of
useless entries, even though I have
/proc/sys/net/ipv4/tcp_no_metrics_save set to 1.

While looking more closely I found a total of four issues.
====================

Link: https://lore.kernel.org/r/20230922220356.3739090-1-edumazet@google.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 35766690 6532e257
...@@ -470,11 +470,15 @@ void tcp_init_metrics(struct sock *sk) ...@@ -470,11 +470,15 @@ void tcp_init_metrics(struct sock *sk)
u32 val, crtt = 0; /* cached RTT scaled by 8 */ u32 val, crtt = 0; /* cached RTT scaled by 8 */
sk_dst_confirm(sk); sk_dst_confirm(sk);
/* ssthresh may have been reduced unnecessarily during.
* 3WHS. Restore it back to its initial default.
*/
tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
if (!dst) if (!dst)
goto reset; goto reset;
rcu_read_lock(); rcu_read_lock();
tm = tcp_get_metrics(sk, dst, true); tm = tcp_get_metrics(sk, dst, false);
if (!tm) { if (!tm) {
rcu_read_unlock(); rcu_read_unlock();
goto reset; goto reset;
...@@ -489,11 +493,6 @@ void tcp_init_metrics(struct sock *sk) ...@@ -489,11 +493,6 @@ void tcp_init_metrics(struct sock *sk)
tp->snd_ssthresh = val; tp->snd_ssthresh = val;
if (tp->snd_ssthresh > tp->snd_cwnd_clamp) if (tp->snd_ssthresh > tp->snd_cwnd_clamp)
tp->snd_ssthresh = tp->snd_cwnd_clamp; tp->snd_ssthresh = tp->snd_cwnd_clamp;
} else {
/* ssthresh may have been reduced unnecessarily during.
* 3WHS. Restore it back to its initial default.
*/
tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
} }
val = tcp_metric_get(tm, TCP_METRIC_REORDERING); val = tcp_metric_get(tm, TCP_METRIC_REORDERING);
if (val && tp->reordering != val) if (val && tp->reordering != val)
...@@ -899,22 +898,25 @@ static void tcp_metrics_flush_all(struct net *net) ...@@ -899,22 +898,25 @@ static void tcp_metrics_flush_all(struct net *net)
unsigned int row; unsigned int row;
for (row = 0; row < max_rows; row++, hb++) { for (row = 0; row < max_rows; row++, hb++) {
struct tcp_metrics_block __rcu **pp; struct tcp_metrics_block __rcu **pp = &hb->chain;
bool match; bool match;
if (!rcu_access_pointer(*pp))
continue;
spin_lock_bh(&tcp_metrics_lock); spin_lock_bh(&tcp_metrics_lock);
pp = &hb->chain;
for (tm = deref_locked(*pp); tm; tm = deref_locked(*pp)) { for (tm = deref_locked(*pp); tm; tm = deref_locked(*pp)) {
match = net ? net_eq(tm_net(tm), net) : match = net ? net_eq(tm_net(tm), net) :
!refcount_read(&tm_net(tm)->ns.count); !refcount_read(&tm_net(tm)->ns.count);
if (match) { if (match) {
*pp = tm->tcpm_next; rcu_assign_pointer(*pp, tm->tcpm_next);
kfree_rcu(tm, rcu_head); kfree_rcu(tm, rcu_head);
} else { } else {
pp = &tm->tcpm_next; pp = &tm->tcpm_next;
} }
} }
spin_unlock_bh(&tcp_metrics_lock); spin_unlock_bh(&tcp_metrics_lock);
cond_resched();
} }
} }
...@@ -949,7 +951,7 @@ static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info) ...@@ -949,7 +951,7 @@ static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info)
if (addr_same(&tm->tcpm_daddr, &daddr) && if (addr_same(&tm->tcpm_daddr, &daddr) &&
(!src || addr_same(&tm->tcpm_saddr, &saddr)) && (!src || addr_same(&tm->tcpm_saddr, &saddr)) &&
net_eq(tm_net(tm), net)) { net_eq(tm_net(tm), net)) {
*pp = tm->tcpm_next; rcu_assign_pointer(*pp, tm->tcpm_next);
kfree_rcu(tm, rcu_head); kfree_rcu(tm, rcu_head);
found = true; found = true;
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment