@@ -35,7 +35,7 @@ impl MiscDeviceOptions {
35
35
let mut result: bindings:: miscdevice = unsafe { MaybeUninit :: zeroed ( ) . assume_init ( ) } ;
36
36
result. minor = bindings:: MISC_DYNAMIC_MINOR as _ ;
37
37
result. name = self . name . as_char_ptr ( ) ;
38
- result. fops = create_vtable :: < T > ( ) ;
38
+ result. fops = MiscdeviceVTable :: < T > :: build ( ) ;
39
39
result
40
40
}
41
41
}
@@ -160,171 +160,160 @@ pub trait MiscDevice: Sized {
160
160
}
161
161
}
162
162
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;
169
176
}
170
- }
171
177
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 } ;
193
180
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 > > ( ) } ;
196
186
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) } ;
210
191
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
+ } ;
218
196
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 ( ) } ;
223
204
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
+ }
235
207
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
+ }
238
225
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
+ }
259
245
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
+ }
281
269
}
282
- }
283
270
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) ;
306
289
}
307
- }
308
290
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
+ }
330
319
}
0 commit comments