lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <D9WLQ3J2TRD1.AA50TVOPKMVQ@kernel.org>
Date: Thu, 15 May 2025 10:46:22 +0200
From: "Benno Lossin" <lossin@...nel.org>
To: "Daniel Almeida" <daniel.almeida@...labora.com>, "Gary Guo"
 <gary@...yguo.net>
Cc: "Miguel Ojeda" <ojeda@...nel.org>, "Alex Gaynor"
 <alex.gaynor@...il.com>, "Boqun Feng" <boqun.feng@...il.com>,
 Björn Roy Baron <bjorn3_gh@...tonmail.com>, "Benno Lossin"
 <benno.lossin@...ton.me>, "Andreas Hindborg" <a.hindborg@...nel.org>,
 "Alice Ryhl" <aliceryhl@...gle.com>, "Trevor Gross" <tmgross@...ch.edu>,
 "Danilo Krummrich" <dakr@...nel.org>, "Greg Kroah-Hartman"
 <gregkh@...uxfoundation.org>, "Rafael J. Wysocki" <rafael@...nel.org>,
 "Thomas Gleixner" <tglx@...utronix.de>, <linux-kernel@...r.kernel.org>,
 <rust-for-linux@...r.kernel.org>
Subject: Re: [PATCH v3 1/2] rust: irq: add support for request_irq()

On Wed May 14, 2025 at 10:58 PM CEST, Daniel Almeida wrote:
> Hi Benno, I really appreciate you taking the time to review my patches.

Glad I can help :)

>> On 14 May 2025, at 17:04, Benno Lossin <lossin@...nel.org> wrote:
>> On Wed May 14, 2025 at 9:20 PM CEST, Daniel Almeida wrote:
>>> Add support for registering IRQ handlers in Rust.
>>> 
>>> IRQ handlers are extensively used in drivers when some peripheral wants
>>> to obtain the CPU attention. Registering a handler will make the system
>>> invoke the passed-in function whenever the chosen IRQ line is triggered.
>>> 
>>> Both regular and threaded IRQ handlers are supported through a Handler
>>> (or ThreadedHandler) trait that is meant to be implemented by a type
>>> that:
>>> 
>>> a) provides a function to be run by the system when the IRQ fires and,
>>> 
>>> b) holds the shared data (i.e.: `T`) between process and IRQ contexts.
>>> 
>>> The requirement that T is Sync derives from the fact that handlers might
>>> run concurrently with other processes executing the same driver,
>>> creating the potential for data races.
>>> 
>>> Ideally, some interior mutability must be in place if T is to be
>>> mutated. This should usually be done through the in-flight SpinLockIrq
>>> type.
>>> 
>>> Co-developed-by: Alice Ryhl <aliceryhl@...gle.com>
>>> Signed-off-by: Alice Ryhl <aliceryhl@...gle.com>
>>> Signed-off-by: Daniel Almeida <daniel.almeida@...labora.com>
>>> ---
>>> rust/bindings/bindings_helper.h |   1 +
>>> rust/helpers/helpers.c          |   1 +
>>> rust/helpers/irq.c              |   9 +
>>> rust/kernel/irq.rs              |  24 +++
>>> rust/kernel/irq/flags.rs        | 102 +++++++++
>>> rust/kernel/irq/request.rs      | 455 ++++++++++++++++++++++++++++++++++++++++
>>> rust/kernel/lib.rs              |   1 +
>>> 7 files changed, 593 insertions(+)
>> 
>> Could you split this patch into smaller chunks?
>
> How? This patch does one thing: it adds request_irq functionality.

You could split off the threaded irq stuff and the flags module.

Smaller patches are much much easier to review IMO.

>>> +pub use request::Handler;
>>> +pub use request::IrqReturn;
>>> +pub use request::Registration;
>>> +pub use request::ThreadedHandler;
>>> +pub use request::ThreadedIrqReturn;
>>> +pub use request::ThreadedRegistration;
>> 
>> Why not?:
>> 
>>    pub use request::{Handler, ..., ThreadedRegistration};
>
> I dislike this notation. It is just a magnet for conflicts.

Rust-analyzer has the "normalize imports" code action that can help with
that. In one of our meetings, we once discussed having a custom tool
that could merge imports, but nobody took the time to build it.

I don't see the argument here, as this re-export shouldn't really
change.

>>> diff --git a/rust/kernel/irq/flags.rs b/rust/kernel/irq/flags.rs
>>> new file mode 100644
>>> index 0000000000000000000000000000000000000000..3cfaef65ae14f6c02f55ebcf4d52450c0052df30
>>> --- /dev/null
>>> +++ b/rust/kernel/irq/flags.rs
>>> @@ -0,0 +1,102 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +// SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
>>> +
>>> +use crate::bindings;
>>> +
>>> +/// Flags to be used when registering IRQ handlers.
>>> +///
>>> +/// They can be combined with the operators `|`, `&`, and `!`.
>>> +#[derive(Clone, Copy, PartialEq, Eq)]
>>> +pub struct Flags(u64);
>> 
>> The constants below seem to all be 32 bit, why did you choose u64?
>
> The C code takes in ffi::c_ulong. Shouldn’t this map to u64? Or maybe usize.

