From: "Alexandre Courbot" <acourbot@nvidia.com>
To: "Vladislav Zaharov" <vladazaharova2018@gmail.com>
Cc: <dakr@kernel.org>, <jhubbard@nvidia.com>, <aliceryhl@google.com>,
<ttabi@nvidia.com>, <gary@garyguo.net>,
<nova-gpu@lists.linux.dev>, <dri-devel@lists.freedesktop.org>,
<linux-kernel@vger.kernel.org>, <linux-doc@vger.kernel.org>
Subject: Re: [PATCH v6 1/3] gpu: nova-core: move the debugfs root into the module data
Date: Sat, 07 Nov 2026 15:47:47 +0900 [thread overview]
Message-ID: <DMOS00OZYWU5.2SUZRN37DEH87@nvidia.com> (raw)
In-Reply-To: <20261014154554.231015-2-vladazaharova2018@gmail.com>
On Thu Oct 15, 2026 at 12:45 AM JST, Vladislav Zaharov wrote:
<...>
> diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
> index a8f6dc22057b..ee3a6600f320 100644
> --- a/drivers/gpu/nova-core/nova_core.rs
> +++ b/drivers/gpu/nova-core/nova_core.rs
> @@ -4,6 +4,7 @@
>
> use kernel::{
> debugfs,
> + device,
> driver::Registration,
> pci,
> prelude::*,
> @@ -32,40 +33,75 @@
>
> pub(crate) const MODULE_NAME: &core::ffi::CStr = <LocalModule as kernel::ModuleMetadata>::NAME;
>
> -// TODO: Move this into per-module data once that exists.
> -static mut DEBUGFS_ROOT: Option<debugfs::Dir> = None;
> +/// Pointer to the [`DebugfsData`] the module owns.
> +///
> +/// A device has no way to reach the data of its module, so code running on behalf of a bound
> +/// device goes through here instead.
> +///
> +/// Written once, while the module data is built, and never again: what it points at is dropped
> +/// only after the driver is unregistered, so it is good for as long as any device is bound, and
> +/// is not read outside of that.
> +// TODO: Drop this once devices can reach the data of their module.
> +static mut DEBUGFS_DATA: *const DebugfsData = core::ptr::null();
>
> -/// Guard that clears `DEBUGFS_ROOT` when dropped.
> -struct DebugfsRootGuard;
> +/// Data the module shares with every GPU it drives.
> +///
> +/// Reached from a device through [`debugfs_data()`].
> +#[pin_data]
> +pub(crate) struct DebugfsData {
> + /// Root directory of the driver in debugfs.
> + root: debugfs::Dir,
> +}
> +
> +impl DebugfsData {
> + /// Creates the shared data.
> + fn new() -> impl PinInit<Self> {
> + pin_init!(Self {
> + root: debugfs::Dir::new(c"nova-core"),
> + })
> + }
Another thing: since this is declaring now a proper interface, can you
move `DebugfsData`, `debugfs_data` and `DEBUGFS_DATA` into a sub-module,
say `debugfs.rs`? This will keep the root module free of clutter and
keep all the debugfs-related setup under a single module.
Tring doing that locally also made me notice another potential
improvement, see below.
>
> -impl Drop for DebugfsRootGuard {
> - fn drop(&mut self) {
> - // SAFETY: This guard is dropped after `_driver` (due to field order),
> - // so the driver is unregistered and no probe() can be running.
> - unsafe { DEBUGFS_ROOT = None };
> + /// Returns the root directory of the driver in debugfs.
> + pub(crate) fn root(&self) -> &debugfs::Dir {
> + &self.root
> }
> }
>
> +/// Returns the data the module shares with its devices.
> +///
> +/// The bound device is what makes this sound: the data is built before the driver is registered
> +/// and dropped after it is unregistered, so it outlives every device that is bound, and the
> +/// returned reference cannot be held past the one it is taken for.
> +pub(crate) fn debugfs_data<'a>(_dev: &'a device::Device<device::Bound>) -> &'a DebugfsData {
> + // SAFETY: A device can only be bound once the driver is registered, which happens after
> + // `DEBUGFS_DATA` is written, so it points at the data of this module, which lives at least
> + // as long as the caller's device is bound.
> + unsafe { &*DEBUGFS_DATA }
> +}
> +
> #[pin_data]
> struct NovaCoreModule {
> - // Fields are dropped in declaration order, so `_driver` is dropped first,
> - // then `_debugfs_guard` clears `DEBUGFS_ROOT`.
> + // Fields are dropped in declaration order, so the registration goes first and no probe() can
> + // still be running once the shared data is torn down. `init()` builds them the other way
> + // round, as the data has to be there before the first probe() reaches for it.
> #[pin]
> _driver: Registration<pci::Adapter<driver::NovaCoreDriver>>,
> - _debugfs_guard: DebugfsRootGuard,
> + #[pin]
> + _debugfs: DebugfsData,
> }
>
> impl InPlaceModule for NovaCoreModule {
> fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, Error> {
> - let dir = debugfs::Dir::new(c"nova-core");
> -
> - // SAFETY: We are the only driver code running during init, so there
> - // cannot be any concurrent access to `DEBUGFS_ROOT`.
> - unsafe { DEBUGFS_ROOT = Some(dir) };
> -
> try_pin_init!(Self {
> + _debugfs <- DebugfsData::new(),
> + _: {
> + // SAFETY: Nothing reads `DEBUGFS_DATA` before a device is bound, which cannot
> + // happen until the driver is registered below. What it points at is dropped only
> + // once the driver is unregistered, so it is valid for as long as any device is
> + // bound, and nothing reads it outside of that.
> + unsafe { DEBUGFS_DATA = &*_debugfs };
> + },
Let's move this initialization into `DebugfsData::new`, using
`pin_chain`:
/// Returns an initializer that creates the shared debugfs data.
///
/// # Safety
///
/// The returned initializer must be run exactly once before the driver is registered. The
/// initialized [`DebugfsData`] must outlive the driver registration.
pub(super) unsafe fn new() -> impl PinInit<Self> {
pin_init!(Self {
root: debugfs::Dir::new(c"nova-core"),
})
.pin_chain(|debugfs| {
// SAFETY: Per the method's safety block, the driver is not registered yet, meaning that
// no device can be probed and thus nothing can access `DEBUGFS_DATA` concurrently.
//
// INVARIANT: Per the method's safety block, `DEBUGFS_DATA` is written before the driver
// is registered and points to a valid instance of `DebugfsData`, which is pinned
// and dropped after the driver is unregistered.
unsafe { DEBUGFS_DATA = &*debugfs };
Ok(())
})
}
That way, the burden of enforcing the invariants for `DEBUGFS_DATA`
relies exclusively on `new` (and we made it unsafe to force the caller
to do that). The only thing `nova_core` has to take care about is
calling it before the driver is registered, and keeping the result alive
until it is unregistered. Simple and trivial to check since `nova_core`
now doesn't contain any of the debugfs code stuff anymore and literally
fits within one screen worth of code.
next prev parent reply other threads:[~2026-11-07 6:48 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-14 15:45 [PATCH v6 0/3] gpu: nova-core: retain the GSP-RM log buffers Vladislav Zaharov
2026-10-14 15:45 ` [PATCH v6 1/3] gpu: nova-core: move the debugfs root into the module data Vladislav Zaharov
2026-11-07 1:23 ` Alexandre Courbot
2026-11-07 6:47 ` Alexandre Courbot [this message]
2026-11-07 13:14 ` Danilo Krummrich
2026-11-07 13:32 ` Alexandre Courbot
2026-11-07 23:18 ` Danilo Krummrich
2026-10-14 15:45 ` [PATCH v6 2/3] gpu: nova-core: gsp: retain the GSP-RM log buffers after unbind Vladislav Zaharov
2026-11-07 1:26 ` Alexandre Courbot
2026-10-14 15:45 ` [PATCH v6 3/3] Documentation: nova: remove completed GSP log buffer task Vladislav Zaharov
2026-11-06 20:51 ` [PATCH v6 0/3] gpu: nova-core: retain the GSP-RM log buffers Timur Tabi
2026-11-06 22:52 ` Danilo Krummrich
2026-11-06 23:15 ` John Hubbard
2026-11-06 23:08 ` Alexandre Courbot
2026-11-06 23:15 ` Alexandre Courbot
2026-11-07 0:39 ` John Hubbard
2026-11-07 1:38 ` Danilo Krummrich
2026-11-07 1:40 ` John Hubbard
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=DMOS00OZYWU5.2SUZRN37DEH87@nvidia.com \
--to=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=dakr@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=nova-gpu@lists.linux.dev \
--cc=ttabi@nvidia.com \
--cc=vladazaharova2018@gmail.com \
/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.