@@ -35,7 +35,7 @@ impl MiscDeviceOptions {
3535 let mut result: bindings:: miscdevice = unsafe { MaybeUninit :: zeroed ( ) . assume_init ( ) } ;
3636 result. minor = bindings:: MISC_DYNAMIC_MINOR as _ ;
3737 result. name = self . name . as_char_ptr ( ) ;
38- result. fops = create_vtable :: < T > ( ) ;
38+ result. fops = MiscdeviceVTable :: < T > :: build ( ) ;
3939 result
4040 }
4141}
@@ -160,171 +160,160 @@ pub trait MiscDevice: Sized {
160160 }
161161}
162162
163- const fn create_vtable < T : MiscDevice > ( ) -> & ' static bindings:: file_operations {
164- const fn maybe_fn < T : Copy > ( check : bool , func : T ) -> Option < T > {
165- if check {
166- Some ( func)
167- } else {
168- None
163+ /// A vtable for the file operations of a Rust miscdevice.
164+ struct MiscdeviceVTable < T : MiscDevice > ( PhantomData < T > ) ;
165+
166+ impl < T : MiscDevice > MiscdeviceVTable < T > {
167+ /// # Safety
168+ ///
169+ /// `file` and `inode` must be the file and inode for a file that is undergoing initialization.
170+ /// The file must be associated with a `MiscDeviceRegistration<T>`.
171+ unsafe extern "C" fn open ( inode : * mut bindings:: inode , raw_file : * mut bindings:: file ) -> c_int {
172+ // SAFETY: The pointers are valid and for a file being opened.
173+ let ret = unsafe { bindings:: generic_file_open ( inode, raw_file) } ;
174+ if ret != 0 {
175+ return ret;
169176 }
170- }
171177
172- struct VtableHelper < T : MiscDevice > {
173- _t : PhantomData < T > ,
174- }
175- impl < T : MiscDevice > VtableHelper < T > {
176- const VTABLE : bindings:: file_operations = bindings:: file_operations {
177- open : Some ( fops_open :: < T > ) ,
178- release : Some ( fops_release :: < T > ) ,
179- unlocked_ioctl : maybe_fn ( T :: HAS_IOCTL , fops_ioctl :: < T > ) ,
180- #[ cfg( CONFIG_COMPAT ) ]
181- compat_ioctl : if T :: HAS_COMPAT_IOCTL {
182- Some ( fops_compat_ioctl :: < T > )
183- } else if T :: HAS_IOCTL {
184- Some ( bindings:: compat_ptr_ioctl)
185- } else {
186- None
187- } ,
188- show_fdinfo : maybe_fn ( T :: HAS_SHOW_FDINFO , fops_show_fdinfo :: < T > ) ,
189- // SAFETY: All zeros is a valid value for `bindings::file_operations`.
190- ..unsafe { MaybeUninit :: zeroed ( ) . assume_init ( ) }
191- } ;
192- }
178+ // SAFETY: The open call of a file can access the private data.
179+ let misc_ptr = unsafe { ( * raw_file) . private_data } ;
193180
194- & VtableHelper :: < T > :: VTABLE
195- }
181+ // SAFETY: This is a miscdevice, so `misc_open()` set the private data to a pointer to the
182+ // associated `struct miscdevice` before calling into this method. Furthermore,
183+ // `misc_open()` ensures that the miscdevice can't be unregistered and freed during this
184+ // call to `fops_open`.
185+ let misc = unsafe { & * misc_ptr. cast :: < MiscDeviceRegistration < T > > ( ) } ;
196186
197- /// # Safety
198- ///
199- /// `file` and `inode` must be the file and inode for a file that is undergoing initialization.
200- /// The file must be associated with a `MiscDeviceRegistration<T>`.
201- unsafe extern "C" fn fops_open < T : MiscDevice > (
202- inode : * mut bindings:: inode ,
203- raw_file : * mut bindings:: file ,
204- ) -> c_int {
205- // SAFETY: The pointers are valid and for a file being opened.
206- let ret = unsafe { bindings:: generic_file_open ( inode, raw_file) } ;
207- if ret != 0 {
208- return ret;
209- }
187+ // SAFETY:
188+ // * This underlying file is valid for (much longer than) the duration of `T::open`.
189+ // * There is no active fdget_pos region on the file on this thread.
190+ let file = unsafe { File :: from_raw_file ( raw_file) } ;
210191
211- // SAFETY: The open call of a file can access the private data.
212- let misc_ptr = unsafe { ( * raw_file) . private_data } ;
213-
214- // SAFETY: This is a miscdevice, so `misc_open()` set the private data to a pointer to the
215- // associated `struct miscdevice` before calling into this method. Furthermore, `misc_open()`
216- // ensures that the miscdevice can't be unregistered and freed during this call to `fops_open`.
217- let misc = unsafe { & * misc_ptr. cast :: < MiscDeviceRegistration < T > > ( ) } ;
192+ let ptr = match T :: open ( file, misc) {
193+ Ok ( ptr) => ptr,
194+ Err ( err) => return err. to_errno ( ) ,
195+ } ;
218196
219- // SAFETY:
220- // * This underlying file is valid for (much longer than) the duration of `T::open`.
221- // * There is no active fdget_pos region on the file on this thread.
222- let file = unsafe { File :: from_raw_file ( raw_file) } ;
197+ // This overwrites the private data with the value specified by the user, changing the type
198+ // of this file's private data. All future accesses to the private data is performed by
199+ // other fops_* methods in this file, which all correctly cast the private data to the new
200+ // type.
201+ //
202+ // SAFETY: The open call of a file can access the private data.
203+ unsafe { ( * raw_file) . private_data = ptr. into_foreign ( ) } ;
223204
224- let ptr = match T :: open ( file, misc) {
225- Ok ( ptr) => ptr,
226- Err ( err) => return err. to_errno ( ) ,
227- } ;
228-
229- // This overwrites the private data with the value specified by the user, changing the type of
230- // this file's private data. All future accesses to the private data is performed by other
231- // fops_* methods in this file, which all correctly cast the private data to the new type.
232- //
233- // SAFETY: The open call of a file can access the private data.
234- unsafe { ( * raw_file) . private_data = ptr. into_foreign ( ) } ;
205+ 0
206+ }
235207
236- 0
237- }
208+ /// # Safety
209+ ///
210+ /// `file` and `inode` must be the file and inode for a file that is being released. The file
211+ /// must be associated with a `MiscDeviceRegistration<T>`.
212+ unsafe extern "C" fn release ( _inode : * mut bindings:: inode , file : * mut bindings:: file ) -> c_int {
213+ // SAFETY: The release call of a file owns the private data.
214+ let private = unsafe { ( * file) . private_data } ;
215+ // SAFETY: The release call of a file owns the private data.
216+ let ptr = unsafe { <T :: Ptr as ForeignOwnable >:: from_foreign ( private) } ;
217+
218+ // SAFETY:
219+ // * The file is valid for the duration of this call.
220+ // * There is no active fdget_pos region on the file on this thread.
221+ T :: release ( ptr, unsafe { File :: from_raw_file ( file) } ) ;
222+
223+ 0
224+ }
238225
239- /// # Safety
240- ///
241- /// `file` and `inode` must be the file and inode for a file that is being released. The file must
242- /// be associated with a `MiscDeviceRegistration<T>`.
243- unsafe extern "C" fn fops_release < T : MiscDevice > (
244- _inode : * mut bindings:: inode ,
245- file : * mut bindings:: file ,
246- ) -> c_int {
247- // SAFETY: The release call of a file owns the private data.
248- let private = unsafe { ( * file) . private_data } ;
249- // SAFETY: The release call of a file owns the private data.
250- let ptr = unsafe { <T :: Ptr as ForeignOwnable >:: from_foreign ( private) } ;
251-
252- // SAFETY:
253- // * The file is valid for the duration of this call.
254- // * There is no active fdget_pos region on the file on this thread.
255- T :: release ( ptr, unsafe { File :: from_raw_file ( file) } ) ;
256-
257- 0
258- }
226+ /// # Safety
227+ ///
228+ /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
229+ unsafe extern "C" fn ioctl ( file : * mut bindings:: file , cmd : c_uint , arg : c_ulong ) -> c_long {
230+ // SAFETY: The ioctl call of a file can access the private data.
231+ let private = unsafe { ( * file) . private_data } ;
232+ // SAFETY: Ioctl calls can borrow the private data of the file.
233+ let device = unsafe { <T :: Ptr as ForeignOwnable >:: borrow ( private) } ;
234+
235+ // SAFETY:
236+ // * The file is valid for the duration of this call.
237+ // * There is no active fdget_pos region on the file on this thread.
238+ let file = unsafe { File :: from_raw_file ( file) } ;
239+
240+ match T :: ioctl ( device, file, cmd, arg) {
241+ Ok ( ret) => ret as c_long ,
242+ Err ( err) => err. to_errno ( ) as c_long ,
243+ }
244+ }
259245
260- /// # Safety
261- ///
262- /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
263- unsafe extern "C" fn fops_ioctl < T : MiscDevice > (
264- file : * mut bindings:: file ,
265- cmd : c_uint ,
266- arg : c_ulong ,
267- ) -> c_long {
268- // SAFETY: The ioctl call of a file can access the private data.
269- let private = unsafe { ( * file) . private_data } ;
270- // SAFETY: Ioctl calls can borrow the private data of the file.
271- let device = unsafe { <T :: Ptr as ForeignOwnable >:: borrow ( private) } ;
272-
273- // SAFETY:
274- // * The file is valid for the duration of this call.
275- // * There is no active fdget_pos region on the file on this thread.
276- let file = unsafe { File :: from_raw_file ( file) } ;
277-
278- match T :: ioctl ( device, file, cmd, arg) {
279- Ok ( ret) => ret as c_long ,
280- Err ( err) => err. to_errno ( ) as c_long ,
246+ /// # Safety
247+ ///
248+ /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
249+ #[ cfg( CONFIG_COMPAT ) ]
250+ unsafe extern "C" fn compat_ioctl (
251+ file : * mut bindings:: file ,
252+ cmd : c_uint ,
253+ arg : c_ulong ,
254+ ) -> c_long {
255+ // SAFETY: The compat ioctl call of a file can access the private data.
256+ let private = unsafe { ( * file) . private_data } ;
257+ // SAFETY: Ioctl calls can borrow the private data of the file.
258+ let device = unsafe { <T :: Ptr as ForeignOwnable >:: borrow ( private) } ;
259+
260+ // SAFETY:
261+ // * The file is valid for the duration of this call.
262+ // * There is no active fdget_pos region on the file on this thread.
263+ let file = unsafe { File :: from_raw_file ( file) } ;
264+
265+ match T :: compat_ioctl ( device, file, cmd, arg) {
266+ Ok ( ret) => ret as c_long ,
267+ Err ( err) => err. to_errno ( ) as c_long ,
268+ }
281269 }
282- }
283270
284- /// # Safety
285- ///
286- /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
287- #[ cfg( CONFIG_COMPAT ) ]
288- unsafe extern "C" fn fops_compat_ioctl < T : MiscDevice > (
289- file : * mut bindings:: file ,
290- cmd : c_uint ,
291- arg : c_ulong ,
292- ) -> c_long {
293- // SAFETY: The compat ioctl call of a file can access the private data.
294- let private = unsafe { ( * file) . private_data } ;
295- // SAFETY: Ioctl calls can borrow the private data of the file.
296- let device = unsafe { <T :: Ptr as ForeignOwnable >:: borrow ( private) } ;
297-
298- // SAFETY:
299- // * The file is valid for the duration of this call.
300- // * There is no active fdget_pos region on the file on this thread.
301- let file = unsafe { File :: from_raw_file ( file) } ;
302-
303- match T :: compat_ioctl ( device, file, cmd, arg) {
304- Ok ( ret) => ret as c_long ,
305- Err ( err) => err. to_errno ( ) as c_long ,
271+ /// # Safety
272+ ///
273+ /// - `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
274+ /// - `seq_file` must be a valid `struct seq_file` that we can write to.
275+ unsafe extern "C" fn show_fdinfo ( seq_file : * mut bindings:: seq_file , file : * mut bindings:: file ) {
276+ // SAFETY: The release call of a file owns the private data.
277+ let private = unsafe { ( * file) . private_data } ;
278+ // SAFETY: Ioctl calls can borrow the private data of the file.
279+ let device = unsafe { <T :: Ptr as ForeignOwnable >:: borrow ( private) } ;
280+ // SAFETY:
281+ // * The file is valid for the duration of this call.
282+ // * There is no active fdget_pos region on the file on this thread.
283+ let file = unsafe { File :: from_raw_file ( file) } ;
284+ // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in
285+ // which this method is called.
286+ let m = unsafe { SeqFile :: from_raw ( seq_file) } ;
287+
288+ T :: show_fdinfo ( device, m, file) ;
306289 }
307- }
308290
309- /// # Safety
310- ///
311- /// - `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
312- /// - `seq_file` must be a valid `struct seq_file` that we can write to.
313- unsafe extern "C" fn fops_show_fdinfo < T : MiscDevice > (
314- seq_file : * mut bindings:: seq_file ,
315- file : * mut bindings:: file ,
316- ) {
317- // SAFETY: The release call of a file owns the private data.
318- let private = unsafe { ( * file) . private_data } ;
319- // SAFETY: Ioctl calls can borrow the private data of the file.
320- let device = unsafe { <T :: Ptr as ForeignOwnable >:: borrow ( private) } ;
321- // SAFETY:
322- // * The file is valid for the duration of this call.
323- // * There is no active fdget_pos region on the file on this thread.
324- let file = unsafe { File :: from_raw_file ( file) } ;
325- // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which
326- // this method is called.
327- let m = unsafe { SeqFile :: from_raw ( seq_file) } ;
328-
329- T :: show_fdinfo ( device, m, file) ;
291+ const VTABLE : bindings:: file_operations = bindings:: file_operations {
292+ open : Some ( Self :: open) ,
293+ release : Some ( Self :: release) ,
294+ unlocked_ioctl : if T :: HAS_IOCTL {
295+ Some ( Self :: ioctl)
296+ } else {
297+ None
298+ } ,
299+ #[ cfg( CONFIG_COMPAT ) ]
300+ compat_ioctl : if T :: HAS_COMPAT_IOCTL {
301+ Some ( Self :: compat_ioctl)
302+ } else if T :: HAS_IOCTL {
303+ Some ( bindings:: compat_ptr_ioctl)
304+ } else {
305+ None
306+ } ,
307+ show_fdinfo : if T :: HAS_SHOW_FDINFO {
308+ Some ( Self :: show_fdinfo)
309+ } else {
310+ None
311+ } ,
312+ // SAFETY: All zeros is a valid value for `bindings::file_operations`.
313+ ..unsafe { MaybeUninit :: zeroed ( ) . assume_init ( ) }
314+ } ;
315+
316+ const fn build ( ) -> & ' static bindings:: file_operations {
317+ & Self :: VTABLE
318+ }
330319}
0 commit comments