From: sashiko-bot@kernel.org
To: "Oliver Hartkopp" <socketcan@hartkopp.net>, linux-can@vger.kernel.org
Cc: "Marc Kleine-Budde" <mkl@pengutronix.de>,
"Vincent Mailhol" <mailhol@kernel.org>,
"Oleksij Rempel" <o.rempel@pengutronix.de>
Subject: Re: [PATCH can-next v3 1/4] can: proc: reset pkg_stats atomics individually
Date: Mon, 19 Oct 2026 07:53:34 +0000 [thread overview]
Message-ID: <sashiko-outbox-176764@kernel.org> (raw)
In-Reply-To: <20261019074244.50391-2-socketcan@hartkopp.net>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] can: proc: stale counter snapshots in can_stat_update() overwrite reset stats
--
commit 947871fd730bb7740551ee6c8b42c7ac5ed61308
Author: Runyu Xiao <runyu.xiao@seu.edu.cn>
can: proc: reset pkg_stats atomics individually
This patch replaces the whole-struct memset() in can_init_stats() with
individual atomic_long_set() and scalar field resets in can_reset_pkg_stats(),
and switches can_stat_update() to use atomic_long_xchg() when reading and
clearing the delta counters.
> diff --git a/net/can/proc.c b/net/can/proc.c
> index de4d05ae34597..70104f13077e0 100644
> --- a/net/can/proc.c
> +++ b/net/can/proc.c
> @@ -76,16 +76,39 @@ static const char rx_list_name[][8] = {
> * af_can statistics stuff
> */
>
> +static void can_reset_pkg_stats(struct can_pkg_stats *pkg_stats)
> +{
> + atomic_long_set(&pkg_stats->rx_frames, 0);
> + atomic_long_set(&pkg_stats->tx_frames, 0);
> + atomic_long_set(&pkg_stats->matches, 0);
> +
> + pkg_stats->total_rx_rate = 0;
> + pkg_stats->total_tx_rate = 0;
> + pkg_stats->total_rx_match_ratio = 0;
> +
> + pkg_stats->current_rx_rate = 0;
> + pkg_stats->current_tx_rate = 0;
> + pkg_stats->current_rx_match_ratio = 0;
> +
> + pkg_stats->max_rx_rate = 0;
> + pkg_stats->max_tx_rate = 0;
> + pkg_stats->max_rx_match_ratio = 0;
> +
> + atomic_long_set(&pkg_stats->rx_frames_delta, 0);
> + atomic_long_set(&pkg_stats->tx_frames_delta, 0);
> + atomic_long_set(&pkg_stats->matches_delta, 0);
> +}
> +
> static void can_init_stats(struct net *net)
> {
> struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
> struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
> /*
> - * This memset function is called from a timer context (when
> + * This stats reset is called from a timer context (when
> * can_stattimer is active which is the default) OR in a process
> * context (reading the proc_fs when can_stattimer is disabled).
> */
> - memset(pkg_stats, 0, sizeof(struct can_pkg_stats));
> + can_reset_pkg_stats(pkg_stats);
> pkg_stats->jiffies_init = jiffies;
>
> rcv_lists_stats->stats_reset++;
> @@ -121,9 +144,10 @@ void can_stat_update(struct timer_list *t)
> long rx_frames = atomic_long_read(&pkg_stats->rx_frames);
> long tx_frames = atomic_long_read(&pkg_stats->tx_frames);
> long matches = atomic_long_read(&pkg_stats->matches);
> - long rx_frames_delta = atomic_long_read(&pkg_stats->rx_frames_delta);
> - long tx_frames_delta = atomic_long_read(&pkg_stats->tx_frames_delta);
> - long matches_delta = atomic_long_read(&pkg_stats->matches_delta);
> + /* fetch and clear values for 'current rate' calculation */
> + long rx_frames_delta = atomic_long_xchg(&pkg_stats->rx_frames_delta, 0);
> + long tx_frames_delta = atomic_long_xchg(&pkg_stats->tx_frames_delta, 0);
> + long matches_delta = atomic_long_xchg(&pkg_stats->matches_delta, 0);
>
> /* restart counting in timer context on user request */
> if (user_reset)
[Severity: Medium]
Does can_stat_update() overwrite the freshly reset scalar statistics in
pkg_stats with stale pre-reset counter snapshots after calling
can_init_stats()?
At the beginning of can_stat_update() in net/can/proc.c, the counters are
snapshotted into local variables before checking for a reset or overflow:
unsigned long j = jiffies; /* snapshot */
long rx_frames = atomic_long_read(&pkg_stats->rx_frames);
long tx_frames = atomic_long_read(&pkg_stats->tx_frames);
long matches = atomic_long_read(&pkg_stats->matches);
/* fetch and clear values for 'current rate' calculation */
long rx_frames_delta = atomic_long_xchg(&pkg_stats->rx_frames_delta, 0);
long tx_frames_delta = atomic_long_xchg(&pkg_stats->tx_frames_delta, 0);
long matches_delta = atomic_long_xchg(&pkg_stats->matches_delta, 0);
/* restart counting in timer context on user request */
if (user_reset)
can_init_stats(net);
/* restart counting on jiffies overflow */
if (j < pkg_stats->jiffies_init)
can_init_stats(net);
/* prevent overflow in calc_rate() */
if (rx_frames > (LONG_MAX / HZ))
can_init_stats(net);
...
When user_reset is set (for example, after reading /proc/net/can/reset_stats)
or when one of the overflow conditions triggers, can_stat_update() calls
can_init_stats() -> can_reset_pkg_stats(), which zeroes the atomic counters
and the derived scalar fields (total_*, current_*, max_*).
However, the local variables rx_frames, tx_frames, matches, rx_frames_delta,
tx_frames_delta, and matches_delta still hold the pre-reset values when
can_stat_update() continues immediately below:
/* calc total values */
if (rx_frames)
pkg_stats->total_rx_match_ratio = (matches * 100) / rx_frames;
pkg_stats->total_tx_rate = calc_rate(pkg_stats->jiffies_init, j,
tx_frames);
pkg_stats->total_rx_rate = calc_rate(pkg_stats->jiffies_init, j,
rx_frames);
/* calc current values */
if (rx_frames_delta)
pkg_stats->current_rx_match_ratio =
(matches_delta * 100) / rx_frames_delta;
pkg_stats->current_tx_rate = calc_rate(0, HZ, tx_frames_delta);
pkg_stats->current_rx_rate = calc_rate(0, HZ, rx_frames_delta);
/* check / update maximum values */
if (pkg_stats->max_tx_rate < pkg_stats->current_tx_rate)
pkg_stats->max_tx_rate = pkg_stats->current_tx_rate;
...
As a result, those pre-reset local variables overwrite total_rx_match_ratio,
current_*, and max_* right after can_reset_pkg_stats() cleared them (and if
the reset was triggered by the rx_frames, tx_frames, or matches overflow
checks, the overflowing values are still passed into the ratio and calc_rate()
calculations).
Additionally, because can_init_stats() sets pkg_stats->jiffies_init = jiffies
by reading live jiffies rather than using the snapshot j, if jiffies ticks
between the snapshot and can_init_stats(net) during a user_reset, the
subsequent check (j < pkg_stats->jiffies_init) will also evaluate to true,
calling can_init_stats(net) a second time and then passing jiffies_init > j
along with the stale non-zero tx_frames and rx_frames into calc_rate().
Should can_stat_update() re-arm the timer and return early (or zero the local
snapshot variables) when can_init_stats() is called?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019074244.50391-1-socketcan@hartkopp.net?part=1
next prev parent reply other threads:[~2026-10-19 7:53 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-19 7:42 [PATCH can-next v3 0/4] can: protect the receive lists with a per-device lock Oliver Hartkopp
2026-10-19 7:42 ` [PATCH can-next v3 1/4] can: proc: reset pkg_stats atomics individually Oliver Hartkopp
2026-10-19 7:53 ` sashiko-bot [this message]
2026-10-19 8:08 ` Oliver Hartkopp
2026-10-19 11:54 ` Oliver Hartkopp
2026-10-19 7:42 ` [PATCH can-next v3 2/4] can: proc: remove pointers from CAN specific proc output Oliver Hartkopp
2026-10-19 7:42 ` [PATCH can-next v3 3/4] can: replace ARPHRD_CAN type checks with can_get_ml_priv() Oliver Hartkopp
2026-10-19 7:42 ` [PATCH can-next v3 4/4] can: protect the receive lists with a per-device lock Oliver Hartkopp
2026-10-19 14:12 ` [PATCH can-next v3 0/4] " Marc Kleine-Budde
2026-10-19 14:46 ` Oliver Hartkopp
2026-10-19 14:49 ` Marc Kleine-Budde
2026-10-19 14:52 ` Marc Kleine-Budde
2026-10-19 15:28 ` Oliver Hartkopp
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-176764@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-can@vger.kernel.org \
--cc=mailhol@kernel.org \
--cc=mkl@pengutronix.de \
--cc=o.rempel@pengutronix.de \
--cc=sashiko-reviews@lists.linux.dev \
--cc=socketcan@hartkopp.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.