Commit 0307a0b7 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

tcp: annotate data-races on tp->segs_in and tp->data_segs_in



tcp_segs_in() can be called from BH, while socket spinlock
is held but socket owned by user, eventually reading these
fields from tcp_get_info()

Found by code inspection, no need to backport this patch
to older kernels.

Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d2489c7b
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -2172,9 +2172,13 @@ static inline void tcp_segs_in(struct tcp_sock *tp, const struct sk_buff *skb)
	u16 segs_in;

	segs_in = max_t(u16, 1, skb_shinfo(skb)->gso_segs);
	tp->segs_in += segs_in;

	/* We update these fields while other threads might
	 * read them from tcp_get_info()
	 */
	WRITE_ONCE(tp->segs_in, tp->segs_in + segs_in);
	if (skb->len > tcp_hdrlen(skb))
		tp->data_segs_in += segs_in;
		WRITE_ONCE(tp->data_segs_in, tp->data_segs_in + segs_in);
}

/*
+4 −2
Original line number Diff line number Diff line
@@ -3769,10 +3769,12 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
	tcp_get_info_chrono_stats(tp, info);

	info->tcpi_segs_out = tp->segs_out;
	info->tcpi_segs_in = tp->segs_in;

	/* segs_in and data_segs_in can be updated from tcp_segs_in() from BH */
	info->tcpi_segs_in = READ_ONCE(tp->segs_in);
	info->tcpi_data_segs_in = READ_ONCE(tp->data_segs_in);

	info->tcpi_min_rtt = tcp_min_rtt(tp);
	info->tcpi_data_segs_in = tp->data_segs_in;
	info->tcpi_data_segs_out = tp->data_segs_out;

	info->tcpi_delivery_rate_app_limited = tp->rate_app_limited ? 1 : 0;