xref: /linux/rust/kernel/debugfs.rs (revision 40ecc49466c8b7f9518c5fbbcfb24cb7e26c36c7)
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 use crate::prelude::*;
12 use crate::str::CStr;
13 #[cfg(CONFIG_DEBUG_FS)]
14 use crate::sync::Arc;
15 use crate::uaccess::UserSliceReader;
16 use core::fmt;
17 use core::marker::PhantomPinned;
18 use core::ops::Deref;
19 
20 mod traits;
21 pub use traits::{Reader, Writer};
22 
23 mod callback_adapters;
24 use callback_adapters::{FormatAdapter, NoWriter, WritableAdapter};
25 mod file_ops;
26 use file_ops::{FileOps, ReadFile, ReadWriteFile, WriteFile};
27 #[cfg(CONFIG_DEBUG_FS)]
28 mod entry;
29 #[cfg(CONFIG_DEBUG_FS)]
30 use entry::Entry;
31 
32 /// Owning handle to a DebugFS directory.
33 ///
34 /// The directory in the filesystem represented by [`Dir`] will be removed when handle has been
35 /// dropped *and* all children have been removed.
36 // If we have a parent, we hold a reference to it in the `Entry`. This prevents the `dentry`
37 // we point to from being cleaned up if our parent `Dir`/`Entry` is dropped before us.
38 //
39 // The `None` option indicates that the `Arc` could not be allocated, so our children would not be
40 // able to refer to us. In this case, we need to silently fail. All future child directories/files
41 // will silently fail as well.
42 #[derive(Clone)]
43 pub struct Dir(#[cfg(CONFIG_DEBUG_FS)] Option<Arc<Entry>>);
44 
45 impl Dir {
46     /// Create a new directory in DebugFS. If `parent` is [`None`], it will be created at the root.
47     fn create(name: &CStr, parent: Option<&Dir>) -> Self {
48         #[cfg(CONFIG_DEBUG_FS)]
49         {
50             let parent_entry = match parent {
51                 // If the parent couldn't be allocated, just early-return
52                 Some(Dir(None)) => return Self(None),
53                 Some(Dir(Some(entry))) => Some(entry.clone()),
54                 None => None,
55             };
56             Self(
57                 // If Arc creation fails, the `Entry` will be dropped, so the directory will be
58                 // cleaned up.
59                 Arc::new(Entry::dynamic_dir(name, parent_entry), GFP_KERNEL).ok(),
60             )
61         }
62         #[cfg(not(CONFIG_DEBUG_FS))]
63         Self()
64     }
65 
66     /// Creates a DebugFS file which will own the data produced by the initializer provided in
67     /// `data`.
68     fn create_file<'a, T, E: 'a>(
69         &'a self,
70         name: &'a CStr,
71         data: impl PinInit<T, E> + 'a,
72         file_ops: &'static FileOps<T>,
73     ) -> impl PinInit<File<T>, E> + 'a
74     where
75         T: Sync + 'static,
76     {
77         let scope = Scope::<T>::new(data, move |data| {
78             #[cfg(CONFIG_DEBUG_FS)]
79             if let Some(parent) = &self.0 {
80                 // SAFETY: Because data derives from a scope, and our entry will be dropped before
81                 // the data is dropped, it is guaranteed to outlive the entry we return.
82                 unsafe { Entry::dynamic_file(name, parent.clone(), data, file_ops) }
83             } else {
84                 Entry::empty()
85             }
86         });
87         try_pin_init! {
88             File {
89                 scope <- scope
90             } ? E
91         }
92     }
93 
94     /// Create a new directory in DebugFS at the root.
95     ///
96     /// # Examples
97     ///
98     /// ```
99     /// # use kernel::c_str;
100     /// # use kernel::debugfs::Dir;
101     /// let debugfs = Dir::new(c_str!("parent"));
102     /// ```
103     pub fn new(name: &CStr) -> Self {
104         Dir::create(name, None)
105     }
106 
107     /// Creates a subdirectory within this directory.
108     ///
109     /// # Examples
110     ///
111     /// ```
112     /// # use kernel::c_str;
113     /// # use kernel::debugfs::Dir;
114     /// let parent = Dir::new(c_str!("parent"));
115     /// let child = parent.subdir(c_str!("child"));
116     /// ```
117     pub fn subdir(&self, name: &CStr) -> Self {
118         Dir::create(name, Some(self))
119     }
120 
121     /// Creates a read-only file in this directory.
122     ///
123     /// The file's contents are produced by invoking [`Writer::write`] on the value initialized by
124     /// `data`.
125     ///
126     /// # Examples
127     ///
128     /// ```
129     /// # use kernel::c_str;
130     /// # use kernel::debugfs::Dir;
131     /// # use kernel::prelude::*;
132     /// # let dir = Dir::new(c_str!("my_debugfs_dir"));
133     /// let file = KBox::pin_init(dir.read_only_file(c_str!("foo"), 200), GFP_KERNEL)?;
134     /// // "my_debugfs_dir/foo" now contains the number 200.
135     /// // The file is removed when `file` is dropped.
136     /// # Ok::<(), Error>(())
137     /// ```
138     pub fn read_only_file<'a, T, E: 'a>(
139         &'a self,
140         name: &'a CStr,
141         data: impl PinInit<T, E> + 'a,
142     ) -> impl PinInit<File<T>, E> + 'a
143     where
144         T: Writer + Send + Sync + 'static,
145     {
146         let file_ops = &<T as ReadFile<_>>::FILE_OPS;
147         self.create_file(name, data, file_ops)
148     }
149 
150     /// Creates a read-only file in this directory, with contents from a callback.
151     ///
152     /// `f` must be a function item or a non-capturing closure.
153     /// This is statically asserted and not a safety requirement.
154     ///
155     /// # Examples
156     ///
157     /// ```
158     /// # use core::sync::atomic::{AtomicU32, Ordering};
159     /// # use kernel::c_str;
160     /// # use kernel::debugfs::Dir;
161     /// # use kernel::prelude::*;
162     /// # let dir = Dir::new(c_str!("foo"));
163     /// let file = KBox::pin_init(
164     ///     dir.read_callback_file(c_str!("bar"),
165     ///     AtomicU32::new(3),
166     ///     &|val, f| {
167     ///       let out = val.load(Ordering::Relaxed);
168     ///       writeln!(f, "{out:#010x}")
169     ///     }),
170     ///     GFP_KERNEL)?;
171     /// // Reading "foo/bar" will show "0x00000003".
172     /// file.store(10, Ordering::Relaxed);
173     /// // Reading "foo/bar" will now show "0x0000000a".
174     /// # Ok::<(), Error>(())
175     /// ```
176     pub fn read_callback_file<'a, T, E: 'a, F>(
177         &'a self,
178         name: &'a CStr,
179         data: impl PinInit<T, E> + 'a,
180         _f: &'static F,
181     ) -> impl PinInit<File<T>, E> + 'a
182     where
183         T: Send + Sync + 'static,
184         F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result + Send + Sync,
185     {
186         let file_ops = <FormatAdapter<T, F>>::FILE_OPS.adapt();
187         self.create_file(name, data, file_ops)
188     }
189 
190     /// Creates a read-write file in this directory.
191     ///
192     /// Reading the file uses the [`Writer`] implementation.
193     /// Writing to the file uses the [`Reader`] implementation.
194     pub fn read_write_file<'a, T, E: 'a>(
195         &'a self,
196         name: &'a CStr,
197         data: impl PinInit<T, E> + 'a,
198     ) -> impl PinInit<File<T>, E> + 'a
199     where
200         T: Writer + Reader + Send + Sync + 'static,
201     {
202         let file_ops = &<T as ReadWriteFile<_>>::FILE_OPS;
203         self.create_file(name, data, file_ops)
204     }
205 
206     /// Creates a read-write file in this directory, with logic from callbacks.
207     ///
208     /// Reading from the file is handled by `f`. Writing to the file is handled by `w`.
209     ///
210     /// `f` and `w` must be function items or non-capturing closures.
211     /// This is statically asserted and not a safety requirement.
212     pub fn read_write_callback_file<'a, T, E: 'a, F, W>(
213         &'a self,
214         name: &'a CStr,
215         data: impl PinInit<T, E> + 'a,
216         _f: &'static F,
217         _w: &'static W,
218     ) -> impl PinInit<File<T>, E> + 'a
219     where
220         T: Send + Sync + 'static,
221         F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result + Send + Sync,
222         W: Fn(&T, &mut UserSliceReader) -> Result + Send + Sync,
223     {
224         let file_ops =
225             <WritableAdapter<FormatAdapter<T, F>, W> as file_ops::ReadWriteFile<_>>::FILE_OPS
226                 .adapt()
227                 .adapt();
228         self.create_file(name, data, file_ops)
229     }
230 
231     /// Creates a write-only file in this directory.
232     ///
233     /// The file owns its backing data. Writing to the file uses the [`Reader`]
234     /// implementation.
235     ///
236     /// The file is removed when the returned [`File`] is dropped.
237     pub fn write_only_file<'a, T, E: 'a>(
238         &'a self,
239         name: &'a CStr,
240         data: impl PinInit<T, E> + 'a,
241     ) -> impl PinInit<File<T>, E> + 'a
242     where
243         T: Reader + Send + Sync + 'static,
244     {
245         self.create_file(name, data, &T::FILE_OPS)
246     }
247 
248     /// Creates a write-only file in this directory, with write logic from a callback.
249     ///
250     /// `w` must be a function item or a non-capturing closure.
251     /// This is statically asserted and not a safety requirement.
252     pub fn write_callback_file<'a, T, E: 'a, W>(
253         &'a self,
254         name: &'a CStr,
255         data: impl PinInit<T, E> + 'a,
256         _w: &'static W,
257     ) -> impl PinInit<File<T>, E> + 'a
258     where
259         T: Send + Sync + 'static,
260         W: Fn(&T, &mut UserSliceReader) -> Result + Send + Sync,
261     {
262         let file_ops = <WritableAdapter<NoWriter<T>, W> as WriteFile<_>>::FILE_OPS
263             .adapt()
264             .adapt();
265         self.create_file(name, data, file_ops)
266     }
267 }
268 
269 #[pin_data]
270 /// Handle to a DebugFS scope, which ensures that attached `data` will outlive the provided
271 /// [`Entry`] without moving.
272 /// Currently, this is used to back [`File`] so that its `read` and/or `write` implementations
273 /// can assume that their backing data is still alive.
274 struct Scope<T> {
275     // This order is load-bearing for drops - `_entry` must be dropped before `data`.
276     #[cfg(CONFIG_DEBUG_FS)]
277     _entry: Entry,
278     #[pin]
279     data: T,
280     // Even if `T` is `Unpin`, we still can't allow it to be moved.
281     #[pin]
282     _pin: PhantomPinned,
283 }
284 
285 #[pin_data]
286 /// Handle to a DebugFS file, owning its backing data.
287 ///
288 /// When dropped, the DebugFS file will be removed and the attached data will be dropped.
289 pub struct File<T> {
290     #[pin]
291     scope: Scope<T>,
292 }
293 
294 #[cfg(not(CONFIG_DEBUG_FS))]
295 impl<'b, T: 'b> Scope<T> {
296     fn new<E: 'b, F>(data: impl PinInit<T, E> + 'b, init: F) -> impl PinInit<Self, E> + 'b
297     where
298         F: for<'a> FnOnce(&'a T) + 'b,
299     {
300         try_pin_init! {
301             Self {
302                 data <- data,
303                 _pin: PhantomPinned
304             } ? E
305         }
306         .pin_chain(|scope| {
307             init(&scope.data);
308             Ok(())
309         })
310     }
311 }
312 
313 #[cfg(CONFIG_DEBUG_FS)]
314 impl<'b, T: 'b> Scope<T> {
315     fn entry_mut(self: Pin<&mut Self>) -> &mut Entry {
316         // SAFETY: _entry is not structurally pinned.
317         unsafe { &mut Pin::into_inner_unchecked(self)._entry }
318     }
319 
320     fn new<E: 'b, F>(data: impl PinInit<T, E> + 'b, init: F) -> impl PinInit<Self, E> + 'b
321     where
322         F: for<'a> FnOnce(&'a T) -> Entry + 'b,
323     {
324         try_pin_init! {
325             Self {
326                 _entry: Entry::empty(),
327                 data <- data,
328                 _pin: PhantomPinned
329             } ? E
330         }
331         .pin_chain(|scope| {
332             *scope.entry_mut() = init(&scope.data);
333             Ok(())
334         })
335     }
336 }
337 
338 impl<T> Deref for Scope<T> {
339     type Target = T;
340     fn deref(&self) -> &T {
341         &self.data
342     }
343 }
344 
345 impl<T> Deref for File<T> {
346     type Target = T;
347     fn deref(&self) -> &T {
348         &self.scope
349     }
350 }
351