@@ -86,7 +86,7 @@ unsafe extern "C" fn read_callback<T: FileOperations>(
86
86
let f = & * ( ( * file) . private_data as * const T ) ;
87
87
// No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
88
88
// See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
89
- T :: READ . unwrap ( ) ( f, & File :: from_ptr( file) , & mut data, ( * offset) . try_into( ) ?) ?;
89
+ T :: read ( f, & File :: from_ptr( file) , & mut data, ( * offset) . try_into( ) ?) ?;
90
90
let written = len - data. len( ) ;
91
91
( * offset) += bindings:: loff_t:: try_from( written) . unwrap( ) ;
92
92
Ok ( written. try_into( ) . unwrap( ) )
@@ -104,7 +104,7 @@ unsafe extern "C" fn write_callback<T: FileOperations>(
104
104
let f = & * ( ( * file) . private_data as * const T ) ;
105
105
// No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
106
106
// See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
107
- T :: WRITE . unwrap ( ) ( f, & mut data, ( * offset) . try_into( ) ?) ?;
107
+ T :: write ( f, & mut data, ( * offset) . try_into( ) ?) ?;
108
108
let read = len - data. len( ) ;
109
109
( * offset) += bindings:: loff_t:: try_from( read) . unwrap( ) ;
110
110
Ok ( read. try_into( ) . unwrap( ) )
@@ -133,7 +133,7 @@ unsafe extern "C" fn llseek_callback<T: FileOperations>(
133
133
_ => return Err ( Error :: EINVAL ) ,
134
134
} ;
135
135
let f = & * ( ( * file) . private_data as * const T ) ;
136
- let off = T :: SEEK . unwrap ( ) ( f, & File :: from_ptr( file) , off) ?;
136
+ let off = T :: seek ( f, & File :: from_ptr( file) , off) ?;
137
137
Ok ( off as bindings:: loff_t)
138
138
}
139
139
}
@@ -149,7 +149,7 @@ unsafe extern "C" fn fsync_callback<T: FileOperations>(
149
149
let end = end. try_into( ) ?;
150
150
let datasync = datasync != 0 ;
151
151
let f = & * ( ( * file) . private_data as * const T ) ;
152
- let res = T :: FSYNC . unwrap ( ) ( f, & File :: from_ptr( file) , start, end, datasync) ?;
152
+ let res = T :: fsync ( f, & File :: from_ptr( file) , start, end, datasync) ?;
153
153
Ok ( res. try_into( ) . unwrap( ) )
154
154
}
155
155
}
@@ -160,17 +160,17 @@ impl<T: FileOperations> FileOperationsVtable<T> {
160
160
pub ( crate ) const VTABLE : bindings:: file_operations = bindings:: file_operations {
161
161
open : Some ( open_callback :: < T > ) ,
162
162
release : Some ( release_callback :: < T > ) ,
163
- read : if T :: READ . is_some ( ) {
163
+ read : if T :: TO_USE . read {
164
164
Some ( read_callback :: < T > )
165
165
} else {
166
166
None
167
167
} ,
168
- write : if T :: WRITE . is_some ( ) {
168
+ write : if T :: TO_USE . write {
169
169
Some ( write_callback :: < T > )
170
170
} else {
171
171
None
172
172
} ,
173
- llseek : if T :: SEEK . is_some ( ) {
173
+ llseek : if T :: TO_USE . seek {
174
174
Some ( llseek_callback :: < T > )
175
175
} else {
176
176
None
@@ -184,7 +184,7 @@ impl<T: FileOperations> FileOperationsVtable<T> {
184
184
fasync : None ,
185
185
flock : None ,
186
186
flush : None ,
187
- fsync : if T :: FSYNC . is_some ( ) {
187
+ fsync : if T :: TO_USE . fsync {
188
188
Some ( fsync_callback :: < T > )
189
189
} else {
190
190
None
@@ -210,26 +210,55 @@ impl<T: FileOperations> FileOperationsVtable<T> {
210
210
} ;
211
211
}
212
212
213
- /// `read` file operation function type.
214
- pub type ReadFn < T > = Option < fn ( & T , & File , & mut UserSlicePtrWriter , u64 ) -> KernelResult < ( ) > > ;
213
+ /// Represents which fields of [`struct file_operations`] should be populated with pointers.
214
+ pub struct ToUse {
215
+ /// The `read` field of [`struct file_operations`].
216
+ pub read : bool ,
215
217
216
- /// `write` file operation function type .
217
- pub type WriteFn < T > = Option < fn ( & T , & mut UserSlicePtrReader , u64 ) -> KernelResult < ( ) > > ;
218
+ /// The `write` field of [`struct file_operations`] .
219
+ pub write : bool ,
218
220
219
- /// `seek` file operation function type .
220
- pub type SeekFn < T > = Option < fn ( & T , & File , SeekFrom ) -> KernelResult < u64 > > ;
221
+ /// The `llseek` field of [`struct file_operations`] .
222
+ pub seek : bool ,
221
223
222
- /// `fsync` file operation function type.
223
- pub type FSync < T > = Option < fn ( & T , & File , u64 , u64 , bool ) -> KernelResult < u32 > > ;
224
+ /// The `fsync` field of [`struct file_operations`].
225
+ pub fsync : bool ,
226
+ }
227
+
228
+ /// A constant version where all values are to set to `false`, that is, all supported fields will
229
+ /// be set to null pointers.
230
+ pub const USE_NONE : ToUse = ToUse {
231
+ read : false ,
232
+ write : false ,
233
+ seek : false ,
234
+ fsync : false ,
235
+ } ;
236
+
237
+ /// Defines the [`FileOperations::TO_USE`] field based on a list of fields to be populated.
238
+ #[ macro_export]
239
+ macro_rules! declare_file_operations {
240
+ ( ) => {
241
+ const TO_USE : $crate:: file_operations:: ToUse = $crate:: file_operations:: USE_NONE ;
242
+ } ;
243
+ ( $( $i: ident) ,+) => {
244
+ const TO_USE : kernel:: file_operations:: ToUse =
245
+ $crate:: file_operations:: ToUse {
246
+ $( $i: true ) ,+ ,
247
+ ..$crate:: file_operations:: USE_NONE
248
+ } ;
249
+ } ;
250
+ }
224
251
225
252
/// Corresponds to the kernel's `struct file_operations`.
226
253
///
227
- /// You implement this trait whenever you would create a
228
- /// `struct file_operations`.
254
+ /// You implement this trait whenever you would create a `struct file_operations`.
229
255
///
230
- /// File descriptors may be used from multiple threads/processes concurrently,
231
- /// so your type must be [`Sync`].
256
+ /// File descriptors may be used from multiple threads/processes concurrently, so your type must be
257
+ /// [`Sync`].
232
258
pub trait FileOperations : Sync + Sized {
259
+ /// The methods to use to populate [`struct file_operations`].
260
+ const TO_USE : ToUse ;
261
+
233
262
/// The pointer type that will be used to hold ourselves.
234
263
type Wrapper : PointerWrapper < Self > ;
235
264
@@ -240,41 +269,46 @@ pub trait FileOperations: Sync + Sized {
240
269
241
270
/// Cleans up after the last reference to the file goes away.
242
271
///
243
- /// Note that the object is moved, so it will be freed automatically unless
244
- /// the implemention moves it elsewhere.
272
+ /// Note that the object is moved, so it will be freed automatically unless the implementation
273
+ /// moves it elsewhere.
245
274
///
246
- /// Corresponds to the `release` function pointer in
247
- /// `struct file_operations`.
275
+ /// Corresponds to the `release` function pointer in `struct file_operations`.
248
276
fn release ( _obj : Self :: Wrapper , _file : & File ) { }
249
277
250
278
/// Reads data from this file to userspace.
251
279
///
252
280
/// Corresponds to the `read` function pointer in `struct file_operations`.
253
- const READ : ReadFn < Self > = None ;
281
+ fn read ( & self , _file : & File , _data : & mut UserSlicePtrWriter , _offset : u64 ) -> KernelResult < ( ) > {
282
+ Err ( Error :: EINVAL )
283
+ }
254
284
255
285
/// Writes data from userspace to this file.
256
286
///
257
287
/// Corresponds to the `write` function pointer in `struct file_operations`.
258
- const WRITE : WriteFn < Self > = None ;
288
+ fn write ( & self , _data : & mut UserSlicePtrReader , _offset : u64 ) -> KernelResult < isize > {
289
+ Err ( Error :: EINVAL )
290
+ }
259
291
260
292
/// Changes the position of the file.
261
293
///
262
- /// Corresponds to the `llseek` function pointer in
263
- /// `struct file_operations`.
264
- const SEEK : SeekFn < Self > = None ;
294
+ /// Corresponds to the `llseek` function pointer in `struct file_operations`.
295
+ fn seek ( & self , _file : & File , _offset : SeekFrom ) -> KernelResult < u64 > {
296
+ Err ( Error :: EINVAL )
297
+ }
265
298
266
299
/// Syncs pending changes to this file.
267
300
///
268
- /// Corresponds to the `fsync` function pointer in
269
- /// `struct file_operations`.
270
- const FSYNC : FSync < Self > = None ;
301
+ /// Corresponds to the `fsync` function pointer in `struct file_operations`.
302
+ fn fsync ( & self , _file : & File , _start : u64 , _end : u64 , _datasync : bool ) -> KernelResult < u32 > {
303
+ Err ( Error :: EINVAL )
304
+ }
271
305
}
272
306
273
307
/// Used to convert an object into a raw pointer that represents it.
274
308
///
275
- /// It can eventually be converted back into the object. This is used to store
276
- /// objects as pointers in kernel data structures, for example, an
277
- /// implementation of `FileOperations` in `struct file::private_data`.
309
+ /// It can eventually be converted back into the object. This is used to store objects as pointers
310
+ /// in kernel data structures, for example, an implementation of [`FileOperations`] in `struct
311
+ /// file::private_data`.
278
312
pub trait PointerWrapper < T > {
279
313
/// Returns the raw pointer.
280
314
fn into_pointer ( self ) -> * const T ;
@@ -283,8 +317,7 @@ pub trait PointerWrapper<T> {
283
317
///
284
318
/// # Safety
285
319
///
286
- /// The passed pointer must come from a previous call to
287
- /// [`PointerWrapper::into_pointer()`].
320
+ /// The passed pointer must come from a previous call to [`PointerWrapper::into_pointer()`].
288
321
unsafe fn from_pointer ( ptr : * const T ) -> Self ;
289
322
}
290
323
0 commit comments