All of lore.kernel.org
 help / color / mirror / Atom feed
From: Boqun Feng <boqun.feng@gmail.com>
To: Alice Ryhl <aliceryhl@google.com>
Cc: "Daniel Almeida" <daniel.almeida@collabora.com>,
	"Miguel Ojeda" <ojeda@kernel.org>, "Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	"Thomas Gleixner" <tglx@linutronix.de>,
	"Bjorn Helgaas" <bhelgaas@google.com>,
	"Krzysztof Wilczy´nski" <kwilczynski@kernel.org>,
	"Benno Lossin" <lossin@kernel.org>,
	"Dirk Behme" <dirk.behme@gmail.com>,
	linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
	linux-pci@vger.kernel.org
Subject: Re: [PATCH v2] rust: irq: add &Device<Bound> argument to irq callbacks
Date: Mon, 11 Aug 2025 07:24:51 -0700	[thread overview]
Message-ID: <aJn9M3WPcI_ZGems@Mac.home> (raw)
In-Reply-To: <CAH5fLghitfmSOByu4ZRmhwdsOadzJOLei_qrAjNM+V15spq44w@mail.gmail.com>

On Mon, Aug 11, 2025 at 04:05:31PM +0200, Alice Ryhl wrote:
> On Mon, Aug 11, 2025 at 3:56 PM Boqun Feng <boqun.feng@gmail.com> wrote:
> >
> > On Mon, Aug 11, 2025 at 12:33:51PM +0000, Alice Ryhl wrote:
> > [...]
> > > @@ -207,8 +207,8 @@ pub fn new<'a>(
> > >              inner <- Devres::new(
> > >                  request.dev,
> > >                  try_pin_init!(RegistrationInner {
> > > -                    // SAFETY: `this` is a valid pointer to the `Registration` instance
> > > -                    cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(),
> > > +                    // INVARIANT: `this` is a valid pointer to the `Registration` instance
> > > +                    cookie: this.as_ptr().cast::<c_void>(),
> >
> > At this moment the `Regstration` is not fully initialized...
> >
> > >                      irq: {
> > >                          // SAFETY:
> > >                          // - The callbacks are valid for use with request_irq.
> > > @@ -221,7 +221,7 @@ pub fn new<'a>(
> > >                                  Some(handle_irq_callback::<T>),
> > >                                  flags.into_inner(),
> > >                                  name.as_char_ptr(),
> > > -                                (&raw mut (*this.as_ptr()).handler).cast(),
> > > +                                this.as_ptr().cast::<c_void>(),
> > >                              )
> >
> > ... and interrupt can happen right after request_irq() ...
> >
> > >                          })?;
> > >                          request.irq
> > > @@ -258,9 +258,13 @@ pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
> > >  ///
> > >  /// This function should be only used as the callback in `request_irq`.
> > >  unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint {
> > > -    // SAFETY: `ptr` is a pointer to T set in `Registration::new`
> > > -    let handler = unsafe { &*(ptr as *const T) };
> > > -    T::handle(handler) as c_uint
> > > +    // SAFETY: `ptr` is a pointer to `Registration<T>` set in `Registration::new`
> > > +    let registration = unsafe { &*(ptr as *const Registration<T>) };
> >
> > ... hence it's not correct to construct a reference to `Registration`
> > here, but yes, both `handler` and the `device` part of `inner` has been
> > properly initialized. So
> >
> >         let registration = ptr.cast::<Registration<T>>();
> >
> >         // SAFETY: The `data` part of `Devres` is `Opaque` and here we
> >         // only access `.device()`, which has been properly initialized
> >         // before `request_irq()`.
> >         let device = unsafe { (*registration).inner.device() };
> >
> >         // SAFETY: The irq callback is removed before the device is
> >         // unbound, so the fact that the irq callback is running implies
> >         // that the device has not yet been unbound.
> >         let device = unsafe { device.as_bound() };
> >
> >         // SAFETY: `.handler` has been properly initialized before
> >         // `request_irq()`.
> >         T::handle(unsafe { &(*registration).handler }, device) as c_uint
> >
> > Thoughts? Similar for the threaded one.
> 
> This code is no different. It creates a reference to `inner` before
> the `irq` field is written. Of course, it's also no different in that
> since data of a `Devres` is in `Opaque`, this is not actually UB.
> 

Well, I think we need at least mentioning that it's safe because we
don't access .inner.inner here, but..

> What I can offer you is to use the closure form of pin-init to call
> request_irq after initialization has fully completed.
> 

.. now you mention this, I think we can just move the `request_irq()`
to the initializer of `_pin`:

------>8
diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs
index ae5d967fb9d6..3343964fc1ab 100644
--- a/rust/kernel/irq/request.rs
+++ b/rust/kernel/irq/request.rs
@@ -209,26 +209,26 @@ pub fn new<'a>(
                 try_pin_init!(RegistrationInner {
                     // INVARIANT: `this` is a valid pointer to the `Registration` instance
                     cookie: this.as_ptr().cast::<c_void>(),
-                    irq: {
-                        // SAFETY:
-                        // - The callbacks are valid for use with request_irq.
-                        // - If this succeeds, the slot is guaranteed to be valid until the
-                        //   destructor of Self runs, which will deregister the callbacks
-                        //   before the memory location becomes invalid.
-                        to_result(unsafe {
-                            bindings::request_irq(
-                                request.irq,
-                                Some(handle_irq_callback::<T>),
-                                flags.into_inner(),
-                                name.as_char_ptr(),
-                                this.as_ptr().cast::<c_void>(),
-                            )
-                        })?;
-                        request.irq
-                    }
+                    irq: request.irq
                 })
             ),
-            _pin: PhantomPinned,
+            _pin: {
+                // SAFETY:
+                // - The callbacks are valid for use with request_irq.
+                // - If this succeeds, the slot is guaranteed to be valid until the
+                //   destructor of Self runs, which will deregister the callbacks
+                //   before the memory location becomes invalid.
+                to_result(unsafe {
+                    bindings::request_irq(
+                        request.irq,
+                        Some(handle_irq_callback::<T>),
+                        flags.into_inner(),
+                        name.as_char_ptr(),
+                        this.as_ptr().cast::<c_void>(),
+                    )
+                })?;
+                PhantomPinned
+            },
         })
     }


Thoughts?

Regards,
Boqun

  reply	other threads:[~2025-08-11 14:24 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-11 12:33 [PATCH v2] rust: irq: add &Device<Bound> argument to irq callbacks Alice Ryhl
2025-08-11 12:38 ` Daniel Almeida
2025-08-11 13:56 ` Boqun Feng
2025-08-11 14:05   ` Alice Ryhl
2025-08-11 14:24     ` Boqun Feng [this message]
2025-08-11 14:25       ` Alice Ryhl
2025-08-11 14:31         ` Boqun Feng
2025-08-11 14:37           ` Alice Ryhl
2025-08-11 14:57             ` Boqun Feng

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=aJn9M3WPcI_ZGems@Mac.home \
    --to=boqun.feng@gmail.com \
    --cc=a.hindborg@kernel.org \
    --cc=aliceryhl@google.com \
    --cc=bhelgaas@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=dirk.behme@gmail.com \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=kwilczynski@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rafael@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tglx@linutronix.de \
    --cc=tmgross@umich.edu \
    /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.