Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: introduce module_param module

Add types and traits for interfacing the C moduleparam API.

Reviewed-by: Benno Lossin <lossin@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Tested-by: Daniel Gomez <da.gomez@samsung.com>
Signed-off-by: Daniel Gomez <da.gomez@kernel.org>

authored by

Andreas Hindborg and committed by
Daniel Gomez
0b08fc29 51d9ee90

+182
+1
rust/kernel/lib.rs
··· 107 107 pub mod maple_tree; 108 108 pub mod miscdevice; 109 109 pub mod mm; 110 + pub mod module_param; 110 111 #[cfg(CONFIG_NET)] 111 112 pub mod net; 112 113 pub mod of;
+181
rust/kernel/module_param.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Support for module parameters. 4 + //! 5 + //! C header: [`include/linux/moduleparam.h`](srctree/include/linux/moduleparam.h) 6 + 7 + use crate::prelude::*; 8 + use crate::str::BStr; 9 + use bindings; 10 + use kernel::sync::SetOnce; 11 + 12 + /// Newtype to make `bindings::kernel_param` [`Sync`]. 13 + #[repr(transparent)] 14 + #[doc(hidden)] 15 + pub struct KernelParam(bindings::kernel_param); 16 + 17 + impl KernelParam { 18 + #[doc(hidden)] 19 + pub const fn new(val: bindings::kernel_param) -> Self { 20 + Self(val) 21 + } 22 + } 23 + 24 + // SAFETY: C kernel handles serializing access to this type. We never access it 25 + // from Rust module. 26 + unsafe impl Sync for KernelParam {} 27 + 28 + /// Types that can be used for module parameters. 29 + // NOTE: This trait is `Copy` because drop could produce unsoundness during teardown. 30 + pub trait ModuleParam: Sized + Copy { 31 + /// Parse a parameter argument into the parameter value. 32 + fn try_from_param_arg(arg: &BStr) -> Result<Self>; 33 + } 34 + 35 + /// Set the module parameter from a string. 36 + /// 37 + /// Used to set the parameter value at kernel initialization, when loading 38 + /// the module or when set through `sysfs`. 39 + /// 40 + /// See `struct kernel_param_ops.set`. 41 + /// 42 + /// # Safety 43 + /// 44 + /// - If `val` is non-null then it must point to a valid null-terminated string that must be valid 45 + /// for reads for the duration of the call. 46 + /// - `param` must be a pointer to a `bindings::kernel_param` initialized by the rust module macro. 47 + /// The pointee must be valid for reads for the duration of the call. 48 + /// 49 + /// # Note 50 + /// 51 + /// - The safety requirements are satisfied by C API contract when this function is invoked by the 52 + /// module subsystem C code. 53 + /// - Currently, we only support read-only parameters that are not readable from `sysfs`. Thus, this 54 + /// function is only called at kernel initialization time, or at module load time, and we have 55 + /// exclusive access to the parameter for the duration of the function. 56 + /// 57 + /// [`module!`]: macros::module 58 + unsafe extern "C" fn set_param<T>(val: *const c_char, param: *const bindings::kernel_param) -> c_int 59 + where 60 + T: ModuleParam, 61 + { 62 + // NOTE: If we start supporting arguments without values, val _is_ allowed 63 + // to be null here. 64 + if val.is_null() { 65 + // TODO: Use pr_warn_once available. 66 + crate::pr_warn!("Null pointer passed to `module_param::set_param`"); 67 + return EINVAL.to_errno(); 68 + } 69 + 70 + // SAFETY: By function safety requirement, val is non-null, null-terminated 71 + // and valid for reads for the duration of this function. 72 + let arg = unsafe { CStr::from_char_ptr(val) }; 73 + 74 + crate::error::from_result(|| { 75 + let new_value = T::try_from_param_arg(arg)?; 76 + 77 + // SAFETY: By function safety requirements, this access is safe. 78 + let container = unsafe { &*((*param).__bindgen_anon_1.arg.cast::<SetOnce<T>>()) }; 79 + 80 + container 81 + .populate(new_value) 82 + .then_some(0) 83 + .ok_or(kernel::error::code::EEXIST) 84 + }) 85 + } 86 + 87 + macro_rules! impl_int_module_param { 88 + ($ty:ident) => { 89 + impl ModuleParam for $ty { 90 + fn try_from_param_arg(arg: &BStr) -> Result<Self> { 91 + <$ty as crate::str::parse_int::ParseInt>::from_str(arg) 92 + } 93 + } 94 + }; 95 + } 96 + 97 + impl_int_module_param!(i8); 98 + impl_int_module_param!(u8); 99 + impl_int_module_param!(i16); 100 + impl_int_module_param!(u16); 101 + impl_int_module_param!(i32); 102 + impl_int_module_param!(u32); 103 + impl_int_module_param!(i64); 104 + impl_int_module_param!(u64); 105 + impl_int_module_param!(isize); 106 + impl_int_module_param!(usize); 107 + 108 + /// A wrapper for kernel parameters. 109 + /// 110 + /// This type is instantiated by the [`module!`] macro when module parameters are 111 + /// defined. You should never need to instantiate this type directly. 112 + /// 113 + /// Note: This type is `pub` because it is used by module crates to access 114 + /// parameter values. 115 + pub struct ModuleParamAccess<T> { 116 + value: SetOnce<T>, 117 + default: T, 118 + } 119 + 120 + // SAFETY: We only create shared references to the contents of this container, 121 + // so if `T` is `Sync`, so is `ModuleParamAccess`. 122 + unsafe impl<T: Sync> Sync for ModuleParamAccess<T> {} 123 + 124 + impl<T> ModuleParamAccess<T> { 125 + #[doc(hidden)] 126 + pub const fn new(default: T) -> Self { 127 + Self { 128 + value: SetOnce::new(), 129 + default, 130 + } 131 + } 132 + 133 + /// Get a shared reference to the parameter value. 134 + // Note: When sysfs access to parameters are enabled, we have to pass in a 135 + // held lock guard here. 136 + pub fn value(&self) -> &T { 137 + self.value.as_ref().unwrap_or(&self.default) 138 + } 139 + 140 + /// Get a mutable pointer to `self`. 141 + /// 142 + /// NOTE: In most cases it is not safe deref the returned pointer. 143 + pub const fn as_void_ptr(&self) -> *mut c_void { 144 + core::ptr::from_ref(self).cast_mut().cast() 145 + } 146 + } 147 + 148 + #[doc(hidden)] 149 + /// Generate a static [`kernel_param_ops`](srctree/include/linux/moduleparam.h) struct. 150 + /// 151 + /// # Examples 152 + /// 153 + /// ```ignore 154 + /// make_param_ops!( 155 + /// /// Documentation for new param ops. 156 + /// PARAM_OPS_MYTYPE, // Name for the static. 157 + /// MyType // A type which implements [`ModuleParam`]. 158 + /// ); 159 + /// ``` 160 + macro_rules! make_param_ops { 161 + ($ops:ident, $ty:ty) => { 162 + #[doc(hidden)] 163 + pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops { 164 + flags: 0, 165 + set: Some(set_param::<$ty>), 166 + get: None, 167 + free: None, 168 + }; 169 + }; 170 + } 171 + 172 + make_param_ops!(PARAM_OPS_I8, i8); 173 + make_param_ops!(PARAM_OPS_U8, u8); 174 + make_param_ops!(PARAM_OPS_I16, i16); 175 + make_param_ops!(PARAM_OPS_U16, u16); 176 + make_param_ops!(PARAM_OPS_I32, i32); 177 + make_param_ops!(PARAM_OPS_U32, u32); 178 + make_param_ops!(PARAM_OPS_I64, i64); 179 + make_param_ops!(PARAM_OPS_U64, u64); 180 + make_param_ops!(PARAM_OPS_ISIZE, isize); 181 + make_param_ops!(PARAM_OPS_USIZE, usize);