Commit f01821b7 authored by Paolo Abeni's avatar Paolo Abeni
Browse files

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.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 35766690 6532e257
Loading
Loading
Loading
Loading
+12 −10
Original line number Diff line number Diff line
@@ -470,11 +470,15 @@ void tcp_init_metrics(struct sock *sk)
	u32 val, crtt = 0; /* cached RTT scaled by 8 */

	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)
		goto reset;

	rcu_read_lock();
	tm = tcp_get_metrics(sk, dst, true);
	tm = tcp_get_metrics(sk, dst, false);
	if (!tm) {
		rcu_read_unlock();
		goto reset;
@@ -489,11 +493,6 @@ void tcp_init_metrics(struct sock *sk)
		tp->snd_ssthresh = val;
		if (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);
	if (val && tp->reordering != val)
@@ -899,22 +898,25 @@ 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;
		struct tcp_metrics_block __rcu **pp = &hb->chain;
		bool match;

		if (!rcu_access_pointer(*pp))
			continue;

		spin_lock_bh(&tcp_metrics_lock);
		pp = &hb->chain;
		for (tm = deref_locked(*pp); tm; tm = deref_locked(*pp)) {
			match = net ? net_eq(tm_net(tm), net) :
				!refcount_read(&tm_net(tm)->ns.count);
			if (match) {
				*pp = tm->tcpm_next;
				rcu_assign_pointer(*pp, tm->tcpm_next);
				kfree_rcu(tm, rcu_head);
			} else {
				pp = &tm->tcpm_next;
			}
		}
		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)
		if (addr_same(&tm->tcpm_daddr, &daddr) &&
		    (!src || addr_same(&tm->tcpm_saddr, &saddr)) &&
		    net_eq(tm_net(tm), net)) {
			*pp = tm->tcpm_next;
			rcu_assign_pointer(*pp, tm->tcpm_next);
			kfree_rcu(tm, rcu_head);
			found = true;
		} else {