88// When DebugFS is disabled, many parameters are dead. Linting for this isn't helpful.
99#![ cfg_attr( not( CONFIG_DEBUG_FS ) , allow( unused_variables) ) ]
1010
11- #[ cfg( CONFIG_DEBUG_FS ) ]
1211use crate :: prelude:: * ;
1312use crate :: str:: CStr ;
1413#[ cfg( CONFIG_DEBUG_FS ) ]
1514use crate :: sync:: Arc ;
15+ use core:: marker:: PhantomPinned ;
16+ use core:: ops:: Deref ;
17+
18+ mod traits;
19+ pub use traits:: Writer ;
1620
21+ mod file_ops;
22+ use file_ops:: { FileOps , ReadFile } ;
1723#[ cfg( CONFIG_DEBUG_FS ) ]
1824mod entry;
1925#[ cfg( CONFIG_DEBUG_FS ) ]
@@ -53,6 +59,34 @@ impl Dir {
5359 Self ( )
5460 }
5561
62+ /// Creates a DebugFS file which will own the data produced by the initializer provided in
63+ /// `data`.
64+ fn create_file < ' a , T , E : ' a > (
65+ & ' a self ,
66+ name : & ' a CStr ,
67+ data : impl PinInit < T , E > + ' a ,
68+ file_ops : & ' static FileOps < T > ,
69+ ) -> impl PinInit < File < T > , E > + ' a
70+ where
71+ T : Sync + ' static ,
72+ {
73+ let scope = Scope :: < T > :: new ( data, move |data| {
74+ #[ cfg( CONFIG_DEBUG_FS ) ]
75+ if let Some ( parent) = & self . 0 {
76+ // SAFETY: Because data derives from a scope, and our entry will be dropped before
77+ // the data is dropped, it is guaranteed to outlive the entry we return.
78+ unsafe { Entry :: dynamic_file ( name, parent. clone ( ) , data, file_ops) }
79+ } else {
80+ Entry :: empty ( )
81+ }
82+ } ) ;
83+ try_pin_init ! {
84+ File {
85+ scope <- scope
86+ } ? E
87+ }
88+ }
89+
5690 /// Create a new directory in DebugFS at the root.
5791 ///
5892 /// # Examples
@@ -79,4 +113,116 @@ impl Dir {
79113 pub fn subdir ( & self , name : & CStr ) -> Self {
80114 Dir :: create ( name, Some ( self ) )
81115 }
116+
117+ /// Creates a read-only file in this directory.
118+ ///
119+ /// The file's contents are produced by invoking [`Writer::write`] on the value initialized by
120+ /// `data`.
121+ ///
122+ /// # Examples
123+ ///
124+ /// ```
125+ /// # use kernel::c_str;
126+ /// # use kernel::debugfs::Dir;
127+ /// # use kernel::prelude::*;
128+ /// # let dir = Dir::new(c_str!("my_debugfs_dir"));
129+ /// let file = KBox::pin_init(dir.read_only_file(c_str!("foo"), 200), GFP_KERNEL)?;
130+ /// // "my_debugfs_dir/foo" now contains the number 200.
131+ /// // The file is removed when `file` is dropped.
132+ /// # Ok::<(), Error>(())
133+ /// ```
134+ pub fn read_only_file < ' a , T , E : ' a > (
135+ & ' a self ,
136+ name : & ' a CStr ,
137+ data : impl PinInit < T , E > + ' a ,
138+ ) -> impl PinInit < File < T > , E > + ' a
139+ where
140+ T : Writer + Send + Sync + ' static ,
141+ {
142+ let file_ops = & <T as ReadFile < _ > >:: FILE_OPS ;
143+ self . create_file ( name, data, file_ops)
144+ }
145+ }
146+
147+ #[ pin_data]
148+ /// Handle to a DebugFS scope, which ensures that attached `data` will outlive the provided
149+ /// [`Entry`] without moving.
150+ /// Currently, this is used to back [`File`] so that its `read` and/or `write` implementations
151+ /// can assume that their backing data is still alive.
152+ struct Scope < T > {
153+ // This order is load-bearing for drops - `_entry` must be dropped before `data`.
154+ #[ cfg( CONFIG_DEBUG_FS ) ]
155+ _entry : Entry ,
156+ #[ pin]
157+ data : T ,
158+ // Even if `T` is `Unpin`, we still can't allow it to be moved.
159+ #[ pin]
160+ _pin : PhantomPinned ,
161+ }
162+
163+ #[ pin_data]
164+ /// Handle to a DebugFS file, owning its backing data.
165+ ///
166+ /// When dropped, the DebugFS file will be removed and the attached data will be dropped.
167+ pub struct File < T > {
168+ #[ pin]
169+ scope : Scope < T > ,
170+ }
171+
172+ #[ cfg( not( CONFIG_DEBUG_FS ) ) ]
173+ impl < ' b , T : ' b > Scope < T > {
174+ fn new < E : ' b , F > ( data : impl PinInit < T , E > + ' b , init : F ) -> impl PinInit < Self , E > + ' b
175+ where
176+ F : for < ' a > FnOnce ( & ' a T ) + ' b ,
177+ {
178+ try_pin_init ! {
179+ Self {
180+ data <- data,
181+ _pin: PhantomPinned
182+ } ? E
183+ }
184+ . pin_chain ( |scope| {
185+ init ( & scope. data ) ;
186+ Ok ( ( ) )
187+ } )
188+ }
189+ }
190+
191+ #[ cfg( CONFIG_DEBUG_FS ) ]
192+ impl < ' b , T : ' b > Scope < T > {
193+ fn entry_mut ( self : Pin < & mut Self > ) -> & mut Entry {
194+ // SAFETY: _entry is not structurally pinned.
195+ unsafe { & mut Pin :: into_inner_unchecked ( self ) . _entry }
196+ }
197+
198+ fn new < E : ' b , F > ( data : impl PinInit < T , E > + ' b , init : F ) -> impl PinInit < Self , E > + ' b
199+ where
200+ F : for < ' a > FnOnce ( & ' a T ) -> Entry + ' b ,
201+ {
202+ try_pin_init ! {
203+ Self {
204+ _entry: Entry :: empty( ) ,
205+ data <- data,
206+ _pin: PhantomPinned
207+ } ? E
208+ }
209+ . pin_chain ( |scope| {
210+ * scope. entry_mut ( ) = init ( & scope. data ) ;
211+ Ok ( ( ) )
212+ } )
213+ }
214+ }
215+
216+ impl < T > Deref for Scope < T > {
217+ type Target = T ;
218+ fn deref ( & self ) -> & T {
219+ & self . data
220+ }
221+ }
222+
223+ impl < T > Deref for File < T > {
224+ type Target = T ;
225+ fn deref ( & self ) -> & T {
226+ & self . scope
227+ }
82228}
0 commit comments