Maybe bindgen is doing some funky stuff, Gary changed the mappings a
couple months ago (from rust/ffi.rs):

    c_long = isize;
    c_ulong = usize;

So this indeed should be usize, what is going on here?

>>> +/// A registration of an IRQ handler for a given IRQ line.
>>> +///
>>> +/// # Examples
>>> +///
>>> +/// The following is an example of using `Registration`. It uses a
>>> +/// [`SpinLock`](crate::sync::SpinLockIrq) to provide the interior mutability.
>>> +/// Note that Spinlocks are not safe to use in IRQ context as of now, but may be
>>> +/// in the future.
>> 
>> Didn't your commit message mention SpinLockIrq?
>
> This is not upstream yet. I removed all mentions of SpinLockIrq on
> purpose, but I apparently missed some as you say.
>
> We definitely need interrupt-aware spinlocks to access the data in interrupt
> context. It is just a matter of deciding whether we will be referring to a type
> whose API is not 100% formalized as we speak, or to SpinLock itself - which is
> already upstream - with a caveat. I chose the latter.

I don't think we should knowingly do something that is "not safe". If
this requires `SpinLockIrq`, then that should land first. I think
referring to a not-yet-existing type is fine.

>>> +/// # Invariants
>>> +///
>>> +/// * We own an irq handler using `&self` as its private data.
>>> +///
>>> +#[pin_data(PinnedDrop)]
>>> +pub struct Registration<T: Handler> {
>>> +    irq: u32,
>>> +    #[pin]
>>> +    handler: T,
>>> +    #[pin]
>>> +    /// Pinned because we need address stability so that we can pass a pointer
>>> +    /// to the callback.
>>> +    _pin: PhantomPinned,
>>> +}
>>> +
>>> +impl<T: Handler> Registration<T> {
>>> +    /// Registers the IRQ handler with the system for the given IRQ number. The
>>> +    /// handler must be able to be called as soon as this function returns.
>> 
>> The first line of documentation should be a single sentence description
>> of what the item does. It will get rendered next to it on the summary &
>> search pages.
>
> Right, I actually rendered the docs before submitting, but apparently I missed this.
>
>> 
>> What is meant by the second sentence? What about this phrasing?: "The
>> handler might be called immediately after this function returns.".
>
> It's a reminder, inherited from the C side, that literally as soon as
> request_irq() returns, your handler may be called. Anything that you need to
> setup before your handler can run must already have been done by this point.
>
> Is this the “second sentence” you are referring to?

Yes. The sentence was worded in a weird way, since in Rust, I would
normally expect that anything can happen to a value, if I give up
ownership.

Also it is not true, since the code in the function body is only run
once you use the initializer, so running this code doesn't do anything:

    let handler = ...;
    let flags = ...;
    let irg = ...;
    

    let reg = Registration::register(irq, flags, cstr!("foo"), handler);

    // the registration is not yet created, only an initializer for a registration.

    let reg = Arc::pin_init(reg);

    // now the registration has been created and the handler can be called.

>>> +    pub fn register(
>>> +        irq: u32,
>>> +        flags: Flags,
>>> +        name: &'static CStr,
>>> +        handler: T,
>>> +    ) -> impl PinInit<Self, Error> {

>>> +/// The value that can be returned from `ThreadedHandler::handle_irq`.
>>> +#[repr(u32)]
>>> +pub enum ThreadedIrqReturn {
>>> +    /// The interrupt was not from this device or was not handled.
>>> +    None = bindings::irqreturn_IRQ_NONE,
>>> +
>>> +    /// The interrupt was handled by this device.
>>> +    Handled = bindings::irqreturn_IRQ_HANDLED,
>>> +
>>> +    /// The handler wants the handler thread to wake up.
>> 
>> How about "The handler wants the handler thread to take care of the
>> interrupt." or is that incorrect?
>
> This is taken straight from the C docs. As I told Andreas, I’d prefer if we
> didn’t add our own docs for C things that have their own docs already.

Fine with me, but we could also change the C docs :)

>>> +///     // This will run (in a separate kthread) if and only if `handle_irq`
>>> +///     // returns `WakeThread`.
>>> +///     fn thread_fn(&self) -> IrqReturn {
>>> +///         // We now have exclusive access to the data by locking the SpinLock.
>>> +///         //
>>> +///         // Ideally, we should disable interrupts while we are doing this to
>>> +///         // avoid deadlocks, but this is not currently possible.
>> 
>> Would this be solved by SpinLockIrq?
>
>
> Yes, that is the point of SpinLockIrq. The exact syntax is still up for debate,
> although by this time I think Lyude & Boqun have already settled on something.

I also was part of the discussion at some point, but dropped out & was
busy with other things. I'll move it up in my todo-list.

---
Cheers,
Benno

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