From: Joseph CT Chan <jctchan@gmail.com>
To: Mark Brown <broonie@kernel.org>
Cc: linux-spi@vger.kernel.org, David Lechner <dlechner@baylibre.com>,
Bart Van Assche <bvanassche@acm.org>,
Conor Dooley <conor.dooley@microchip.com>,
Joseph CT Chan <josephctchan@google.com>
Subject: [PATCH v2 1/5] spi: Split spi_write_then_read()
Date: Tue, 3 Nov 2026 22:55:18 +0000 [thread overview]
Message-ID: <20261103225522.3643901-2-jctchan@gmail.com> (raw)
In-Reply-To: <20261103225522.3643901-1-jctchan@gmail.com>
From: Bart Van Assche <bvanassche@acm.org>
Extract spi_write_then_read_buf() from spi_write_then_read(), move the
buffer mutex to file scope as spi_buf_lock, and annotate buf with
__guarded_by(&spi_buf_lock). Eliminate the correlated conditional unlock
in spi_write_then_read() to enable Clang's static context analysis to
verify lock balance and buffer access safety at compile time.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Joseph CT Chan <josephctchan@google.com>
---
drivers/spi/spi.c | 95 ++++++++++++++++++++++++++---------------------
1 file changed, 53 insertions(+), 42 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 0d36460e2c87..85089b0ebf4b 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -5135,7 +5135,39 @@ EXPORT_SYMBOL_GPL(spi_bus_unlock);
/* Portable code must never pass more than 32 bytes */
#define SPI_BUFSIZ max(32, SMP_CACHE_BYTES)
-static u8 *buf;
+static DEFINE_MUTEX(spi_buf_lock);
+static u8 *buf __guarded_by(&spi_buf_lock);
+
+static int spi_write_then_read_buf(struct spi_device *spi,
+ const void *txbuf, unsigned int n_tx,
+ void *rxbuf, unsigned int n_rx, u8 *local_buf)
+{
+ struct spi_message message;
+ struct spi_transfer x[2];
+ int status;
+
+ spi_message_init(&message);
+ memset(x, 0, sizeof(x));
+ if (n_tx) {
+ x[0].len = n_tx;
+ spi_message_add_tail(&x[0], &message);
+ }
+ if (n_rx) {
+ x[1].len = n_rx;
+ spi_message_add_tail(&x[1], &message);
+ }
+
+ memcpy(local_buf, txbuf, n_tx);
+ x[0].tx_buf = local_buf;
+ x[1].rx_buf = local_buf + n_tx;
+
+ /* Do the I/O */
+ status = spi_sync(spi, &message);
+ if (status == 0)
+ memcpy(rxbuf, x[1].rx_buf, n_rx);
+
+ return status;
+}
/**
* spi_write_then_read - SPI synchronous write followed by read
@@ -5161,11 +5193,7 @@ int spi_write_then_read(struct spi_device *spi,
const void *txbuf, unsigned n_tx,
void *rxbuf, unsigned n_rx)
{
- static DEFINE_MUTEX(lock);
-
int status;
- struct spi_message message;
- struct spi_transfer x[2];
u8 *local_buf;
/*
@@ -5174,39 +5202,21 @@ int spi_write_then_read(struct spi_device *spi,
* keep heap costs out of the hot path unless someone else is
* using the pre-allocated buffer or the transfer is too large.
*/
- if ((n_tx + n_rx) > SPI_BUFSIZ || !mutex_trylock(&lock)) {
- local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx),
- GFP_KERNEL | GFP_DMA);
- if (!local_buf)
- return -ENOMEM;
- } else {
- local_buf = buf;
- }
-
- spi_message_init(&message);
- memset(x, 0, sizeof(x));
- if (n_tx) {
- x[0].len = n_tx;
- spi_message_add_tail(&x[0], &message);
- }
- if (n_rx) {
- x[1].len = n_rx;
- spi_message_add_tail(&x[1], &message);
+ if ((n_tx + n_rx) <= SPI_BUFSIZ && mutex_trylock(&spi_buf_lock)) {
+ status = spi_write_then_read_buf(spi, txbuf, n_tx, rxbuf, n_rx,
+ buf);
+ mutex_unlock(&spi_buf_lock);
+ return status;
}
- memcpy(local_buf, txbuf, n_tx);
- x[0].tx_buf = local_buf;
- x[1].rx_buf = local_buf + n_tx;
-
- /* Do the I/O */
- status = spi_sync(spi, &message);
- if (status == 0)
- memcpy(rxbuf, x[1].rx_buf, n_rx);
+ local_buf = kmalloc(max((unsigned int)SPI_BUFSIZ, n_tx + n_rx),
+ GFP_KERNEL | GFP_DMA);
+ if (!local_buf)
+ return -ENOMEM;
- if (x[0].tx_buf == buf)
- mutex_unlock(&lock);
- else
- kfree(local_buf);
+ status = spi_write_then_read_buf(spi, txbuf, n_tx, rxbuf, n_rx,
+ local_buf);
+ kfree(local_buf);
return status;
}
@@ -5371,10 +5381,10 @@ static int __init spi_init(void)
{
int status;
- buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
- if (!buf) {
- status = -ENOMEM;
- goto err0;
+ scoped_guard(mutex, &spi_buf_lock) {
+ buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
}
status = bus_register(&spi_bus_type);
@@ -5403,9 +5413,10 @@ static int __init spi_init(void)
err2:
bus_unregister(&spi_bus_type);
err1:
- kfree(buf);
- buf = NULL;
-err0:
+ scoped_guard(mutex, &spi_buf_lock) {
+ kfree(buf);
+ buf = NULL;
+ }
return status;
}
--
2.56.0.385.gac671c819a-goog
next prev parent reply other threads:[~2026-11-03 22:55 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-03 22:55 [PATCH v2 0/5] spi: lock context annotations Joseph CT Chan
2026-11-03 22:55 ` Joseph CT Chan [this message]
2026-11-03 22:55 ` [PATCH v2 2/5] spi: Add lock context annotations for bus_lock_mutex Joseph CT Chan
2026-11-03 22:55 ` [PATCH v2 3/5] spi: spi-mem: Add lock context annotations Joseph CT Chan
2026-11-03 22:55 ` [PATCH v2 4/5] spi: microchip-core-qspi: " Joseph CT Chan
2026-11-03 22:55 ` [PATCH v2 5/5] spi: Enable lock context analysis Joseph CT Chan
2026-11-04 14:46 ` [PATCH v2 0/5] spi: lock context annotations Mark Brown
2026-11-05 4:03 ` Joseph CT Chan
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=20261103225522.3643901-2-jctchan@gmail.com \
--to=jctchan@gmail.com \
--cc=broonie@kernel.org \
--cc=bvanassche@acm.org \
--cc=conor.dooley@microchip.com \
--cc=dlechner@baylibre.com \
--cc=josephctchan@google.com \
--cc=linux-spi@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox