xref: /linux/rust/kernel/debugfs/traits.rs (revision d05b8e97690fa19be39f0af03e7f117f601b6319)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2025 Google LLC.
3 
4 //! Traits for rendering or updating values exported to DebugFS.
5 
6 use crate::alloc::Allocator;
7 use crate::fs::file;
8 use crate::prelude::*;
9 use crate::sync::Arc;
10 use crate::sync::Mutex;
11 use crate::transmute::{AsBytes, FromBytes};
12 use crate::uaccess::{UserSliceReader, UserSliceWriter};
13 use core::fmt::{self, Debug, Formatter};
14 use core::ops::{Deref, DerefMut};
15 use core::str::FromStr;
16 use core::sync::atomic::{
17     AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64,
18     AtomicU8, AtomicUsize, Ordering,
19 };
20 
21 /// A trait for types that can be written into a string.
22 ///
23 /// This works very similarly to `Debug`, and is automatically implemented if `Debug` is
24 /// implemented for a type. It is also implemented for any writable type inside a `Mutex`.
25 ///
26 /// The derived implementation of `Debug` [may
27 /// change](https://doc.rust-lang.org/std/fmt/trait.Debug.html#stability)
28 /// between Rust versions, so if stability is key for your use case, please implement `Writer`
29 /// explicitly instead.
30 pub trait Writer {
31     /// Formats the value using the given formatter.
32     fn write(&self, f: &mut Formatter<'_>) -> fmt::Result;
33 }
34 
35 impl<T: Writer> Writer for Mutex<T> {
36     fn write(&self, f: &mut Formatter<'_>) -> fmt::Result {
37         self.lock().write(f)
38     }
39 }
40 
41 impl<T: Debug> Writer for T {
42     fn write(&self, f: &mut Formatter<'_>) -> fmt::Result {
43         writeln!(f, "{self:?}")
44     }
45 }
46 
47 /// Trait for types that can be written out as binary.
48 pub trait BinaryWriter {
49     /// Writes the binary form of `self` into `writer`.
50     ///
51     /// `offset` is the requested offset into the binary representation of `self`.
52     ///
53     /// On success, returns the number of bytes written in to `writer`.
54     fn write_to_slice(
55         &self,
56         writer: &mut UserSliceWriter,
57         offset: &mut file::Offset,
58     ) -> Result<usize>;
59 }
60 
61 // Base implementation for any `T: AsBytes`.
62 impl<T: AsBytes> BinaryWriter for T {
63     fn write_to_slice(
64         &self,
65         writer: &mut UserSliceWriter,
66         offset: &mut file::Offset,
67     ) -> Result<usize> {
68         writer.write_slice_file(self.as_bytes(), offset)
69     }
70 }
71 
72 // Delegate for `Mutex<T>`: Support a `T` with an outer mutex.
73 impl<T: BinaryWriter> BinaryWriter for Mutex<T> {
74     fn write_to_slice(
75         &self,
76         writer: &mut UserSliceWriter,
77         offset: &mut file::Offset,
78     ) -> Result<usize> {
79         let guard = self.lock();
80 
81         guard.write_to_slice(writer, offset)
82     }
83 }
84 
85 // Delegate for `Box<T, A>`: Support a `Box<T, A>` with no lock or an inner lock.
86 impl<T, A> BinaryWriter for Box<T, A>
87 where
88     T: BinaryWriter,
89     A: Allocator,
90 {
91     fn write_to_slice(
92         &self,
93         writer: &mut UserSliceWriter,
94         offset: &mut file::Offset,
95     ) -> Result<usize> {
96         self.deref().write_to_slice(writer, offset)
97     }
98 }
99 
100 // Delegate for `Pin<Box<T, A>>`: Support a `Pin<Box<T, A>>` with no lock or an inner lock.
101 impl<T, A> BinaryWriter for Pin<Box<T, A>>
102 where
103     T: BinaryWriter,
104     A: Allocator,
105 {
106     fn write_to_slice(
107         &self,
108         writer: &mut UserSliceWriter,
109         offset: &mut file::Offset,
110     ) -> Result<usize> {
111         self.deref().write_to_slice(writer, offset)
112     }
113 }
114 
115 // Delegate for `Arc<T>`: Support a `Arc<T>` with no lock or an inner lock.
116 impl<T> BinaryWriter for Arc<T>
117 where
118     T: BinaryWriter,
119 {
120     fn write_to_slice(
121         &self,
122         writer: &mut UserSliceWriter,
123         offset: &mut file::Offset,
124     ) -> Result<usize> {
125         self.deref().write_to_slice(writer, offset)
126     }
127 }
128 
129 // Delegate for `Vec<T, A>`.
130 impl<T, A> BinaryWriter for Vec<T, A>
131 where
132     T: AsBytes,
133     A: Allocator,
134 {
135     fn write_to_slice(
136         &self,
137         writer: &mut UserSliceWriter,
138         offset: &mut file::Offset,
139     ) -> Result<usize> {
140         let slice = self.as_slice();
141 
142         // SAFETY: `T: AsBytes` allows us to treat `&[T]` as `&[u8]`.
143         let buffer = unsafe {
144             core::slice::from_raw_parts(slice.as_ptr().cast(), core::mem::size_of_val(slice))
145         };
146 
147         writer.write_slice_file(buffer, offset)
148     }
149 }
150 
151 /// A trait for types that can be updated from a user slice.
152 ///
153 /// This works similarly to `FromStr`, but operates on a `UserSliceReader` rather than a &str.
154 ///
155 /// It is automatically implemented for all atomic integers, or any type that implements `FromStr`
156 /// wrapped in a `Mutex`.
157 pub trait Reader {
158     /// Updates the value from the given user slice.
159     fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result;
160 }
161 
162 impl<T: FromStr> Reader for Mutex<T> {
163     fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result {
164         let mut buf = [0u8; 128];
165         if reader.len() > buf.len() {
166             return Err(EINVAL);
167         }
168         let n = reader.len();
169         reader.read_slice(&mut buf[..n])?;
170 
171         let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?;
172         let val = s.trim().parse::<T>().map_err(|_| EINVAL)?;
173         *self.lock() = val;
174         Ok(())
175     }
176 }
177 
178 /// Trait for types that can be constructed from a binary representation.
179 ///
180 /// See also [`BinaryReader`] for interior mutability.
181 pub trait BinaryReaderMut {
182     /// Reads the binary form of `self` from `reader`.
183     ///
184     /// Same as [`BinaryReader::read_from_slice`], but takes a mutable reference.
185     ///
186     /// `offset` is the requested offset into the binary representation of `self`.
187     ///
188     /// On success, returns the number of bytes read from `reader`.
189     fn read_from_slice_mut(
190         &mut self,
191         reader: &mut UserSliceReader,
192         offset: &mut file::Offset,
193     ) -> Result<usize>;
194 }
195 
196 // Base implementation for any `T: AsBytes + FromBytes`.
197 impl<T: AsBytes + FromBytes> BinaryReaderMut for T {
198     fn read_from_slice_mut(
199         &mut self,
200         reader: &mut UserSliceReader,
201         offset: &mut file::Offset,
202     ) -> Result<usize> {
203         reader.read_slice_file(self.as_bytes_mut(), offset)
204     }
205 }
206 
207 // Delegate for `Box<T, A>`: Support a `Box<T, A>` with an outer lock.
208 impl<T: ?Sized + BinaryReaderMut, A: Allocator> BinaryReaderMut for Box<T, A> {
209     fn read_from_slice_mut(
210         &mut self,
211         reader: &mut UserSliceReader,
212         offset: &mut file::Offset,
213     ) -> Result<usize> {
214         self.deref_mut().read_from_slice_mut(reader, offset)
215     }
216 }
217 
218 // Delegate for `Vec<T, A>`: Support a `Vec<T, A>` with an outer lock.
219 impl<T, A> BinaryReaderMut for Vec<T, A>
220 where
221     T: AsBytes + FromBytes,
222     A: Allocator,
223 {
224     fn read_from_slice_mut(
225         &mut self,
226         reader: &mut UserSliceReader,
227         offset: &mut file::Offset,
228     ) -> Result<usize> {
229         let slice = self.as_mut_slice();
230 
231         // SAFETY: `T: AsBytes + FromBytes` allows us to treat `&mut [T]` as `&mut [u8]`.
232         let buffer = unsafe {
233             core::slice::from_raw_parts_mut(
234                 slice.as_mut_ptr().cast(),
235                 core::mem::size_of_val(slice),
236             )
237         };
238 
239         reader.read_slice_file(buffer, offset)
240     }
241 }
242 
243 /// Trait for types that can be constructed from a binary representation.
244 ///
245 /// See also [`BinaryReaderMut`] for the mutable version.
246 pub trait BinaryReader {
247     /// Reads the binary form of `self` from `reader`.
248     ///
249     /// `offset` is the requested offset into the binary representation of `self`.
250     ///
251     /// On success, returns the number of bytes read from `reader`.
252     fn read_from_slice(
253         &self,
254         reader: &mut UserSliceReader,
255         offset: &mut file::Offset,
256     ) -> Result<usize>;
257 }
258 
259 // Delegate for `Mutex<T>`: Support a `T` with an outer `Mutex`.
260 impl<T: BinaryReaderMut + Unpin> BinaryReader for Mutex<T> {
261     fn read_from_slice(
262         &self,
263         reader: &mut UserSliceReader,
264         offset: &mut file::Offset,
265     ) -> Result<usize> {
266         let mut this = self.lock();
267 
268         this.read_from_slice_mut(reader, offset)
269     }
270 }
271 
272 // Delegate for `Box<T, A>`: Support a `Box<T, A>` with an inner lock.
273 impl<T: ?Sized + BinaryReader, A: Allocator> BinaryReader for Box<T, A> {
274     fn read_from_slice(
275         &self,
276         reader: &mut UserSliceReader,
277         offset: &mut file::Offset,
278     ) -> Result<usize> {
279         self.deref().read_from_slice(reader, offset)
280     }
281 }
282 
283 // Delegate for `Pin<Box<T, A>>`: Support a `Pin<Box<T, A>>` with an inner lock.
284 impl<T: ?Sized + BinaryReader, A: Allocator> BinaryReader for Pin<Box<T, A>> {
285     fn read_from_slice(
286         &self,
287         reader: &mut UserSliceReader,
288         offset: &mut file::Offset,
289     ) -> Result<usize> {
290         self.deref().read_from_slice(reader, offset)
291     }
292 }
293 
294 // Delegate for `Arc<T>`: Support an `Arc<T>` with an inner lock.
295 impl<T: ?Sized + BinaryReader> BinaryReader for Arc<T> {
296     fn read_from_slice(
297         &self,
298         reader: &mut UserSliceReader,
299         offset: &mut file::Offset,
300     ) -> Result<usize> {
301         self.deref().read_from_slice(reader, offset)
302     }
303 }
304 
305 macro_rules! impl_reader_for_atomic {
306     ($(($atomic_type:ty, $int_type:ty)),*) => {
307         $(
308             impl Reader for $atomic_type {
309                 fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result {
310                     let mut buf = [0u8; 21]; // Enough for a 64-bit number.
311                     if reader.len() > buf.len() {
312                         return Err(EINVAL);
313                     }
314                     let n = reader.len();
315                     reader.read_slice(&mut buf[..n])?;
316 
317                     let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?;
318                     let val = s.trim().parse::<$int_type>().map_err(|_| EINVAL)?;
319                     self.store(val, Ordering::Relaxed);
320                     Ok(())
321                 }
322             }
323         )*
324     };
325 }
326 
327 impl_reader_for_atomic!(
328     (AtomicI16, i16),
329     (AtomicI32, i32),
330     (AtomicI64, i64),
331     (AtomicI8, i8),
332     (AtomicIsize, isize),
333     (AtomicU16, u16),
334     (AtomicU32, u32),
335     (AtomicU64, u64),
336     (AtomicU8, u8),
337     (AtomicUsize, usize)
338 );
339