Re: [PATCH] rust: bindings: derive Zeroable for bindgen's opaque array wrappers
From: John Hubbard
Date: Sun Nov 01 2026 - 18:16:06 EST
On 10/31/26 8:28 AM, Sasha Levin wrote:
bindgen 0.73 emits the blob of some opaque types, such as ones aligned
to more than 4 bytes, as a `__BindgenOpaqueArray` or
`__BindgenOpaqueArray<align>` newtype instead of a plain array. The
newtype only derives `PartialEq`, `Eq`, `Copy`, `Clone`, `Debug` and
`Hash`, and the `MaybeZeroable` custom derive does not reach it, so a
struct that embeds such an opaque type is no longer `Zeroable`.
`spinlock` is opaque (see rust/bindgen_parameters), and with lockdep its
blob becomes a `__BindgenOpaqueArray8<[u8; 72]>`. Commit 71ec3c7d6db8
("blk-mq: quiesce a queue that joins a quiesced tag set") added a
`spinlock_t` to `struct blk_mq_tag_set`, so an allmodconfig build with
bindgen 0.73 now fails:
error[E0277]: the trait bound `bindings::__BindgenOpaqueArray8<[u8; 72]>: pin_init::Zeroable` is not satisfied
--> rust/kernel/block/mq/tag_set.rs:41:49
Which wrappers exist depends on the bindgen version and on the opaque
types of the configuration, so they cannot be covered by unconditional
impls in rust/bindings/lib.rs like `__BindgenBitfieldUnit` is. Derive
`Zeroable` for each wrapper in the generated bindings instead. The
pattern allows for the spacing of bindgen's output when rustfmt is not
available.
Fixes: 71ec3c7d6db8 ("blk-mq: quiesce a queue that joins a quiesced tag set")
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
This fixed my local build of the Nova driver in drm-rust-next, too. Nice!
I see Danilo already on Cc, but just wanted to respond here, so that he knows
it is affecting that branch.
thanks,
--
John Hubbard
---
Jens, Linus: the block pull brought this in. 71ec3c7d6db8 puts the first
spinlock_t into a struct that the Rust code zero-initializes, and since
then a Rust allmodconfig build of mainline fails with bindgen 0.73.
Sadly the commit wasn't in linux-next before the pull request went out,
so the build breakage wasn't caught there.
Build tested x86_64 and arm64 allmodconfig with bindgen 0.73.2, and the
Rust code with bindgen 0.72.1 (no change to the generated bindings) and
0.73.0, with and without formatted bindgen output.
rust/Makefile | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/rust/Makefile b/rust/Makefile
index 0ac9ab28cc2b5..0165626decbe7 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -514,13 +514,20 @@ endif
bindgen_c_flags_final = $(bindgen_c_flags_lto) -fno-builtin -D__BINDGEN__
# `--rust-target` points to our minimum supported Rust version.
+#
+# `bindgen` 0.73 emits the blob of some opaque types as a
+# `__BindgenOpaqueArray[<align>]` newtype, which the custom derives do not
+# reach. Derive `Zeroable` for those wrappers, so that a struct embedding such
+# an opaque type (e.g. `spinlock_t` with lockdep) is still `Zeroable`. The
+# pattern also matches the unformatted output used when `rustfmt` is missing.
quiet_cmd_bindgen = BINDGEN $@
cmd_bindgen = \
$(BINDGEN) $< $(bindgen_target_flags) --rust-target 1.85 \
--use-core --with-derive-default --ctypes-prefix ffi --no-layout-tests \
--no-debug '.*' --enable-function-attribute-detection \
-o $@ -- $(bindgen_c_flags_final) -DMODULE \
- $(bindgen_target_cflags) $(bindgen_target_extra)
+ $(bindgen_target_cflags) $(bindgen_target_extra); \
+ sed -Ei 's/pub struct __BindgenOpaqueArray[0-9]* *< *T *> *\( *pub T *\) *;/$(pound)[derive(pin_init::Zeroable)] &/g' $@
$(obj)/bindings/bindings_generated.rs: private bindgen_target_flags = \
$(shell grep -Ev '^#|^$$' $(src)/bindgen_parameters)
base-commit: 36aad21d50d1af3f6954bb0c988257a908202477