From: Simon Horman <horms@kernel.org>
To: fanwu01@zju.edu.cn
Cc: Simon Horman <horms@kernel.org>,
netdev@vger.kernel.org, david@ixit.cz, mgreer@animalcreek.com,
oe-linux-nfc@lists.linux.dev, linux-wireless@vger.kernel.org,
linux-kernel@vger.kernel.org, stable@vger.kernel.org
Subject: Re: [PATCH net] nfc: trf7970a: initialize lock and timeout_work before requesting the IRQ
Date: Fri, 31 Jul 2026 14:24:54 +0100 [thread overview]
Message-ID: <20260731132454.277038-1-horms@kernel.org> (raw)
In-Reply-To: <20260728031021.230831-1-fanwu01@zju.edu.cn>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260728031021.230831-1-fanwu01@zju.edu.cn?part=1
---
--- Patch [1]: [PATCH net] nfc: trf7970a: initialize lock and timeout_work before requesting the IRQ ---
commit 4be20d05d9fa2b3917899acbab0b48bcd2d1125f
Author: Fan Wu <fanwu01@zju.edu.cn>
nfc: trf7970a: initialize lock and timeout_work before requesting the IRQ
This moves mutex_init(&trf->lock) and INIT_DELAYED_WORK(&trf->timeout_work,
...) above devm_request_threaded_irq() in trf7970a_probe(), so an interrupt
arriving right after the handler is registered cannot touch an
uninitialized mutex or delayed_work. The IRQ-request failure path destroys
the mutex inline and returns. Tagged for stable.
> diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
> index 60883001fa5d..3e57f8cf229e 100644
> --- a/drivers/nfc/trf7970a.c
> +++ b/drivers/nfc/trf7970a.c
> @@ -2124,18 +2124,19 @@ static int trf7970a_probe(struct spi_device *spi)
> }
> }
>
> + mutex_init(&trf->lock);
> + INIT_DELAYED_WORK(&trf->timeout_work, trf7970a_timeout_work_handler);
> +
> ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL,
> trf7970a_irq,
> IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> "trf7970a", trf);
> if (ret) {
> dev_err(trf->dev, "Can't request IRQ#%d: %d\n", spi->irq, ret);
> + mutex_destroy(&trf->lock);
> return ret;
> }
>
> - mutex_init(&trf->lock);
> - INIT_DELAYED_WORK(&trf->timeout_work, trf7970a_timeout_work_handler);
> -
[Severity: High]
This isn't a bug introduced by this patch, but since the patch fixes the
setup side of exactly this ordering problem and is tagged for stable, is
the mirror-image teardown window worth addressing at the same time?
Nothing in this driver ever synchronously cancels trf->timeout_work, and
the devm-registered IRQ is only released by devres_release_all(), i.e.
after trf7970a_remove() returns and after probe's error unwinding at the
err_destroy_lock label.
First case, work still queued at unbind. trf7970a_tg_listen() arms the work
in mode-detect state:
trf->state = mode_detect ? TRF7970A_ST_LISTENING_MD :
TRF7970A_ST_LISTENING;
schedule_delayed_work(&trf->timeout_work, msecs_to_jiffies(timeout));
but trf7970a_shutdown() has no arm for TRF7970A_ST_LISTENING_MD:
switch (trf->state) {
case TRF7970A_ST_WAIT_FOR_TX_FIFO:
...
case TRF7970A_ST_LISTENING:
trf7970a_send_err_upstream(trf, -ECANCELED);
fallthrough;
...
default:
break;
}
so the queued work survives, and trf7970a_remove() goes on to
nfc_digital_unregister_device(trf->ddev);
nfc_digital_free_device(trf->ddev);
...
mutex_destroy(&trf->lock);
and returns, after which devres frees the devm_kzalloc'ed trf. Can the
still-armed delayed_work timer, which lives inside that freed allocation,
then fire and have trf7970a_timeout_work_handler() dereference trf->dev,
trf->state and trf->lock after free?
Second case, work already running. The only stop used anywhere in the file
is the non-synchronous variant, in trf7970a_send_err_upstream():
cancel_delayed_work(&trf->timeout_work);
If trf7970a_timeout_work_handler() is already blocked on
mutex_lock(&trf->lock) while trf7970a_remove() holds it, that cancel
returns 0 and remove() continues. Once remove() unlocks, does the handler
acquire the lock and run concurrently with the rest of remove(), reaching
trf7970a_send_err_upstream() -> trf7970a_send_upstream() -> trf->cb(trf->ddev,
...) after nfc_digital_free_device(trf->ddev), and finally
mutex_unlock(&trf->lock) on a mutex already destroyed inside memory devres
frees as soon as remove() returns? nfc_digital_unregister_device() only
sync-cancels its own poll_work/cmd_work/cmd_complete_work, it does not
touch trf->timeout_work.
There is also a debug-only aspect on the newly funnelled error paths. All
failures after the IRQ request (VIN and VDD_IO get/enable, ddev allocation,
startup, nfc_digital_register_device) reach
err_destroy_lock:
mutex_destroy(&trf->lock);
return ret;
while the devm IRQ is still armed, and trf7970a_irq() takes the lock as its
first action before any state check:
mutex_lock(&trf->lock);
if (trf->state == TRF7970A_ST_RF_OFF) {
With CONFIG_DEBUG_MUTEXES, mutex_destroy() clears lock->magic, so does a
late interrupt on these paths (and on the remove() path) trip
DEBUG_LOCKS_WARN_ON in the mutex debug checks?
Would adding cancel_delayed_work_sync(&trf->timeout_work) plus a
devm_free_irq()/disable_irq() (or registering the mutex and work teardown
with devm_add_action_or_reset() so release order mirrors setup) before
mutex_destroy() in both trf7970a_remove() and the probe unwind, and handling
TRF7970A_ST_LISTENING_MD in trf7970a_shutdown(), close these windows?
Verified with git grep on drivers/nfc/trf7970a.c: no occurrences of
cancel_delayed_work_sync, flush_delayed_work, disable_irq or devm_free_irq.
prev parent reply other threads:[~2026-07-31 13:25 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-28 3:10 [PATCH net] nfc: trf7970a: initialize lock and timeout_work before requesting the IRQ Fan Wu
2026-07-31 13:24 ` Simon Horman [this message]
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=20260731132454.277038-1-horms@kernel.org \
--to=horms@kernel.org \
--cc=david@ixit.cz \
--cc=fanwu01@zju.edu.cn \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=mgreer@animalcreek.com \
--cc=netdev@vger.kernel.org \
--cc=oe-linux-nfc@lists.linux.dev \
--cc=stable@vger.kernel.org \
/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.