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