On Thu Dec 18, 2025 at 2:39 AM CET, Timur Tabi wrote:
> Create the 'nova_core' root debugfs entry when the driver loads.
> The Dir entry is part of the NovaCoreModule, so when the module
> unloads, the NovaCoreModule object is dropped, and that drops the
> _debugfs_root, which automatically deletes the debugfs file.
>
> Field order in Rust structs determines drop order - fields are dropped
> in declaration order. By placing _driver before _debugfs_root:
>
> 1. The driver registration is dropped first, which removes all PCI
> devices and their associated debugfs subdirectories
> 2. Then _debugfs_root is dropped, removing the now-empty nova_core
> directory
>
> This ordering is critical because debugfs_remove() performs recursive
> removal. If the parent directory were removed first, it would free the
> child dentries, and then the child's drop would attempt to remove an
> already-freed dentry, causing a use-after-free crash.
>
> Signed-off-by: Timur Tabi <[email protected]>
> ---
> drivers/gpu/nova-core/nova_core.rs | 12 +++++++++---
> 1 file changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/nova_core.rs
> b/drivers/gpu/nova-core/nova_core.rs
> index 01353be103ca..f17505e5e2b3 100644
> --- a/drivers/gpu/nova-core/nova_core.rs
> +++ b/drivers/gpu/nova-core/nova_core.rs
> @@ -2,8 +2,7 @@
>
> //! Nova Core GPU Driver
>
> -use kernel::{error::Error, pci, prelude::*, InPlaceModule};
> -use pin_init::{PinInit, pinned_drop};
> +use kernel::{debugfs::Dir, error::Error, pci, prelude::*, InPlaceModule};
Again, please use kernel vertical style.
>
> #[macro_use]
> mod bitfield;
> @@ -24,17 +23,24 @@
>
> pub(crate) const MODULE_NAME: &kernel::str::CStr = <LocalModule as
> kernel::ModuleMetadata>::NAME;
>
> -#[pin_data(PinnedDrop)]
> +#[pin_data]
> struct NovaCoreModule {
> + // Note: field order matters for drop order. The driver must be dropped
> before
> + // the debugfs directory so that device subdirectories are removed first.
This is not correct, subdirectories have a reference count of their parent
directory. Hence, the drop order does not matter.
> #[pin]
> _driver: kernel::driver::Registration<pci::Adapter<driver::NovaCore>>,
> + _debugfs_root: Dir,
> }
>
> impl InPlaceModule for NovaCoreModule {
> fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self,
> Error> {
> pr_info!("NovaCore GPU driver loaded\n");
> +
> + let debugfs_root = Dir::new(kernel::c_str!("nova_core"));
I'd just inline this statement below.
> +
> try_pin_init!(Self {
> _driver <- kernel::driver::Registration::new(MODULE_NAME,
> module),
> + _debugfs_root: debugfs_root,
> })
> }
> }
> --
> 2.52.0