xref: /linux/rust/kernel/debugfs/entry.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 use crate::str::CStr;
5*7f201ca1SMatthew Maurer use crate::sync::Arc;
6*7f201ca1SMatthew Maurer 
7*7f201ca1SMatthew Maurer /// Owning handle to a DebugFS entry.
8*7f201ca1SMatthew Maurer ///
9*7f201ca1SMatthew Maurer /// # Invariants
10*7f201ca1SMatthew Maurer ///
11*7f201ca1SMatthew Maurer /// The wrapped pointer will always be `NULL`, an error, or an owned DebugFS `dentry`.
12*7f201ca1SMatthew Maurer pub(crate) struct Entry {
13*7f201ca1SMatthew Maurer     entry: *mut bindings::dentry,
14*7f201ca1SMatthew Maurer     // If we were created with an owning parent, this is the keep-alive
15*7f201ca1SMatthew Maurer     _parent: Option<Arc<Entry>>,
16*7f201ca1SMatthew Maurer }
17*7f201ca1SMatthew Maurer 
18*7f201ca1SMatthew Maurer // SAFETY: [`Entry`] is just a `dentry` under the hood, which the API promises can be transferred
19*7f201ca1SMatthew Maurer // between threads.
20*7f201ca1SMatthew Maurer unsafe impl Send for Entry {}
21*7f201ca1SMatthew Maurer 
22*7f201ca1SMatthew Maurer // SAFETY: All the C functions we call on the `dentry` pointer are threadsafe.
23*7f201ca1SMatthew Maurer unsafe impl Sync for Entry {}
24*7f201ca1SMatthew Maurer 
25*7f201ca1SMatthew Maurer impl Entry {
26*7f201ca1SMatthew Maurer     pub(crate) fn dynamic_dir(name: &CStr, parent: Option<Arc<Self>>) -> Self {
27*7f201ca1SMatthew Maurer         let parent_ptr = match &parent {
28*7f201ca1SMatthew Maurer             Some(entry) => entry.as_ptr(),
29*7f201ca1SMatthew Maurer             None => core::ptr::null_mut(),
30*7f201ca1SMatthew Maurer         };
31*7f201ca1SMatthew Maurer         // SAFETY: The invariants of this function's arguments ensure the safety of this call.
32*7f201ca1SMatthew Maurer         // * `name` is a valid C string by the invariants of `&CStr`.
33*7f201ca1SMatthew Maurer         // * `parent_ptr` is either `NULL` (if `parent` is `None`), or a pointer to a valid
34*7f201ca1SMatthew Maurer         //   `dentry` by our invariant. `debugfs_create_dir` handles `NULL` pointers correctly.
35*7f201ca1SMatthew Maurer         let entry = unsafe { bindings::debugfs_create_dir(name.as_char_ptr(), parent_ptr) };
36*7f201ca1SMatthew Maurer 
37*7f201ca1SMatthew Maurer         Entry {
38*7f201ca1SMatthew Maurer             entry,
39*7f201ca1SMatthew Maurer             _parent: parent,
40*7f201ca1SMatthew Maurer         }
41*7f201ca1SMatthew Maurer     }
42*7f201ca1SMatthew Maurer 
43*7f201ca1SMatthew Maurer     /// Returns the pointer representation of the DebugFS directory.
44*7f201ca1SMatthew Maurer     ///
45*7f201ca1SMatthew Maurer     /// # Guarantees
46*7f201ca1SMatthew Maurer     ///
47*7f201ca1SMatthew Maurer     /// Due to the type invariant, the value returned from this function will always be an error
48*7f201ca1SMatthew Maurer     /// code, NULL, or a live DebugFS directory. If it is live, it will remain live at least as
49*7f201ca1SMatthew Maurer     /// long as this entry lives.
50*7f201ca1SMatthew Maurer     pub(crate) fn as_ptr(&self) -> *mut bindings::dentry {
51*7f201ca1SMatthew Maurer         self.entry
52*7f201ca1SMatthew Maurer     }
53*7f201ca1SMatthew Maurer }
54*7f201ca1SMatthew Maurer 
55*7f201ca1SMatthew Maurer impl Drop for Entry {
56*7f201ca1SMatthew Maurer     fn drop(&mut self) {
57*7f201ca1SMatthew Maurer         // SAFETY: `debugfs_remove` can take `NULL`, error values, and legal DebugFS dentries.
58*7f201ca1SMatthew Maurer         // `as_ptr` guarantees that the pointer is of this form.
59*7f201ca1SMatthew Maurer         unsafe { bindings::debugfs_remove(self.as_ptr()) }
60*7f201ca1SMatthew Maurer     }
61*7f201ca1SMatthew Maurer }
62