* [PATCH v2 1/5] spi: Split spi_write_then_read()
2026-11-03 22:55 [PATCH v2 0/5] spi: lock context annotations Joseph CT Chan
@ 2026-11-03 22:55 ` Joseph CT Chan
2026-11-03 22:55 ` [PATCH v2 2/5] spi: Add lock context annotations for bus_lock_mutex Joseph CT Chan
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Joseph CT Chan @ 2026-11-03 22:55 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi, David Lechner, Bart Van Assche, Conor Dooley,
Joseph CT Chan
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
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v2 2/5] spi: Add lock context annotations for bus_lock_mutex
2026-11-03 22:55 [PATCH v2 0/5] spi: lock context annotations Joseph CT Chan
2026-11-03 22:55 ` [PATCH v2 1/5] spi: Split spi_write_then_read() Joseph CT Chan
@ 2026-11-03 22:55 ` Joseph CT Chan
2026-11-03 22:55 ` [PATCH v2 3/5] spi: spi-mem: Add lock context annotations Joseph CT Chan
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Joseph CT Chan @ 2026-11-03 22:55 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi, David Lechner, Bart Van Assche, Conor Dooley,
Joseph CT Chan
From: Bart Van Assche <bvanassche@acm.org>
Annotate spi_bus_lock() with __acquires(), spi_bus_unlock() with
__releases(), spi_sync_locked() and __spi_sync() with __must_hold(), and
spi_sync() with __must_not_hold() for bus_lock_mutex in
include/linux/spi/spi.h and drivers/spi/spi.c. Document exclusive SPI
bus lock ownership and enable static context analysis to verify locking
invariants across callers and the SPI core.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Joseph CT Chan <josephctchan@google.com>
---
drivers/spi/spi.c | 5 +++++
include/linux/spi/spi.h | 12 ++++++++----
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 85089b0ebf4b..01dfc25c1376 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -4959,6 +4959,7 @@ static void spi_complete(void *arg)
}
static int __spi_sync(struct spi_device *spi, struct spi_message *message)
+ __must_hold(&spi->controller->bus_lock_mutex)
{
DECLARE_COMPLETION_ONSTACK(done);
unsigned long flags;
@@ -5045,6 +5046,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message)
* Return: zero on success, else a negative error code.
*/
int spi_sync(struct spi_device *spi, struct spi_message *message)
+ __must_not_hold(&spi->controller->bus_lock_mutex)
{
int ret;
@@ -5073,6 +5075,7 @@ EXPORT_SYMBOL_GPL(spi_sync);
* Return: zero on success, else a negative error code.
*/
int spi_sync_locked(struct spi_device *spi, struct spi_message *message)
+ __must_hold(&spi->controller->bus_lock_mutex)
{
return __spi_sync(spi, message);
}
@@ -5094,6 +5097,7 @@ EXPORT_SYMBOL_GPL(spi_sync_locked);
* Return: always zero.
*/
int spi_bus_lock(struct spi_controller *ctlr)
+ __acquires(&ctlr->bus_lock_mutex)
{
unsigned long flags;
@@ -5123,6 +5127,7 @@ EXPORT_SYMBOL_GPL(spi_bus_lock);
* Return: always zero.
*/
int spi_bus_unlock(struct spi_controller *ctlr)
+ __releases(&ctlr->bus_lock_mutex)
{
ctlr->bus_lock_flag = 0;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index fb4baa0d3398..553c32987c97 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -1497,10 +1497,14 @@ extern int spi_split_transfers_maxwords(struct spi_controller *ctlr,
* they will sleep uninterruptibly until the async transfer completes.
*/
-extern int spi_sync(struct spi_device *spi, struct spi_message *message);
-extern int spi_sync_locked(struct spi_device *spi, struct spi_message *message);
-extern int spi_bus_lock(struct spi_controller *ctlr);
-extern int spi_bus_unlock(struct spi_controller *ctlr);
+extern int spi_sync(struct spi_device *spi, struct spi_message *message)
+ __must_not_hold(&spi->controller->bus_lock_mutex);
+extern int spi_sync_locked(struct spi_device *spi, struct spi_message *message)
+ __must_hold(&spi->controller->bus_lock_mutex);
+extern int spi_bus_lock(struct spi_controller *ctlr)
+ __acquires(&ctlr->bus_lock_mutex);
+extern int spi_bus_unlock(struct spi_controller *ctlr)
+ __releases(&ctlr->bus_lock_mutex);
/**
* spi_sync_transfer - synchronous SPI data transfer
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v2 3/5] spi: spi-mem: Add lock context annotations
2026-11-03 22:55 [PATCH v2 0/5] spi: lock context annotations Joseph CT Chan
2026-11-03 22:55 ` [PATCH v2 1/5] spi: Split spi_write_then_read() Joseph CT Chan
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 ` Joseph CT Chan
2026-11-03 22:55 ` [PATCH v2 4/5] spi: microchip-core-qspi: " Joseph CT Chan
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Joseph CT Chan @ 2026-11-03 22:55 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi, David Lechner, Bart Van Assche, Conor Dooley,
Joseph CT Chan
From: Bart Van Assche <bvanassche@acm.org>
Annotate spi_mem_access_start() with __cond_acquires() and
spi_mem_access_end() with __releases() for both bus_lock_mutex and
io_mutex in drivers/spi/spi-mem.c. Enable static context analysis to
track controller lock ownership across SPI memory operations without
false positive lock imbalance warnings.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Joseph CT Chan <josephctchan@google.com>
---
drivers/spi/spi-mem.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index b94680b60af9..f115ef6bf53b 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -297,6 +297,8 @@ bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
EXPORT_SYMBOL_GPL(spi_mem_supports_op);
static int spi_mem_access_start(struct spi_mem *mem)
+ __cond_acquires(0, &mem->spi->controller->bus_lock_mutex)
+ __cond_acquires(0, &mem->spi->controller->io_mutex)
{
struct spi_controller *ctlr = mem->spi->controller;
@@ -324,6 +326,8 @@ static int spi_mem_access_start(struct spi_mem *mem)
}
static void spi_mem_access_end(struct spi_mem *mem)
+ __releases(&mem->spi->controller->io_mutex)
+ __releases(&mem->spi->controller->bus_lock_mutex)
{
struct spi_controller *ctlr = mem->spi->controller;
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v2 4/5] spi: microchip-core-qspi: Add lock context annotations
2026-11-03 22:55 [PATCH v2 0/5] spi: lock context annotations Joseph CT Chan
` (2 preceding siblings ...)
2026-11-03 22:55 ` [PATCH v2 3/5] spi: spi-mem: Add lock context annotations Joseph CT Chan
@ 2026-11-03 22:55 ` 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
5 siblings, 0 replies; 8+ messages in thread
From: Joseph CT Chan @ 2026-11-03 22:55 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi, David Lechner, Bart Van Assche, Conor Dooley,
Joseph CT Chan
From: Bart Van Assche <bvanassche@acm.org>
Annotate mchp_coreqspi_prepare_message() with __cond_acquires() and
mchp_coreqspi_unprepare_message() with __releases() for op_lock in
drivers/spi/spi-microchip-core-qspi.c. Document message-scoped ownership
of op_lock across SPI core message preparation callbacks and enable
static context analysis to verify error-path unlocking.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Joseph CT Chan <josephctchan@google.com>
---
drivers/spi/spi-microchip-core-qspi.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c
index c0ea65014d2e..a3143d966538 100644
--- a/drivers/spi/spi-microchip-core-qspi.c
+++ b/drivers/spi/spi-microchip-core-qspi.c
@@ -603,7 +603,10 @@ static const struct spi_controller_mem_caps mchp_coreqspi_mem_caps = {
.per_op_freq = true,
};
+#define TO_MCHP_COREQSPI(ctlr) ((struct mchp_coreqspi *)spi_controller_get_devdata(ctlr))
+
static int mchp_coreqspi_unprepare_message(struct spi_controller *ctlr, struct spi_message *m)
+ __releases(&TO_MCHP_COREQSPI(ctlr)->op_lock)
{
struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
@@ -619,6 +622,7 @@ static int mchp_coreqspi_unprepare_message(struct spi_controller *ctlr, struct s
}
static int mchp_coreqspi_prepare_message(struct spi_controller *ctlr, struct spi_message *m)
+ __cond_acquires(0, &TO_MCHP_COREQSPI(ctlr)->op_lock)
{
struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
struct spi_transfer *t = NULL;
@@ -685,6 +689,8 @@ static int mchp_coreqspi_prepare_message(struct spi_controller *ctlr, struct spi
return 0;
};
+#undef TO_MCHP_COREQSPI
+
static int mchp_coreqspi_transfer_one(struct spi_controller *ctlr, struct spi_device *spi,
struct spi_transfer *t)
{
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v2 5/5] spi: Enable lock context analysis
2026-11-03 22:55 [PATCH v2 0/5] spi: lock context annotations Joseph CT Chan
` (3 preceding siblings ...)
2026-11-03 22:55 ` [PATCH v2 4/5] spi: microchip-core-qspi: " Joseph CT Chan
@ 2026-11-03 22:55 ` Joseph CT Chan
2026-11-04 14:46 ` [PATCH v2 0/5] spi: lock context annotations Mark Brown
5 siblings, 0 replies; 8+ messages in thread
From: Joseph CT Chan @ 2026-11-03 22:55 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi, David Lechner, Bart Van Assche, Conor Dooley,
Joseph CT Chan
From: Bart Van Assche <bvanassche@acm.org>
Set CONTEXT_ANALYSIS := y in drivers/spi/Makefile and
drivers/spi/tests/Makefile to enable compile-time lock context checking
for the SPI core, controller drivers, and KUnit tests when building with
CONFIG_WARN_CONTEXT_ANALYSIS=y.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Joseph CT Chan <josephctchan@google.com>
---
drivers/spi/Makefile | 2 ++
drivers/spi/tests/Makefile | 2 ++
2 files changed, 4 insertions(+)
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d4a806b46b2c..60112e379bd6 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -5,6 +5,8 @@
ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG
+CONTEXT_ANALYSIS := y
+
# small core, mostly translating board-specific
# config declarations into driver model code
obj-$(CONFIG_SPI_MASTER) += spi.o
diff --git a/drivers/spi/tests/Makefile b/drivers/spi/tests/Makefile
index 6dbf53643619..db716eaf8c43 100644
--- a/drivers/spi/tests/Makefile
+++ b/drivers/spi/tests/Makefile
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+CONTEXT_ANALYSIS := y
+
obj-$(CONFIG_SPI_DMA_KUNIT_TEST) += spi-dma-kunit.o
obj-$(CONFIG_SPI_CORE_KUNIT_TEST) += spi-core-kunit.o
--
2.56.0.385.gac671c819a-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v2 0/5] spi: lock context annotations
2026-11-03 22:55 [PATCH v2 0/5] spi: lock context annotations Joseph CT Chan
` (4 preceding siblings ...)
2026-11-03 22:55 ` [PATCH v2 5/5] spi: Enable lock context analysis Joseph CT Chan
@ 2026-11-04 14:46 ` Mark Brown
2026-11-05 4:03 ` Joseph CT Chan
5 siblings, 1 reply; 8+ messages in thread
From: Mark Brown @ 2026-11-04 14:46 UTC (permalink / raw)
To: Joseph CT Chan
Cc: linux-spi, David Lechner, Bart Van Assche, Conor Dooley,
Joseph CT Chan
[-- Attachment #1: Type: text/plain, Size: 352 bytes --]
On Tue, Nov 03, 2026 at 10:55:17PM +0000, Joseph CT Chan wrote:
> From: Joseph CT Chan <josephctchan@google.com>
>
> Hi Mark,
>
> These are Bart Van Assche's patches, which I am carrying for him. They
> add Clang lock context annotations for the SPI bus_lock_mutex, spi-mem
This doesn't apply against current code, please check and resend.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH v2 0/5] spi: lock context annotations
2026-11-04 14:46 ` [PATCH v2 0/5] spi: lock context annotations Mark Brown
@ 2026-11-05 4:03 ` Joseph CT Chan
0 siblings, 0 replies; 8+ messages in thread
From: Joseph CT Chan @ 2026-11-05 4:03 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi, David Lechner, Bart Van Assche, Conor Dooley,
Joseph CT Chan
On Wed, Nov 04, 2026 at 02:46:56PM +0000, Mark Brown wrote:
> This doesn't apply against current code, please check and resend.
Sorry, this one depends on the SPI core series too. I will resend it on
its own once that is applied.
Thanks,
Joseph
^ permalink raw reply [flat|nested] 8+ messages in thread