Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 871ecf0

Browse files
hartkoppCarlos Llamas
authored andcommitted
UPSTREAM: can: statistics: use atomic access in hot path
[ Upstream commit 80b5f90 ] In can_send() and can_receive() CAN messages and CAN filter matches are counted to be visible in the CAN procfs files. KCSAN detected a data race within can_send() when two CAN frames have been generated by a timer event writing to the same CAN netdevice at the same time. Use atomic operations to access the statistics in the hot path to fix the KCSAN complaint. Reported-by: syzbot+78ce4489b812515d5e4d@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/67cd717d.050a0220.e1a89.0006.GAE@google.com Change-Id: Ia1b2b44418970aad7fff7472ad1f805a9c0bf096 Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr> Link: https://patch.msgid.link/20250310143353.3242-1-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Sasha Levin <sashal@kernel.org> (cherry picked from commit d840c84) Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
1 parent 5081792 commit 871ecf0

File tree

3 files changed

+39
-31
lines changed

3 files changed

+39
-31
lines changed

net/can/af_can.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,8 @@ int can_send(struct sk_buff *skb, int loop)
287287
netif_rx(newskb);
288288

289289
/* update statistics */
290-
pkg_stats->tx_frames++;
291-
pkg_stats->tx_frames_delta++;
290+
atomic_long_inc(&pkg_stats->tx_frames);
291+
atomic_long_inc(&pkg_stats->tx_frames_delta);
292292

293293
return 0;
294294

@@ -647,8 +647,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
647647
int matches;
648648

649649
/* update statistics */
650-
pkg_stats->rx_frames++;
651-
pkg_stats->rx_frames_delta++;
650+
atomic_long_inc(&pkg_stats->rx_frames);
651+
atomic_long_inc(&pkg_stats->rx_frames_delta);
652652

653653
/* create non-zero unique skb identifier together with *skb */
654654
while (!(can_skb_prv(skb)->skbcnt))
@@ -669,8 +669,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
669669
consume_skb(skb);
670670

671671
if (matches > 0) {
672-
pkg_stats->matches++;
673-
pkg_stats->matches_delta++;
672+
atomic_long_inc(&pkg_stats->matches);
673+
atomic_long_inc(&pkg_stats->matches_delta);
674674
}
675675
}
676676

net/can/af_can.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ struct receiver {
6666
struct can_pkg_stats {
6767
unsigned long jiffies_init;
6868

69-
unsigned long rx_frames;
70-
unsigned long tx_frames;
71-
unsigned long matches;
69+
atomic_long_t rx_frames;
70+
atomic_long_t tx_frames;
71+
atomic_long_t matches;
7272

7373
unsigned long total_rx_rate;
7474
unsigned long total_tx_rate;
@@ -82,9 +82,9 @@ struct can_pkg_stats {
8282
unsigned long max_tx_rate;
8383
unsigned long max_rx_match_ratio;
8484

85-
unsigned long rx_frames_delta;
86-
unsigned long tx_frames_delta;
87-
unsigned long matches_delta;
85+
atomic_long_t rx_frames_delta;
86+
atomic_long_t tx_frames_delta;
87+
atomic_long_t matches_delta;
8888
};
8989

9090
/* persistent statistics */

net/can/proc.c

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ void can_stat_update(struct timer_list *t)
118118
struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
119119
unsigned long j = jiffies; /* snapshot */
120120

121+
long rx_frames = atomic_long_read(&pkg_stats->rx_frames);
122+
long tx_frames = atomic_long_read(&pkg_stats->tx_frames);
123+
long matches = atomic_long_read(&pkg_stats->matches);
124+
long rx_frames_delta = atomic_long_read(&pkg_stats->rx_frames_delta);
125+
long tx_frames_delta = atomic_long_read(&pkg_stats->tx_frames_delta);
126+
long matches_delta = atomic_long_read(&pkg_stats->matches_delta);
127+
121128
/* restart counting in timer context on user request */
122129
if (user_reset)
123130
can_init_stats(net);
@@ -127,35 +134,33 @@ void can_stat_update(struct timer_list *t)
127134
can_init_stats(net);
128135

129136
/* prevent overflow in calc_rate() */
130-
if (pkg_stats->rx_frames > (ULONG_MAX / HZ))
137+
if (rx_frames > (LONG_MAX / HZ))
131138
can_init_stats(net);
132139

133140
/* prevent overflow in calc_rate() */
134-
if (pkg_stats->tx_frames > (ULONG_MAX / HZ))
141+
if (tx_frames > (LONG_MAX / HZ))
135142
can_init_stats(net);
136143

137144
/* matches overflow - very improbable */
138-
if (pkg_stats->matches > (ULONG_MAX / 100))
145+
if (matches > (LONG_MAX / 100))
139146
can_init_stats(net);
140147

141148
/* calc total values */
142-
if (pkg_stats->rx_frames)
143-
pkg_stats->total_rx_match_ratio = (pkg_stats->matches * 100) /
144-
pkg_stats->rx_frames;
149+
if (rx_frames)
150+
pkg_stats->total_rx_match_ratio = (matches * 100) / rx_frames;
145151

146152
pkg_stats->total_tx_rate = calc_rate(pkg_stats->jiffies_init, j,
147-
pkg_stats->tx_frames);
153+
tx_frames);
148154
pkg_stats->total_rx_rate = calc_rate(pkg_stats->jiffies_init, j,
149-
pkg_stats->rx_frames);
155+
rx_frames);
150156

151157
/* calc current values */
152-
if (pkg_stats->rx_frames_delta)
158+
if (rx_frames_delta)
153159
pkg_stats->current_rx_match_ratio =
154-
(pkg_stats->matches_delta * 100) /
155-
pkg_stats->rx_frames_delta;
160+
(matches_delta * 100) / rx_frames_delta;
156161

157-
pkg_stats->current_tx_rate = calc_rate(0, HZ, pkg_stats->tx_frames_delta);
158-
pkg_stats->current_rx_rate = calc_rate(0, HZ, pkg_stats->rx_frames_delta);
162+
pkg_stats->current_tx_rate = calc_rate(0, HZ, tx_frames_delta);
163+
pkg_stats->current_rx_rate = calc_rate(0, HZ, rx_frames_delta);
159164

160165
/* check / update maximum values */
161166
if (pkg_stats->max_tx_rate < pkg_stats->current_tx_rate)
@@ -168,9 +173,9 @@ void can_stat_update(struct timer_list *t)
168173
pkg_stats->max_rx_match_ratio = pkg_stats->current_rx_match_ratio;
169174

170175
/* clear values for 'current rate' calculation */
171-
pkg_stats->tx_frames_delta = 0;
172-
pkg_stats->rx_frames_delta = 0;
173-
pkg_stats->matches_delta = 0;
176+
atomic_long_set(&pkg_stats->tx_frames_delta, 0);
177+
atomic_long_set(&pkg_stats->rx_frames_delta, 0);
178+
atomic_long_set(&pkg_stats->matches_delta, 0);
174179

175180
/* restart timer (one second) */
176181
mod_timer(&net->can.stattimer, round_jiffies(jiffies + HZ));
@@ -214,9 +219,12 @@ static int can_stats_proc_show(struct seq_file *m, void *v)
214219
struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
215220

216221
seq_putc(m, '\n');
217-
seq_printf(m, " %8ld transmitted frames (TXF)\n", pkg_stats->tx_frames);
218-
seq_printf(m, " %8ld received frames (RXF)\n", pkg_stats->rx_frames);
219-
seq_printf(m, " %8ld matched frames (RXMF)\n", pkg_stats->matches);
222+
seq_printf(m, " %8ld transmitted frames (TXF)\n",
223+
atomic_long_read(&pkg_stats->tx_frames));
224+
seq_printf(m, " %8ld received frames (RXF)\n",
225+
atomic_long_read(&pkg_stats->rx_frames));
226+
seq_printf(m, " %8ld matched frames (RXMF)\n",
227+
atomic_long_read(&pkg_stats->matches));
220228

221229
seq_putc(m, '\n');
222230

0 commit comments

Comments
 (0)