Repository navigation
Expand file tree
/
Copy pathload_parameters.rs
More file actions
140 lines (123 loc) · 4.86 KB
/
Copy pathload_parameters.rs
File metadata and controls
140 lines (123 loc) · 4.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! Load-time module parameters.
//!
//! Linux 6.18 has the C module-parameter ABI but predates parameter support in
//! Rust's `module!` macro. Registration lives here so both API generations use
//! the same implementation.
use core::{cell::UnsafeCell, ptr};
use kernel::{bindings, ffi};
// Use the C module-loader symbol directly. Rust's `module!` macro does not
// expose `THIS_MODULE` at the crate root on every supported kernel.
#[cfg(MODULE)]
#[allow(improper_ctypes)]
unsafe extern "C" {
static __this_module: kernel::types::Opaque<bindings::module>;
}
#[repr(transparent)]
pub(super) struct ModuleParameter<T>(UnsafeCell<T>);
// SAFETY: These parameters have permission 0, so the module loader is the only
// writer and finishes parsing them before module initialization.
unsafe impl<T: Send> Sync for ModuleParameter<T> {}
impl<T: Copy> ModuleParameter<T> {
const fn new(default: T) -> Self {
Self(UnsafeCell::new(default))
}
pub(super) fn value(&self) -> T {
// SAFETY: Module loading publishes the parsed value before any ZeroFS
// callback can read it, and permission 0 prevents later sysfs writes.
unsafe { ptr::read_volatile(self.0.get()) }
}
const fn as_void_ptr(&self) -> *mut ffi::c_void {
self.0.get().cast()
}
}
#[repr(transparent)]
#[allow(dead_code)]
struct RegisteredParameter(bindings::kernel_param);
// SAFETY: The descriptor is immutable after its static initialization; the
// kernel only follows its pointers while this module remains loaded.
unsafe impl Sync for RegisteredParameter {}
const fn string_bytes<const N: usize>(value: &str) -> [u8; N] {
let bytes = value.as_bytes();
assert!(bytes.len() == N);
let mut output = [0; N];
let mut index = 0;
while index < N {
output[index] = bytes[index];
index += 1;
}
output
}
macro_rules! module_parameter {
(
$name:ident: $type:ty = $default:expr,
ops: $ops:ident,
description: $description:literal
) => {
#[allow(non_upper_case_globals)]
pub(super) static $name: ModuleParameter<$type> = ModuleParameter::new($default);
const _: () = {
const PARAMETER_NAME: &kernel::str::CStr = kernel::c_str!(stringify!($name));
#[link_section = "__param"]
#[used(compiler)]
static DESCRIPTOR: RegisteredParameter = RegisteredParameter(bindings::kernel_param {
name: kernel::str::as_char_ptr_in_const_context(PARAMETER_NAME),
// SAFETY: The loader constructs `__this_module` before parsing
// parameters and keeps it live until the module is unloaded.
#[cfg(MODULE)]
mod_: unsafe { __this_module.get() },
#[cfg(not(MODULE))]
mod_: ptr::null_mut(),
// `param_ops_*` are immutable, exported kernel descriptors
// that remain live for the module's lifetime.
ops: core::ptr::addr_of!(bindings::$ops),
perm: 0,
level: -1,
flags: 0,
__bindgen_anon_1: bindings::kernel_param__bindgen_ty_1 {
arg: $name.as_void_ptr(),
},
});
#[cfg(MODULE)]
const PARAMETER_TYPE_INFO: &str =
concat!("parmtype=", stringify!($name), ":", stringify!($type), "\0");
#[cfg(MODULE)]
#[link_section = ".modinfo"]
#[used(compiler)]
static PARAMETER_TYPE: [u8; PARAMETER_TYPE_INFO.len()] =
string_bytes(PARAMETER_TYPE_INFO);
#[cfg(MODULE)]
const PARAMETER_DESCRIPTION_INFO: &str =
concat!("parm=", stringify!($name), ":", $description, "\0");
#[cfg(MODULE)]
#[link_section = ".modinfo"]
#[used(compiler)]
static PARAMETER_DESCRIPTION: [u8; PARAMETER_DESCRIPTION_INFO.len()] =
string_bytes(PARAMETER_DESCRIPTION_INFO);
};
};
}
module_parameter!(
server_ipv4: u32 = 0x7f00_0001,
ops: param_ops_uint,
description: "ZeroFS IPv4 address used by none/tcp mount sources; 0 disables it"
);
module_parameter!(
server_ipv4_peer: u32 = 0,
ops: param_ops_uint,
description: "The HA peer for none/tcp mount sources; 0 disables it"
);
module_parameter!(
server_port: u16 = 5564,
ops: param_ops_ushort,
description: "ZeroFS TCP port used by none/tcp mount sources"
);
module_parameter!(
request_timeout_ms: u32 = 5_000,
ops: param_ops_uint,
description: "Per-phase ZeroFS I/O, admission, and receive-silence timeout in milliseconds"
);
module_parameter!(
reconnect_grace_ms: u32 = 120_000,
ops: param_ops_uint,
description: "Longest a request waits for reconnect and session replay, in milliseconds; a mutation resend is bounded by the protocol retry horizon regardless"
);