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