xref: /linux/rust/kernel/debugfs.rs (revision 7f201ca18c825592e392596a2fca2374dd2a4dfe)
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