@@ -15,6 +15,13 @@ use core::fmt::Write;
15
15
///
16
16
/// [`PAGE_SIZE`]: `crate::PAGE_SIZE`
17
17
pub trait ModuleParam : core:: fmt:: Display + core:: marker:: Sized {
18
+ /// The `ModuleParam` will be used by the kernel module through this type.
19
+ ///
20
+ /// This may differ from `Self` if, for example, `Self` needs to track
21
+ /// ownership without exposing it or allocate extra space for other possible
22
+ /// parameter values. See [`StringParam`] or [`ArrayParam`] for examples.
23
+ type Value : ?Sized ;
24
+
18
25
/// Whether the parameter is allowed to be set without an argument.
19
26
///
20
27
/// Setting this to `true` allows the parameter to be passed without an
@@ -27,7 +34,13 @@ pub trait ModuleParam: core::fmt::Display + core::marker::Sized {
27
34
/// `arg == None` indicates that the parameter was passed without an
28
35
/// argument. If `NOARG_ALLOWED` is set to `false` then `arg` is guaranteed
29
36
/// to always be `Some(_)`.
30
- fn try_from_param_arg ( arg : Option < & [ u8 ] > ) -> Option < Self > ;
37
+ fn try_from_param_arg ( arg : Option < & ' static [ u8 ] > ) -> Option < Self > ;
38
+
39
+ /// Get the current value of the parameter for use in the kernel module.
40
+ ///
41
+ /// This function should not be used directly. Instead use the wrapper
42
+ /// `read` which will be generated by [`module::module`].
43
+ fn value ( & self ) -> & Self :: Value ;
31
44
32
45
/// Set the module parameter from a string.
33
46
///
@@ -161,17 +174,23 @@ impl_parse_int!(usize);
161
174
macro_rules! impl_module_param {
162
175
( $ty: ident) => {
163
176
impl ModuleParam for $ty {
177
+ type Value = $ty;
164
178
const NOARG_ALLOWED : bool = false ;
165
179
166
- fn try_from_param_arg( arg: Option <& [ u8 ] >) -> Option <Self > {
180
+ fn try_from_param_arg( arg: Option <& ' static [ u8 ] >) -> Option <Self > {
167
181
let bytes = arg?;
168
182
let utf8 = core:: str :: from_utf8( bytes) . ok( ) ?;
169
183
<$ty as crate :: module_param:: ParseInt >:: from_str( utf8)
170
184
}
185
+
186
+ fn value( & self ) -> & Self :: Value {
187
+ self
188
+ }
171
189
}
172
190
} ;
173
191
}
174
192
193
+ #[ doc( hidden) ]
175
194
#[ macro_export]
176
195
/// Generate a static [`kernel_param_ops`](../../../include/linux/moduleparam.h) struct.
177
196
///
@@ -184,27 +203,27 @@ macro_rules! impl_module_param {
184
203
/// );
185
204
/// ```
186
205
macro_rules! make_param_ops {
187
- ( $ops: ident, $ty: ident ) => {
188
- make_param_ops!(
206
+ ( $ops: ident, $ty: ty ) => {
207
+ $crate :: make_param_ops!(
189
208
#[ doc="" ]
190
209
$ops,
191
210
$ty
192
211
) ;
193
212
} ;
194
- ( $( #[ $meta: meta] ) * $ops: ident, $ty: ident ) => {
213
+ ( $( #[ $meta: meta] ) * $ops: ident, $ty: ty ) => {
195
214
$( #[ $meta] ) *
196
215
///
197
216
/// Static [`kernel_param_ops`](../../../include/linux/moduleparam.h)
198
217
/// struct generated by [`make_param_ops`].
199
- pub static $ops: crate :: bindings:: kernel_param_ops = crate :: bindings:: kernel_param_ops {
200
- flags: if <$ty as crate :: module_param:: ModuleParam >:: NOARG_ALLOWED {
201
- crate :: bindings:: KERNEL_PARAM_OPS_FL_NOARG
218
+ pub static $ops: $ crate:: bindings:: kernel_param_ops = $ crate:: bindings:: kernel_param_ops {
219
+ flags: if <$ty as $ crate:: module_param:: ModuleParam >:: NOARG_ALLOWED {
220
+ $ crate:: bindings:: KERNEL_PARAM_OPS_FL_NOARG
202
221
} else {
203
222
0
204
223
} ,
205
- set: Some ( <$ty as crate :: module_param:: ModuleParam >:: set_param) ,
206
- get: Some ( <$ty as crate :: module_param:: ModuleParam >:: get_param) ,
207
- free: Some ( <$ty as crate :: module_param:: ModuleParam >:: free) ,
224
+ set: Some ( <$ty as $ crate:: module_param:: ModuleParam >:: set_param) ,
225
+ get: Some ( <$ty as $ crate:: module_param:: ModuleParam >:: get_param) ,
226
+ free: Some ( <$ty as $ crate:: module_param:: ModuleParam >:: free) ,
208
227
} ;
209
228
} ;
210
229
}
@@ -282,16 +301,21 @@ make_param_ops!(
282
301
) ;
283
302
284
303
impl ModuleParam for bool {
304
+ type Value = bool ;
285
305
const NOARG_ALLOWED : bool = true ;
286
306
287
- fn try_from_param_arg ( arg : Option < & [ u8 ] > ) -> Option < Self > {
307
+ fn try_from_param_arg ( arg : Option < & ' static [ u8 ] > ) -> Option < Self > {
288
308
match arg {
289
309
None => Some ( true ) ,
290
310
Some ( b"y" ) | Some ( b"Y" ) | Some ( b"1" ) | Some ( b"true" ) => Some ( true ) ,
291
311
Some ( b"n" ) | Some ( b"N" ) | Some ( b"0" ) | Some ( b"false" ) => Some ( false ) ,
292
312
_ => None ,
293
313
}
294
314
}
315
+
316
+ fn value ( & self ) -> & Self :: Value {
317
+ self
318
+ }
295
319
}
296
320
297
321
make_param_ops ! (
@@ -300,3 +324,156 @@ make_param_ops!(
300
324
PARAM_OPS_BOOL ,
301
325
bool
302
326
) ;
327
+
328
+ /// An array of at __most__ `N` values.
329
+ ///
330
+ /// # Invariant
331
+ ///
332
+ /// The first `self.used` elements of `self.values` are initialized.
333
+ pub struct ArrayParam < T , const N : usize > {
334
+ values : [ core:: mem:: MaybeUninit < T > ; N ] ,
335
+ used : usize ,
336
+ }
337
+
338
+ impl < T , const N : usize > ArrayParam < T , { N } > {
339
+ fn values ( & self ) -> & [ T ] {
340
+ // SAFETY: The invariant maintained by `ArrayParam` allows us to cast
341
+ // the first `self.used` elements to `T`.
342
+ unsafe {
343
+ & * ( & self . values [ 0 ..self . used ] as * const [ core:: mem:: MaybeUninit < T > ] as * const [ T ] )
344
+ }
345
+ }
346
+ }
347
+
348
+ impl < T : Copy , const N : usize > ArrayParam < T , { N } > {
349
+ const fn new ( ) -> Self {
350
+ // INVARIANT: The first `self.used` elements of `self.values` are
351
+ // initialized.
352
+ ArrayParam {
353
+ values : [ core:: mem:: MaybeUninit :: uninit ( ) ; N ] ,
354
+ used : 0 ,
355
+ }
356
+ }
357
+
358
+ const fn push ( & mut self , val : T ) {
359
+ if self . used < N {
360
+ // INVARIANT: The first `self.used` elements of `self.values` are
361
+ // initialized.
362
+ self . values [ self . used ] = core:: mem:: MaybeUninit :: new ( val) ;
363
+ self . used += 1 ;
364
+ }
365
+ }
366
+
367
+ /// Create an instance of `ArrayParam` initialized with `vals`.
368
+ ///
369
+ /// This function is only meant to be used in the [`module::module`] macro.
370
+ pub const fn create ( vals : & [ T ] ) -> Self {
371
+ let mut result = ArrayParam :: new ( ) ;
372
+ let mut i = 0 ;
373
+ while i < vals. len ( ) {
374
+ result. push ( vals[ i] ) ;
375
+ i += 1 ;
376
+ }
377
+ result
378
+ }
379
+ }
380
+
381
+ impl < T : core:: fmt:: Display , const N : usize > core:: fmt:: Display for ArrayParam < T , { N } > {
382
+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
383
+ for val in self . values ( ) {
384
+ write ! ( f, "{}," , val) ?;
385
+ }
386
+ Ok ( ( ) )
387
+ }
388
+ }
389
+
390
+ impl < T : Copy + core:: fmt:: Display + ModuleParam , const N : usize > ModuleParam
391
+ for ArrayParam < T , { N } >
392
+ {
393
+ type Value = [ T ] ;
394
+ const NOARG_ALLOWED : bool = false ;
395
+
396
+ fn try_from_param_arg ( arg : Option < & ' static [ u8 ] > ) -> Option < Self > {
397
+ arg. and_then ( |args| {
398
+ let mut result = Self :: new ( ) ;
399
+ for arg in args. split ( |b| * b == b',' ) {
400
+ result. push ( T :: try_from_param_arg ( Some ( arg) ) ?) ;
401
+ }
402
+ Some ( result)
403
+ } )
404
+ }
405
+
406
+ fn value ( & self ) -> & Self :: Value {
407
+ self . values ( )
408
+ }
409
+ }
410
+
411
+ /// A C-style string parameter.
412
+ ///
413
+ /// The Rust version of the [`charp`] parameter. This type is meant to be
414
+ /// used by the [`module::module`] macro, not handled directly. Instead use the
415
+ /// `read` method generated by that macro.
416
+ ///
417
+ /// [`charp`]: ../../../include/linux/moduleparam.h
418
+ pub enum StringParam {
419
+ /// A borrowed parameter value.
420
+ ///
421
+ /// Either the default value (which is static in the module) or borrowed
422
+ /// from the original argument buffer used to set the value.
423
+ Ref ( & ' static [ u8 ] ) ,
424
+
425
+ /// A value that was allocated when the parameter was set.
426
+ ///
427
+ /// The value needs to be freed when the parameter is reset or the module is
428
+ /// unloaded.
429
+ Owned ( alloc:: vec:: Vec < u8 > ) ,
430
+ }
431
+
432
+ impl StringParam {
433
+ fn bytes ( & self ) -> & [ u8 ] {
434
+ match self {
435
+ StringParam :: Ref ( bytes) => * bytes,
436
+ StringParam :: Owned ( vec) => & vec[ ..] ,
437
+ }
438
+ }
439
+ }
440
+
441
+ impl core:: fmt:: Display for StringParam {
442
+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
443
+ let bytes = self . bytes ( ) ;
444
+ match core:: str:: from_utf8 ( bytes) {
445
+ Ok ( utf8) => write ! ( f, "{}" , utf8) ,
446
+ Err ( _) => write ! ( f, "{:?}" , bytes) ,
447
+ }
448
+ }
449
+ }
450
+
451
+ impl ModuleParam for StringParam {
452
+ type Value = [ u8 ] ;
453
+ const NOARG_ALLOWED : bool = false ;
454
+
455
+ fn try_from_param_arg ( arg : Option < & ' static [ u8 ] > ) -> Option < Self > {
456
+ // SAFETY: It is always safe to call [`slab_is_available`](../../../include/linux/slab.h).
457
+ let slab_available = unsafe { crate :: bindings:: slab_is_available ( ) } ;
458
+ arg. map ( |arg| {
459
+ if slab_available {
460
+ let mut vec = alloc:: vec:: Vec :: new ( ) ;
461
+ vec. extend_from_slice ( arg) ;
462
+ StringParam :: Owned ( vec)
463
+ } else {
464
+ StringParam :: Ref ( arg)
465
+ }
466
+ } )
467
+ }
468
+
469
+ fn value ( & self ) -> & Self :: Value {
470
+ self . bytes ( )
471
+ }
472
+ }
473
+
474
+ make_param_ops ! (
475
+ /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
476
+ /// for [`StringParam`].
477
+ PARAM_OPS_STR ,
478
+ StringParam
479
+ ) ;
0 commit comments