xref: /linux/rust/kernel/debugfs/entry.rs (revision 5e40b591cb46c0379d5406fa5548c9b2a3801353)
17f201ca1SMatthew Maurer // SPDX-License-Identifier: GPL-2.0
27f201ca1SMatthew Maurer // Copyright (C) 2025 Google LLC.
37f201ca1SMatthew Maurer 
4*5e40b591SMatthew Maurer use crate::debugfs::file_ops::FileOps;
5*5e40b591SMatthew Maurer use crate::ffi::c_void;
67f201ca1SMatthew Maurer use crate::str::CStr;
77f201ca1SMatthew Maurer use crate::sync::Arc;
87f201ca1SMatthew Maurer 
97f201ca1SMatthew Maurer /// Owning handle to a DebugFS entry.
107f201ca1SMatthew Maurer ///
117f201ca1SMatthew Maurer /// # Invariants
127f201ca1SMatthew Maurer ///
137f201ca1SMatthew Maurer /// The wrapped pointer will always be `NULL`, an error, or an owned DebugFS `dentry`.
147f201ca1SMatthew Maurer pub(crate) struct Entry {
157f201ca1SMatthew Maurer     entry: *mut bindings::dentry,
167f201ca1SMatthew Maurer     // If we were created with an owning parent, this is the keep-alive
177f201ca1SMatthew Maurer     _parent: Option<Arc<Entry>>,
187f201ca1SMatthew Maurer }
197f201ca1SMatthew Maurer 
207f201ca1SMatthew Maurer // SAFETY: [`Entry`] is just a `dentry` under the hood, which the API promises can be transferred
217f201ca1SMatthew Maurer // between threads.
227f201ca1SMatthew Maurer unsafe impl Send for Entry {}
237f201ca1SMatthew Maurer 
247f201ca1SMatthew Maurer // SAFETY: All the C functions we call on the `dentry` pointer are threadsafe.
257f201ca1SMatthew Maurer unsafe impl Sync for Entry {}
267f201ca1SMatthew Maurer 
277f201ca1SMatthew Maurer impl Entry {
287f201ca1SMatthew Maurer     pub(crate) fn dynamic_dir(name: &CStr, parent: Option<Arc<Self>>) -> Self {
297f201ca1SMatthew Maurer         let parent_ptr = match &parent {
307f201ca1SMatthew Maurer             Some(entry) => entry.as_ptr(),
317f201ca1SMatthew Maurer             None => core::ptr::null_mut(),
327f201ca1SMatthew Maurer         };
337f201ca1SMatthew Maurer         // SAFETY: The invariants of this function's arguments ensure the safety of this call.
347f201ca1SMatthew Maurer         // * `name` is a valid C string by the invariants of `&CStr`.
357f201ca1SMatthew Maurer         // * `parent_ptr` is either `NULL` (if `parent` is `None`), or a pointer to a valid
367f201ca1SMatthew Maurer         //   `dentry` by our invariant. `debugfs_create_dir` handles `NULL` pointers correctly.
377f201ca1SMatthew Maurer         let entry = unsafe { bindings::debugfs_create_dir(name.as_char_ptr(), parent_ptr) };
387f201ca1SMatthew Maurer 
397f201ca1SMatthew Maurer         Entry {
407f201ca1SMatthew Maurer             entry,
417f201ca1SMatthew Maurer             _parent: parent,
427f201ca1SMatthew Maurer         }
437f201ca1SMatthew Maurer     }
447f201ca1SMatthew Maurer 
45*5e40b591SMatthew Maurer     /// # Safety
46*5e40b591SMatthew Maurer     ///
47*5e40b591SMatthew Maurer     /// * `data` must outlive the returned `Entry`.
48*5e40b591SMatthew Maurer     pub(crate) unsafe fn dynamic_file<T>(
49*5e40b591SMatthew Maurer         name: &CStr,
50*5e40b591SMatthew Maurer         parent: Arc<Self>,
51*5e40b591SMatthew Maurer         data: &T,
52*5e40b591SMatthew Maurer         file_ops: &'static FileOps<T>,
53*5e40b591SMatthew Maurer     ) -> Self {
54*5e40b591SMatthew Maurer         // SAFETY: The invariants of this function's arguments ensure the safety of this call.
55*5e40b591SMatthew Maurer         // * `name` is a valid C string by the invariants of `&CStr`.
56*5e40b591SMatthew Maurer         // * `parent.as_ptr()` is a pointer to a valid `dentry` by invariant.
57*5e40b591SMatthew Maurer         // * The caller guarantees that `data` will outlive the returned `Entry`.
58*5e40b591SMatthew Maurer         // * The guarantees on `FileOps` assert the vtable will be compatible with the data we have
59*5e40b591SMatthew Maurer         //   provided.
60*5e40b591SMatthew Maurer         let entry = unsafe {
61*5e40b591SMatthew Maurer             bindings::debugfs_create_file_full(
62*5e40b591SMatthew Maurer                 name.as_char_ptr(),
63*5e40b591SMatthew Maurer                 file_ops.mode(),
64*5e40b591SMatthew Maurer                 parent.as_ptr(),
65*5e40b591SMatthew Maurer                 core::ptr::from_ref(data) as *mut c_void,
66*5e40b591SMatthew Maurer                 core::ptr::null(),
67*5e40b591SMatthew Maurer                 &**file_ops,
68*5e40b591SMatthew Maurer             )
69*5e40b591SMatthew Maurer         };
70*5e40b591SMatthew Maurer 
71*5e40b591SMatthew Maurer         Entry {
72*5e40b591SMatthew Maurer             entry,
73*5e40b591SMatthew Maurer             _parent: Some(parent),
74*5e40b591SMatthew Maurer         }
75*5e40b591SMatthew Maurer     }
76*5e40b591SMatthew Maurer 
77*5e40b591SMatthew Maurer     /// Constructs a placeholder DebugFS [`Entry`].
78*5e40b591SMatthew Maurer     pub(crate) fn empty() -> Self {
79*5e40b591SMatthew Maurer         Self {
80*5e40b591SMatthew Maurer             entry: core::ptr::null_mut(),
81*5e40b591SMatthew Maurer             _parent: None,
82*5e40b591SMatthew Maurer         }
83*5e40b591SMatthew Maurer     }
84*5e40b591SMatthew Maurer 
857f201ca1SMatthew Maurer     /// Returns the pointer representation of the DebugFS directory.
867f201ca1SMatthew Maurer     ///
877f201ca1SMatthew Maurer     /// # Guarantees
887f201ca1SMatthew Maurer     ///
897f201ca1SMatthew Maurer     /// Due to the type invariant, the value returned from this function will always be an error
907f201ca1SMatthew Maurer     /// code, NULL, or a live DebugFS directory. If it is live, it will remain live at least as
917f201ca1SMatthew Maurer     /// long as this entry lives.
927f201ca1SMatthew Maurer     pub(crate) fn as_ptr(&self) -> *mut bindings::dentry {
937f201ca1SMatthew Maurer         self.entry
947f201ca1SMatthew Maurer     }
957f201ca1SMatthew Maurer }
967f201ca1SMatthew Maurer 
977f201ca1SMatthew Maurer impl Drop for Entry {
987f201ca1SMatthew Maurer     fn drop(&mut self) {
997f201ca1SMatthew Maurer         // SAFETY: `debugfs_remove` can take `NULL`, error values, and legal DebugFS dentries.
1007f201ca1SMatthew Maurer         // `as_ptr` guarantees that the pointer is of this form.
1017f201ca1SMatthew Maurer         unsafe { bindings::debugfs_remove(self.as_ptr()) }
1027f201ca1SMatthew Maurer     }
1037f201ca1SMatthew Maurer }
104