Skip to content

Commit cdec777

Browse files
committed
rust: module: add support for module softdep info
Add support for declaring module softdeps in the generated module info. The module macro may now include something like the following: module! { ... softdeps { pre: keywrap, post: sha512, ... } Signed-off-by: Dan Robertson <[email protected]>
1 parent fc2b177 commit cdec777

File tree

1 file changed

+168
-96
lines changed

1 file changed

+168
-96
lines changed

rust/module.rs

Lines changed: 168 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#![deny(clippy::perf)]
1010
#![deny(clippy::style)]
1111

12+
use core::fmt;
1213
use proc_macro::{token_stream, Delimiter, Group, TokenStream, TokenTree};
1314

1415
fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
@@ -119,93 +120,6 @@ fn get_byte_string(it: &mut token_stream::IntoIter, expected_name: &str) -> Stri
119120
byte_string
120121
}
121122

122-
fn __build_modinfo_string_base(
123-
module: &str,
124-
field: &str,
125-
content: &str,
126-
variable: &str,
127-
builtin: bool,
128-
) -> String {
129-
let string = if builtin {
130-
// Built-in modules prefix their modinfo strings by `module.`.
131-
format!(
132-
"{module}.{field}={content}",
133-
module = module,
134-
field = field,
135-
content = content
136-
)
137-
} else {
138-
// Loadable modules' modinfo strings go as-is.
139-
format!("{field}={content}", field = field, content = content)
140-
};
141-
142-
format!(
143-
"
144-
{cfg}
145-
#[link_section = \".modinfo\"]
146-
#[used]
147-
pub static {variable}: [u8; {length}] = *b\"{string}\\0\";
148-
",
149-
cfg = if builtin {
150-
"#[cfg(not(MODULE))]"
151-
} else {
152-
"#[cfg(MODULE)]"
153-
},
154-
variable = variable,
155-
length = string.len() + 1,
156-
string = string,
157-
)
158-
}
159-
160-
fn __build_modinfo_string_variable(module: &str, field: &str) -> String {
161-
format!("__{module}_{field}", module = module, field = field)
162-
}
163-
164-
fn build_modinfo_string_only_builtin(module: &str, field: &str, content: &str) -> String {
165-
__build_modinfo_string_base(
166-
module,
167-
field,
168-
content,
169-
&__build_modinfo_string_variable(module, field),
170-
true,
171-
)
172-
}
173-
174-
fn build_modinfo_string_only_loadable(module: &str, field: &str, content: &str) -> String {
175-
__build_modinfo_string_base(
176-
module,
177-
field,
178-
content,
179-
&__build_modinfo_string_variable(module, field),
180-
false,
181-
)
182-
}
183-
184-
fn build_modinfo_string(module: &str, field: &str, content: &str) -> String {
185-
build_modinfo_string_only_builtin(module, field, content)
186-
+ &build_modinfo_string_only_loadable(module, field, content)
187-
}
188-
189-
fn build_modinfo_string_optional(module: &str, field: &str, content: Option<&str>) -> String {
190-
if let Some(content) = content {
191-
build_modinfo_string(module, field, content)
192-
} else {
193-
"".to_string()
194-
}
195-
}
196-
197-
fn build_modinfo_string_param(module: &str, field: &str, param: &str, content: &str) -> String {
198-
let variable = format!(
199-
"__{module}_{field}_{param}",
200-
module = module,
201-
field = field,
202-
param = param
203-
);
204-
let content = format!("{param}:{content}", param = param, content = content);
205-
__build_modinfo_string_base(module, field, &content, &variable, true)
206-
+ &__build_modinfo_string_base(module, field, &content, &variable, false)
207-
}
208-
209123
fn permissions_are_readonly(perms: &str) -> bool {
210124
let (radix, digits) = if let Some(n) = perms.strip_prefix("0x") {
211125
(16, n)
@@ -307,6 +221,118 @@ fn generated_array_ops_name(vals: &str, max_length: usize) -> String {
307221
)
308222
}
309223

224+
struct ModuleInfoStringBuilder<'a> {
225+
counter: usize,
226+
module: &'a str,
227+
}
228+
229+
impl<'a> ModuleInfoStringBuilder<'a> {
230+
fn new(module_str: &'a str) -> ModuleInfoStringBuilder<'a> {
231+
ModuleInfoStringBuilder {
232+
module: module_str,
233+
counter: 0,
234+
}
235+
}
236+
237+
fn build_modinfo_string_base(
238+
&self,
239+
field: &str,
240+
content: &str,
241+
variable: &str,
242+
builtin: bool,
243+
) -> String {
244+
let string = if builtin {
245+
// Built-in modules prefix their modinfo strings by `module.`.
246+
format!(
247+
"{module}.{field}={content}",
248+
module = self.module,
249+
field = field,
250+
content = content
251+
)
252+
} else {
253+
// Loadable modules' modinfo strings go as-is.
254+
format!("{field}={content}", field = field, content = content)
255+
};
256+
257+
format!(
258+
"
259+
{cfg}
260+
#[link_section = \".modinfo\"]
261+
#[used]
262+
pub static {variable}: [u8; {length}] = *b\"{string}\\0\";
263+
",
264+
cfg = if builtin {
265+
"#[cfg(not(MODULE))]"
266+
} else {
267+
"#[cfg(MODULE)]"
268+
},
269+
variable = variable,
270+
length = string.len() + 1,
271+
string = string,
272+
)
273+
}
274+
275+
fn build_modinfo_string_variable(&mut self, field: &str) -> String {
276+
self.counter += 1;
277+
format!(
278+
"__{module}_{field}{counter}",
279+
module = self.module,
280+
field = field,
281+
counter = self.counter,
282+
)
283+
}
284+
285+
fn build_modinfo_string_only_builtin(&mut self, field: &str, content: &str) -> String {
286+
let str_var = self.build_modinfo_string_variable(field);
287+
self.build_modinfo_string_base(field, content, &str_var, true)
288+
}
289+
290+
fn build_modinfo_string_only_loadable(&mut self, field: &str, content: &str) -> String {
291+
let str_var = self.build_modinfo_string_variable(field);
292+
self.build_modinfo_string_base(field, content, &str_var, false)
293+
}
294+
295+
fn build_modinfo_string(&mut self, field: &str, content: &str) -> String {
296+
self.build_modinfo_string_only_builtin(field, content)
297+
+ &self.build_modinfo_string_only_loadable(field, content)
298+
}
299+
300+
fn build_modinfo_string_optional(&mut self, field: &str, content: Option<&str>) -> String {
301+
if let Some(content) = content {
302+
self.build_modinfo_string(field, content)
303+
} else {
304+
"".to_string()
305+
}
306+
}
307+
308+
fn build_modinfo_string_param(&mut self, field: &str, param: &str, content: &str) -> String {
309+
let variable = format!(
310+
"__{module}_{field}_{param}",
311+
module = self.module,
312+
field = field,
313+
param = param
314+
);
315+
let content = format!("{param}:{content}", param = param, content = content);
316+
self.build_modinfo_string_base(field, &content, &variable, true)
317+
+ &self.build_modinfo_string_base(field, &content, &variable, false)
318+
}
319+
}
320+
321+
#[derive(Debug)]
322+
enum Softdep {
323+
Pre(String),
324+
Post(String),
325+
}
326+
327+
impl fmt::Display for Softdep {
328+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
329+
match self {
330+
Softdep::Pre(ref module) => write!(f, "pre: {}", module),
331+
Softdep::Post(ref module) => write!(f, "post: {}", module),
332+
}
333+
}
334+
}
335+
310336
#[derive(Debug, Default)]
311337
struct ModuleInfo {
312338
type_: String,
@@ -316,6 +342,7 @@ struct ModuleInfo {
316342
description: Option<String>,
317343
alias: Option<String>,
318344
params: Option<Group>,
345+
softdeps: Option<Vec<Softdep>>,
319346
}
320347

321348
impl ModuleInfo {
@@ -331,6 +358,7 @@ impl ModuleInfo {
331358
"alias",
332359
"alias_rtnl_link",
333360
"params",
361+
"softdeps",
334362
];
335363
const REQUIRED_KEYS: &[&str] = &["type", "name", "license"];
336364
let mut seen_keys = Vec::new();
@@ -362,6 +390,9 @@ impl ModuleInfo {
362390
info.alias = Some(format!("rtnl-link-{}", expect_byte_string(it)))
363391
}
364392
"params" => info.params = Some(expect_group(it)),
393+
"softdeps" => {
394+
info.softdeps = Some(Self::parse_softdeps(expect_group(it)));
395+
}
365396
_ => panic!(
366397
"Unknown key \"{}\". Valid keys are: {:?}.",
367398
key, EXPECTED_KEYS
@@ -397,6 +428,44 @@ impl ModuleInfo {
397428

398429
info
399430
}
431+
432+
fn parse_softdeps(group: Group) -> Vec<Softdep> {
433+
assert_eq!(group.delimiter(), Delimiter::Brace);
434+
435+
let mut it = group.stream().into_iter();
436+
437+
let mut res = vec![];
438+
439+
while let Some(order) = try_ident(&mut it) {
440+
res.push(Self::parse_softdep(&mut it, &order));
441+
}
442+
443+
expect_end(&mut it);
444+
445+
res
446+
}
447+
448+
fn parse_softdep(it: &mut token_stream::IntoIter, order: &str) -> Softdep {
449+
assert_eq!(expect_punct(it), ':');
450+
let module = expect_ident(it);
451+
let softdep = match &*order {
452+
"pre" => Softdep::Pre(module),
453+
"post" => Softdep::Post(module),
454+
_ => panic!("failed to parse invalid softdep '{}: {}", order, module),
455+
};
456+
assert_eq!(expect_punct(it), ',');
457+
softdep
458+
}
459+
460+
fn encode_softdeps<'a>(&self, str_builder: &mut ModuleInfoStringBuilder<'a>) -> String {
461+
match self.softdeps {
462+
Some(ref softdeps) => softdeps.iter().fold(String::new(), |mut acc, new| {
463+
acc.push_str(&str_builder.build_modinfo_string("softdep", &format!("{}", new)));
464+
acc
465+
}),
466+
None => String::new(),
467+
}
468+
}
400469
}
401470

402471
/// Declares a kernel module.
@@ -483,11 +552,14 @@ pub fn module(ts: TokenStream) -> TokenStream {
483552
let mut it = ts.into_iter();
484553

485554
let info = ModuleInfo::parse(&mut it);
555+
let mut str_builder = ModuleInfoStringBuilder::new(&info.name);
486556

487557
let name = info.name.clone();
488558

489559
let mut array_types_to_generate = Vec::new();
490560
let mut params_modinfo = String::new();
561+
let softdeps = info.encode_softdeps(&mut str_builder);
562+
491563
if let Some(params) = info.params {
492564
assert_eq!(params.delimiter(), Delimiter::Brace);
493565

@@ -532,14 +604,12 @@ pub fn module(ts: TokenStream) -> TokenStream {
532604
}
533605
};
534606

535-
params_modinfo.push_str(&build_modinfo_string_param(
536-
&name,
607+
params_modinfo.push_str(&str_builder.build_modinfo_string_param(
537608
"parmtype",
538609
&param_name,
539610
&param_kernel_type,
540611
));
541-
params_modinfo.push_str(&build_modinfo_string_param(
542-
&name,
612+
params_modinfo.push_str(&str_builder.build_modinfo_string_param(
543613
"parm",
544614
&param_name,
545615
&param_description,
@@ -761,16 +831,18 @@ pub fn module(ts: TokenStream) -> TokenStream {
761831
{params_modinfo}
762832
763833
{generated_array_types}
834+
{softdeps}
764835
",
765836
type_ = info.type_,
766837
name = info.name,
767-
author = &build_modinfo_string_optional(&name, "author", info.author.as_deref()),
768-
description = &build_modinfo_string_optional(&name, "description", info.description.as_deref()),
769-
license = &build_modinfo_string(&name, "license", &info.license),
770-
alias = &build_modinfo_string_optional(&name, "alias", info.alias.as_deref()),
771-
file = &build_modinfo_string_only_builtin(&name, "file", &file),
838+
author = &str_builder.build_modinfo_string_optional("author", info.author.as_deref()),
839+
description = &str_builder.build_modinfo_string_optional("description", info.description.as_deref()),
840+
license = &str_builder.build_modinfo_string("license", &info.license),
841+
alias = &str_builder.build_modinfo_string_optional("alias", info.alias.as_deref()),
842+
file = &str_builder.build_modinfo_string_only_builtin("file", &file),
772843
params_modinfo = params_modinfo,
773844
generated_array_types = generated_array_types,
845+
softdeps = softdeps,
774846
initcall_section = ".initcall6.init"
775847
).parse().expect("Error parsing formatted string into token stream.")
776848
}

0 commit comments

Comments
 (0)