Skip to content

Commit 374297e

Browse files
committed
Merge branch 'tcp_metrics-series-of-fixes'
Eric Dumazet says: ==================== tcp_metrics: series of fixes This series contains a fix for addr_same() and various data-race annotations. We still have to address races over tm->tcpm_saddr and tm->tcpm_daddr later. ==================== Link: https://lore.kernel.org/r/20230802131500.1478140-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents b755c25 + ddf251f commit 374297e

File tree

1 file changed

+44
-26
lines changed

1 file changed

+44
-26
lines changed

net/ipv4/tcp_metrics.c

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct tcp_fastopen_metrics {
4040

4141
struct tcp_metrics_block {
4242
struct tcp_metrics_block __rcu *tcpm_next;
43-
possible_net_t tcpm_net;
43+
struct net *tcpm_net;
4444
struct inetpeer_addr tcpm_saddr;
4545
struct inetpeer_addr tcpm_daddr;
4646
unsigned long tcpm_stamp;
@@ -51,34 +51,38 @@ struct tcp_metrics_block {
5151
struct rcu_head rcu_head;
5252
};
5353

54-
static inline struct net *tm_net(struct tcp_metrics_block *tm)
54+
static inline struct net *tm_net(const struct tcp_metrics_block *tm)
5555
{
56-
return read_pnet(&tm->tcpm_net);
56+
/* Paired with the WRITE_ONCE() in tcpm_new() */
57+
return READ_ONCE(tm->tcpm_net);
5758
}
5859

5960
static bool tcp_metric_locked(struct tcp_metrics_block *tm,
6061
enum tcp_metric_index idx)
6162
{
62-
return tm->tcpm_lock & (1 << idx);
63+
/* Paired with WRITE_ONCE() in tcpm_suck_dst() */
64+
return READ_ONCE(tm->tcpm_lock) & (1 << idx);
6365
}
6466

65-
static u32 tcp_metric_get(struct tcp_metrics_block *tm,
67+
static u32 tcp_metric_get(const struct tcp_metrics_block *tm,
6668
enum tcp_metric_index idx)
6769
{
68-
return tm->tcpm_vals[idx];
70+
/* Paired with WRITE_ONCE() in tcp_metric_set() */
71+
return READ_ONCE(tm->tcpm_vals[idx]);
6972
}
7073

7174
static void tcp_metric_set(struct tcp_metrics_block *tm,
7275
enum tcp_metric_index idx,
7376
u32 val)
7477
{
75-
tm->tcpm_vals[idx] = val;
78+
/* Paired with READ_ONCE() in tcp_metric_get() */
79+
WRITE_ONCE(tm->tcpm_vals[idx], val);
7680
}
7781

7882
static bool addr_same(const struct inetpeer_addr *a,
7983
const struct inetpeer_addr *b)
8084
{
81-
return inetpeer_addr_cmp(a, b) == 0;
85+
return (a->family == b->family) && !inetpeer_addr_cmp(a, b);
8286
}
8387

8488
struct tcpm_hash_bucket {
@@ -89,6 +93,7 @@ static struct tcpm_hash_bucket *tcp_metrics_hash __read_mostly;
8993
static unsigned int tcp_metrics_hash_log __read_mostly;
9094

9195
static DEFINE_SPINLOCK(tcp_metrics_lock);
96+
static DEFINE_SEQLOCK(fastopen_seqlock);
9297

9398
static void tcpm_suck_dst(struct tcp_metrics_block *tm,
9499
const struct dst_entry *dst,
@@ -97,7 +102,7 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm,
97102
u32 msval;
98103
u32 val;
99104

100-
tm->tcpm_stamp = jiffies;
105+
WRITE_ONCE(tm->tcpm_stamp, jiffies);
101106

102107
val = 0;
103108
if (dst_metric_locked(dst, RTAX_RTT))
@@ -110,30 +115,42 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm,
110115
val |= 1 << TCP_METRIC_CWND;
111116
if (dst_metric_locked(dst, RTAX_REORDERING))
112117
val |= 1 << TCP_METRIC_REORDERING;
113-
tm->tcpm_lock = val;
118+
/* Paired with READ_ONCE() in tcp_metric_locked() */
119+
WRITE_ONCE(tm->tcpm_lock, val);
114120

115121
msval = dst_metric_raw(dst, RTAX_RTT);
116-
tm->tcpm_vals[TCP_METRIC_RTT] = msval * USEC_PER_MSEC;
122+
tcp_metric_set(tm, TCP_METRIC_RTT, msval * USEC_PER_MSEC);
117123

118124
msval = dst_metric_raw(dst, RTAX_RTTVAR);
119-
tm->tcpm_vals[TCP_METRIC_RTTVAR] = msval * USEC_PER_MSEC;
120-
tm->tcpm_vals[TCP_METRIC_SSTHRESH] = dst_metric_raw(dst, RTAX_SSTHRESH);
121-
tm->tcpm_vals[TCP_METRIC_CWND] = dst_metric_raw(dst, RTAX_CWND);
122-
tm->tcpm_vals[TCP_METRIC_REORDERING] = dst_metric_raw(dst, RTAX_REORDERING);
125+
tcp_metric_set(tm, TCP_METRIC_RTTVAR, msval * USEC_PER_MSEC);
126+
tcp_metric_set(tm, TCP_METRIC_SSTHRESH,
127+
dst_metric_raw(dst, RTAX_SSTHRESH));
128+
tcp_metric_set(tm, TCP_METRIC_CWND,
129+
dst_metric_raw(dst, RTAX_CWND));
130+
tcp_metric_set(tm, TCP_METRIC_REORDERING,
131+
dst_metric_raw(dst, RTAX_REORDERING));
123132
if (fastopen_clear) {
133+
write_seqlock(&fastopen_seqlock);
124134
tm->tcpm_fastopen.mss = 0;
125135
tm->tcpm_fastopen.syn_loss = 0;
126136
tm->tcpm_fastopen.try_exp = 0;
127137
tm->tcpm_fastopen.cookie.exp = false;
128138
tm->tcpm_fastopen.cookie.len = 0;
139+
write_sequnlock(&fastopen_seqlock);
129140
}
130141
}
131142

132143
#define TCP_METRICS_TIMEOUT (60 * 60 * HZ)
133144

134-
static void tcpm_check_stamp(struct tcp_metrics_block *tm, struct dst_entry *dst)
145+
static void tcpm_check_stamp(struct tcp_metrics_block *tm,
146+
const struct dst_entry *dst)
135147
{
136-
if (tm && unlikely(time_after(jiffies, tm->tcpm_stamp + TCP_METRICS_TIMEOUT)))
148+
unsigned long limit;
149+
150+
if (!tm)
151+
return;
152+
limit = READ_ONCE(tm->tcpm_stamp) + TCP_METRICS_TIMEOUT;
153+
if (unlikely(time_after(jiffies, limit)))
137154
tcpm_suck_dst(tm, dst, false);
138155
}
139156

@@ -174,20 +191,23 @@ static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst,
174191
oldest = deref_locked(tcp_metrics_hash[hash].chain);
175192
for (tm = deref_locked(oldest->tcpm_next); tm;
176193
tm = deref_locked(tm->tcpm_next)) {
177-
if (time_before(tm->tcpm_stamp, oldest->tcpm_stamp))
194+
if (time_before(READ_ONCE(tm->tcpm_stamp),
195+
READ_ONCE(oldest->tcpm_stamp)))
178196
oldest = tm;
179197
}
180198
tm = oldest;
181199
} else {
182-
tm = kmalloc(sizeof(*tm), GFP_ATOMIC);
200+
tm = kzalloc(sizeof(*tm), GFP_ATOMIC);
183201
if (!tm)
184202
goto out_unlock;
185203
}
186-
write_pnet(&tm->tcpm_net, net);
204+
/* Paired with the READ_ONCE() in tm_net() */
205+
WRITE_ONCE(tm->tcpm_net, net);
206+
187207
tm->tcpm_saddr = *saddr;
188208
tm->tcpm_daddr = *daddr;
189209

190-
tcpm_suck_dst(tm, dst, true);
210+
tcpm_suck_dst(tm, dst, reclaim);
191211

192212
if (likely(!reclaim)) {
193213
tm->tcpm_next = tcp_metrics_hash[hash].chain;
@@ -434,7 +454,7 @@ void tcp_update_metrics(struct sock *sk)
434454
tp->reordering);
435455
}
436456
}
437-
tm->tcpm_stamp = jiffies;
457+
WRITE_ONCE(tm->tcpm_stamp, jiffies);
438458
out_unlock:
439459
rcu_read_unlock();
440460
}
@@ -539,8 +559,6 @@ bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst)
539559
return ret;
540560
}
541561

542-
static DEFINE_SEQLOCK(fastopen_seqlock);
543-
544562
void tcp_fastopen_cache_get(struct sock *sk, u16 *mss,
545563
struct tcp_fastopen_cookie *cookie)
546564
{
@@ -647,7 +665,7 @@ static int tcp_metrics_fill_info(struct sk_buff *msg,
647665
}
648666

649667
if (nla_put_msecs(msg, TCP_METRICS_ATTR_AGE,
650-
jiffies - tm->tcpm_stamp,
668+
jiffies - READ_ONCE(tm->tcpm_stamp),
651669
TCP_METRICS_ATTR_PAD) < 0)
652670
goto nla_put_failure;
653671

@@ -658,7 +676,7 @@ static int tcp_metrics_fill_info(struct sk_buff *msg,
658676
if (!nest)
659677
goto nla_put_failure;
660678
for (i = 0; i < TCP_METRIC_MAX_KERNEL + 1; i++) {
661-
u32 val = tm->tcpm_vals[i];
679+
u32 val = tcp_metric_get(tm, i);
662680

663681
if (!val)
664682
continue;

0 commit comments

Comments
 (0)