From: Chaosheng Qu <chaosheng.qu.linux@gmail.com>
To: sashiko-bot@kernel.org
Cc: linux-can@vger.kernel.org, Marc Kleine-Budde <mkl@pengutronix.de>,
Vincent Mailhol <mailhol@kernel.org>,
Oliver Hartkopp <socketcan@hartkopp.net>,
Oleksij Rempel <o.rempel@pengutronix.de>,
Dario Binacchi <dario.binacchi@amarulasolutions.com>
Subject: Re: [PATCH net-next 1/2] can: slcan: publish tty->disc_data only after register_candev()
Date: Sun, 25 Oct 2026 10:18:45 +0800 [thread overview]
Message-ID: <179289472574.8393.6822604769258631913@gmail.com> (raw)
In-Reply-To: <sashiko-outbox-175332@kernel.org>
Hi sashiko,
Thanks -- the mechanism is real and the cover letter is wrong about it. Let me
confirm what you describe, then be precise about what this series does and does
not fix.
The lost callback is real. `tty_wakeup()` is the only caller of
`ld->ops->write_wakeup`, and it takes the ldisc reference with
`tty_ldisc_ref()`, which is a `ldsem_down_read_trylock()`. While `slcan_open()`
runs we hold `ldisc_sem` for writing (`tty_set_ldisc()` takes it around
`tty_ldisc_open()`), so the trylock fails, `tty_ldisc_ref()` returns NULL, and
the callback is silently skipped:
```c
if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
ld = tty_ldisc_ref(tty);
if (ld) {
if (ld->ops->write_wakeup)
ld->ops->write_wakeup(tty);
tty_ldisc_deref(ld);
}
}
wake_up_interruptible_poll(&tty->write_wait, EPOLLOUT);
```
So a UART `write_wakeup()` arriving inside that window loses
`slcan_write_wakeup()` -> `schedule_work(&sl->tx_work)` never happens ->
`slcan_transmit()` never runs -> `netif_wake_queue()` is never reached and the
queue stays stopped. The only other thing `tty_wakeup()` does is wake the
`write_wait` pollers, so nothing else notices. `slcan_transmit_cmd()` has the
same hole: it waits on `xcmd_wait` for the `SLF_XCMD` completion that only
`slcan_transmit()` can clear, so a wakeup lost there ends in `-ETIMEDOUT` after
one second.
Two caveats, in the interest of accuracy rather than defence:
1. This window is not introduced by the series. Pre-series the pointer is
stored even earlier, just above `register_candev()`, so the same race exists
in the tree today. What the patch fixes is the other half: the dangling
`tty->disc_data` left behind when `register_candev()` fails, which both
`slcan_write_wakeup()` and `slcan_netdev_xmit()` dereference without a NULL
check.
2. Deferring `register_candev()` until after the semaphore is released is not
expressible from `ldisc->open()`. `tty_set_ldisc()` holds `ldisc_sem` across
`tty_ldisc_open()` and only unlocks it at the `out:` label after `.open()`
has returned, and `tty_ldisc_setup()` opens the primary tty with `ldisc_sem`
already held. The only way to publish after the unlock is to move
`register_candev()` onto a work item queued at the end of `.open()` -- which
also means `.open()` can no longer report a registration failure:
`slcan_close()` would have to handle a not-yet-registered device, and the
ldisc change would succeed before we know whether the netdev exists.
The failure is also bounded and recoverable: the window lasts only as long as
`slcan_open()`, and afterwards a bring-down/bring-up of the interface (or a tty
hangup) goes through `slcan_netdev_close()`/`slcan_open()`, which clear
`TTY_DO_WRITE_WAKEUP`, `flush_work(&sl->tx_work)` and start the queue again. It
needs the UART wakeup to land exactly inside the tail of `.open()`, so this is a
narrow race, not a stall from normal use.
For the next revision I will drop the "the stale pointer is not observable
today" sentence from the cover letter -- you are right that it is wrong for the
`write_wakeup` path -- and state the above instead. If you think moving the
registration to a work item is the right trade-off, I would rather do it as a
separate patch on top: folding an error-handling change into a two-line
ordering fix is not something I want to hide in this series.
Thanks,
Chaosheng
next prev parent reply other threads:[~2026-10-25 2:27 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-16 6:11 [PATCH net-next 0/2] can: publish tty->disc_data only after register_candev() Chaosheng Qu
2026-10-16 6:11 ` [PATCH net-next 1/2] can: slcan: " Chaosheng Qu
2026-10-17 6:11 ` sashiko-bot
2026-10-25 2:18 ` Chaosheng Qu [this message]
2026-10-16 6:11 ` [PATCH net-next 2/2] can: can327: " Chaosheng Qu
2026-10-16 14:10 ` Max
2026-10-17 6:11 ` sashiko-bot
2026-10-25 2:18 ` Chaosheng Qu
2026-11-09 17:21 ` Max Staudt
2026-11-11 6:40 ` [PATCH net-next 0/2] can: " Chaosheng Qu
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=179289472574.8393.6822604769258631913@gmail.com \
--to=chaosheng.qu.linux@gmail.com \
--cc=dario.binacchi@amarulasolutions.com \
--cc=linux-can@vger.kernel.org \
--cc=mailhol@kernel.org \
--cc=mkl@pengutronix.de \
--cc=o.rempel@pengutronix.de \
--cc=sashiko-bot@kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox