From: sashiko-bot@kernel.org
To: "Maurice Hieronymus" <mhi@mailbox.org>
Cc: linux-pci@vger.kernel.org, ojeda@kernel.org
Subject: Re: [PATCH 4/4] rust: samples: add EDU PCI driver sample
Date: Sun, 14 Jun 2026 16:16:37 +0000 [thread overview]
Message-ID: <20260614161637.C9DAF1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260614-b4-rust-pci-edu-driver-v1-4-e3f2471b595c@mailbox.org>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] The IRQ handler unconditionally returns `irq::IrqReturn::Handled` even if no interrupt was serviced.
- [High] The driver blocks indefinitely in `probe()` waiting for hardware interrupts, risking a system hang.
- [High] An unacknowledged factorial interrupt causes the subsequent IRQ test to fail and hang indefinitely.
- [High] Leftover interrupts or spurious IRQs trigger premature completions, causing a data race with active DMA transfers.
- [High] The allocated PCI IRQ vectors are prematurely freed before the driver is fully initialized, permanently breaking interrupts.
--
commit 028e22726596441f18ba4b799ddf50110e879fa5
Author: Maurice Hieronymus <mhi@mailbox.org>
rust: samples: add EDU PCI driver sample
Add a Rust sample driver for the QEMU EDU device, wired up via a new
SAMPLE_RUST_DRIVER_EDU Kconfig option and the samples Makefile.
> diff --git a/samples/rust/rust_driver_edu.rs b/samples/rust/rust_driver_edu.rs
> new file mode 100644
> index 0000000000000..c092117473d3d
> --- /dev/null
> +++ b/samples/rust/rust_driver_edu.rs
[ ... ]
> + fn factorial(pdev: &pci::Device<Bound>, bar: &Bar0) -> Result {
> + Self::wait_until_compute_has_finished(pdev, bar)?;
> +
> + bar.write(regs::FACTORIAL, 4.into());
> +
> + Self::wait_until_compute_has_finished(pdev, bar)?;
> +
> + let result: u32 = bar.read(regs::FACTORIAL).into();
[Severity: High]
Does this code leave the FACT_IRQ bit set in IRQ_STATUS without acknowledging
it?
Since IRQ_ACK is never written to clear this completion, could the leftover
unacknowledged interrupt cause the strict equality check
magic == IRQ_MAGIC_VALUE to fail later in the IRQ handler, and block
test_irq() indefinitely?
> +
> + let expected = 24;
[ ... ]
> + fn test_irq(pdev: &pci::Device<Bound>, bar: &Bar0, data: &Arc<EduDriverData>) -> Result {
> + dev_dbg!(pdev, "raising irq\n");
> +
> + bar.write(regs::IRQ_RAISE, IRQ_MAGIC_VALUE.into());
> +
> + data.irq_test_completion.wait_for_completion();
[Severity: High]
Can this block probe() indefinitely?
If the hardware fails to raise the interrupt, wouldn't waiting without a
timeout stall the driver probe sequence and potentially lock up subsystem
initialization?
> + Ok(())
> + }
> +
> + fn test_dma(pdev: &pci::Device<Bound>, bar: &Bar0, data: &Arc<EduDriverData>) -> Result {
[ ... ]
> + bar.write(
> + regs::DMA_COMMAND,
> + regs::DMA_COMMAND::zeroed()
> + .with_start_transfer(true)
> + .with_direction(false)
> + .with_raise_irq(true),
> + );
> +
> + data.irq_dma_completion.wait_for_completion();
[Severity: High]
As with test_irq(), can this unbounded wait hang the system if the DMA
interrupt never arrives?
> +
> + // Destroy previous value to test roundtrip
> + kernel::dma_write!(dma, , 0);
> +
> + bar.write(regs::DMA_SRC, QEMU_DMA_BASE.into());
> + bar.write(regs::DMA_DST, dma.dma_handle().into());
> + bar.write(regs::DMA_COUNT, (dma.size() as u64).into());
> + bar.write(
> + regs::DMA_COMMAND,
> + regs::DMA_COMMAND::zeroed()
> + .with_start_transfer(true)
> + .with_direction(true)
> + .with_raise_irq(true),
> + );
> +
> + data.irq_dma_completion.wait_for_completion();
[Severity: High]
Could this return immediately due to stale completion counts?
If there are leftover interrupts from a previous module load or a spurious IRQ
inflates the completion count before this second transfer,
wait_for_completion() might not wait for the active transfer. Could this
result in a data race with the active DMA transfer?
> +
> + let result = kernel::dma_read!(dma,);
[ ... ]
> + fn probe(
> + pdev: &pci::Device<kernel::device::Core>,
> + _id_info: &Self::IdInfo,
> + ) -> impl PinInit<Self, Error> {
> + pin_init::pin_init_scope(move || {
[ ... ]
> + let irq = pdev
> + .alloc_irq_vectors(1, 1, IrqTypes::default().with(pci::IrqType::Msi))
> + .inspect_err(|e| dev_err!(pdev, "alloc_irq_vectors failed: {:?}\n", e))?;
> +
> + // State shared with the IRQ handler (the BAR and the completion the
> + // handler signals) lives in an `Arc<EduDriverData>`. `EduDriverData`
[ ... ]
> + Ok(try_pin_init!(Self {
> + irq_handler <- req,
> + // Side-effect block: run the staged self-tests against the mapped
> + // BAR now that the handler is live. A failure here aborts probe.
> + _: {
> + let bar = data.bar.access(pdev.as_ref())?;
> + EduDriver::init(pdev, bar, &data)?;
[Severity: High]
Are the allocated IRQ vectors prematurely freed before this block executes?
Since irq is a local variable in the closure passed to pin_init_scope(),
won't its Drop implementation run and free the vectors when the closure
returns? This would happen before the initializer is pinned and the
side-effect block runs EduDriver::init(), causing the self-tests to trigger
device events on freed IRQ vectors.
> + dev_info!(
> + pdev,
> + "rust_driver_edu successfully initialized\n",
> + );
> + },
> + data,
> + pdev: pdev.into()
> + }))
> + })
> + }
> +}
> +
> +impl irq::Handler for EduDriverData {
> + fn handle(&self, pdev: &kernel::device::Device<Bound>) -> irq::IrqReturn {
[ ... ]
> + // TEST_IRQ
> + let magic = status & !DMA_IRQ;
> + if magic == IRQ_MAGIC_VALUE {
> + dev_dbg!(pdev, "handling test completion in irq\n");
> + bar.write(regs::IRQ_ACK, magic.into());
> + self.irq_test_completion.complete();
> + }
> +
> + irq::IrqReturn::Handled
[Severity: High]
Will returning irq::IrqReturn::Handled unconditionally circumvent the kernel's
spurious interrupt detection mechanism?
If IRQ_STATUS is 0 or no specific interrupt source is found, wouldn't claiming
to handle the interrupt cause an infinite IRQ storm instead of correctly
returning irq::IrqReturn::None?
> + }
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260614-b4-rust-pci-edu-driver-v1-0-e3f2471b595c@mailbox.org?part=4
next prev parent reply other threads:[~2026-06-14 16:16 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-14 15:59 [PATCH 0/4] rust: samples: add an EDU PCI driver sample (MMIO + IRQ + DMA) Maurice Hieronymus
2026-06-14 15:59 ` [PATCH 1/4] rust: pci: make Vendor::from_raw() public Maurice Hieronymus
2026-06-14 16:04 ` sashiko-bot
2026-06-14 16:47 ` Gary Guo
2026-06-14 15:59 ` [PATCH 2/4] rust: pci: add managed Device::enable_device() Maurice Hieronymus
2026-06-14 16:11 ` sashiko-bot
2026-06-14 19:06 ` Maurice Hieronymus
2026-06-14 15:59 ` [PATCH 3/4] rust: completion: add complete() Maurice Hieronymus
2026-06-14 16:04 ` sashiko-bot
2026-06-14 17:38 ` Gary Guo
2026-06-14 19:07 ` Maurice Hieronymus
2026-06-14 15:59 ` [PATCH 4/4] rust: samples: add EDU PCI driver sample Maurice Hieronymus
2026-06-14 16:16 ` sashiko-bot [this message]
2026-06-15 10:12 ` Ewan Chorynski
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=20260614161637.C9DAF1F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=mhi@mailbox.org \
--cc=ojeda@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/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.