1*7f201ca1SMatthew Maurer // SPDX-License-Identifier: GPL-2.0 2*7f201ca1SMatthew Maurer // Copyright (C) 2025 Google LLC. 3*7f201ca1SMatthew Maurer 4*7f201ca1SMatthew Maurer //! DebugFS Abstraction 5*7f201ca1SMatthew Maurer //! 6*7f201ca1SMatthew Maurer //! C header: [`include/linux/debugfs.h`](srctree/include/linux/debugfs.h) 7*7f201ca1SMatthew Maurer 8*7f201ca1SMatthew Maurer // When DebugFS is disabled, many parameters are dead. Linting for this isn't helpful. 9*7f201ca1SMatthew Maurer #![cfg_attr(not(CONFIG_DEBUG_FS), allow(unused_variables))] 10*7f201ca1SMatthew Maurer 11*7f201ca1SMatthew Maurer #[cfg(CONFIG_DEBUG_FS)] 12*7f201ca1SMatthew Maurer use crate::prelude::*; 13*7f201ca1SMatthew Maurer use crate::str::CStr; 14*7f201ca1SMatthew Maurer #[cfg(CONFIG_DEBUG_FS)] 15*7f201ca1SMatthew Maurer use crate::sync::Arc; 16*7f201ca1SMatthew Maurer 17*7f201ca1SMatthew Maurer #[cfg(CONFIG_DEBUG_FS)] 18*7f201ca1SMatthew Maurer mod entry; 19*7f201ca1SMatthew Maurer #[cfg(CONFIG_DEBUG_FS)] 20*7f201ca1SMatthew Maurer use entry::Entry; 21*7f201ca1SMatthew Maurer 22*7f201ca1SMatthew Maurer /// Owning handle to a DebugFS directory. 23*7f201ca1SMatthew Maurer /// 24*7f201ca1SMatthew Maurer /// The directory in the filesystem represented by [`Dir`] will be removed when handle has been 25*7f201ca1SMatthew Maurer /// dropped *and* all children have been removed. 26*7f201ca1SMatthew Maurer // If we have a parent, we hold a reference to it in the `Entry`. This prevents the `dentry` 27*7f201ca1SMatthew Maurer // we point to from being cleaned up if our parent `Dir`/`Entry` is dropped before us. 28*7f201ca1SMatthew Maurer // 29*7f201ca1SMatthew Maurer // The `None` option indicates that the `Arc` could not be allocated, so our children would not be 30*7f201ca1SMatthew Maurer // able to refer to us. In this case, we need to silently fail. All future child directories/files 31*7f201ca1SMatthew Maurer // will silently fail as well. 32*7f201ca1SMatthew Maurer #[derive(Clone)] 33*7f201ca1SMatthew Maurer pub struct Dir(#[cfg(CONFIG_DEBUG_FS)] Option<Arc<Entry>>); 34*7f201ca1SMatthew Maurer 35*7f201ca1SMatthew Maurer impl Dir { 36*7f201ca1SMatthew Maurer /// Create a new directory in DebugFS. If `parent` is [`None`], it will be created at the root. 37*7f201ca1SMatthew Maurer fn create(name: &CStr, parent: Option<&Dir>) -> Self { 38*7f201ca1SMatthew Maurer #[cfg(CONFIG_DEBUG_FS)] 39*7f201ca1SMatthew Maurer { 40*7f201ca1SMatthew Maurer let parent_entry = match parent { 41*7f201ca1SMatthew Maurer // If the parent couldn't be allocated, just early-return 42*7f201ca1SMatthew Maurer Some(Dir(None)) => return Self(None), 43*7f201ca1SMatthew Maurer Some(Dir(Some(entry))) => Some(entry.clone()), 44*7f201ca1SMatthew Maurer None => None, 45*7f201ca1SMatthew Maurer }; 46*7f201ca1SMatthew Maurer Self( 47*7f201ca1SMatthew Maurer // If Arc creation fails, the `Entry` will be dropped, so the directory will be 48*7f201ca1SMatthew Maurer // cleaned up. 49*7f201ca1SMatthew Maurer Arc::new(Entry::dynamic_dir(name, parent_entry), GFP_KERNEL).ok(), 50*7f201ca1SMatthew Maurer ) 51*7f201ca1SMatthew Maurer } 52*7f201ca1SMatthew Maurer #[cfg(not(CONFIG_DEBUG_FS))] 53*7f201ca1SMatthew Maurer Self() 54*7f201ca1SMatthew Maurer } 55*7f201ca1SMatthew Maurer 56*7f201ca1SMatthew Maurer /// Create a new directory in DebugFS at the root. 57*7f201ca1SMatthew Maurer /// 58*7f201ca1SMatthew Maurer /// # Examples 59*7f201ca1SMatthew Maurer /// 60*7f201ca1SMatthew Maurer /// ``` 61*7f201ca1SMatthew Maurer /// # use kernel::c_str; 62*7f201ca1SMatthew Maurer /// # use kernel::debugfs::Dir; 63*7f201ca1SMatthew Maurer /// let debugfs = Dir::new(c_str!("parent")); 64*7f201ca1SMatthew Maurer /// ``` 65*7f201ca1SMatthew Maurer pub fn new(name: &CStr) -> Self { 66*7f201ca1SMatthew Maurer Dir::create(name, None) 67*7f201ca1SMatthew Maurer } 68*7f201ca1SMatthew Maurer 69*7f201ca1SMatthew Maurer /// Creates a subdirectory within this directory. 70*7f201ca1SMatthew Maurer /// 71*7f201ca1SMatthew Maurer /// # Examples 72*7f201ca1SMatthew Maurer /// 73*7f201ca1SMatthew Maurer /// ``` 74*7f201ca1SMatthew Maurer /// # use kernel::c_str; 75*7f201ca1SMatthew Maurer /// # use kernel::debugfs::Dir; 76*7f201ca1SMatthew Maurer /// let parent = Dir::new(c_str!("parent")); 77*7f201ca1SMatthew Maurer /// let child = parent.subdir(c_str!("child")); 78*7f201ca1SMatthew Maurer /// ``` 79*7f201ca1SMatthew Maurer pub fn subdir(&self, name: &CStr) -> Self { 80*7f201ca1SMatthew Maurer Dir::create(name, Some(self)) 81*7f201ca1SMatthew Maurer } 82*7f201ca1SMatthew Maurer } 83