Re: [PATCH 11/11] can: isotp: publish tx.state with smp_store_release()
From: Jinjie Ruan
Date: Tue Aug 25 2026 - 23:33:50 EST
在 2026/8/25 19:46, Oliver Hartkopp 写道:
>
>
> On 25.08.26 11:54, Jinjie Ruan wrote:
>> The writer already pairs with the smp_load_acquire() readers
>> in isotp_tx_timeout()/isotp_tx_gen_done(); convert
>> the smp_wmb() + WRITE_ONCE() into a release store.
>>
>> Assisted-by: DeepSeek:DeepSeek-V3
>> Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
>> ---
>> net/can/isotp.c | 4 ++--
>> 1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/net/can/isotp.c b/net/can/isotp.c
>> index 155530aedce2..11b653ba7c10 100644
>> --- a/net/can/isotp.c
>> +++ b/net/can/isotp.c
>> @@ -1156,8 +1156,8 @@ static int isotp_sendmsg(struct socket *sock,
>> struct msghdr *msg, size_t size)
>> my_gen = isotp_inc_tx_gen(READ_ONCE(so->tx_gen));
>> isotp_set_tx_result(so, my_gen, ECOMM); /* prevent stale slot
>> matching */
>> WRITE_ONCE(so->tx_gen, my_gen);
>> - smp_wmb(); /* see smp_load_acquire() in isotp_tx_[timeout|
>> gen_done] */
>> - WRITE_ONCE(so->tx.state, ISOTP_SENDING);
>> + /* Pairs with smp_load_acquire() in isotp_tx_[timeout|gen_done] */
>> + smp_store_release(&so->tx.state, ISOTP_SENDING);
>> WRITE_ONCE(so->cfecho, 0);
>> spin_unlock_bh(&so->rx_lock);
>>
>
> Hi Jinjie,
>
Hi Oliver,
> thank you for the patch, but I think this breaks the barrier logic.
> The original smp_wmb() ensures that so->tx_gen is visible before both
> subsequent writes (so->tx.state and so->cfecho).
Right!
>
> By converting only the first write into smp_store_release(), the
> WRITE_ONCE(so->cfecho, 0) is no longer protected. The compiler or CPU
> could reorder and execute the cfecho write before the release store of
Indeed, that's true.
> so->tx.state, introducing a race condition with the concurrent readers.
My rough understanding is as follows:
All lock-free readers fall into two disjoint sets:
- `isotp_tx_timeout()` and `isotp_tx_gen_done()`: read only `tx.state`
(acquire) and `tx_gen`
- `isotp_txfr_timer_handler()` the timer path of `isotp_send_cframe()`,
and the post-claim path of `isotp_sendmsg()` touch `cfecho` but never
`tx_gen`.
So no lock-free reader observes both `tx_gen` and `cfecho`.
`isotp_rcv_echo()` is the only function reading both, and it runs under
`so->rx_lock`, which serializes it with the claim.
So the ordering the `smp_wmb()` provided on top of the new release store
`tx_gen` before `cfecho` — is unobservable to every reader.
Moreover, `tx.state` and `cfecho` were never ordered against each other
by the original barrier: both followed the `smp_wmb()`, so the `(state,
cfecho)` visibility seen by the lock-free timer readers is bit-for-bit
identical before and after this change.
So the release store preserves the one ordering that matters: a reader
observing `ISOTP_SENDING` sees the new `tx_gen`.
Best regards,
Jinjie
>
> Best regards,
> Oliver
>
>