[3/3] rust: macros: Allow specifying multiple module aliases

Message ID 20230224-rust-macros-v1-3-b39fae46e102@asahilina.net
State New
Headers
Series rust: Miscellaneous macro improvements |

Commit Message

Asahi Lina Feb. 24, 2023, 7:25 a.m. UTC
  Modules can (and usually do) have multiple alias tags, in order to
specify multiple possible device matches for autoloading. Allow this by
changing the alias ModuleInfo field to an Option<Vec<String>>.

Note: For normal device IDs this is autogenerated by modpost (which is
not properly integrated with Rust support yet), so it is useful to be
able to manually add device match aliases for now, and should still be
useful in the future for corner cases that modpost does not handle.

This pulls in the expect_group() helper from the rfl/rust branch
(with credit to authors).

Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Co-developed-by: Finn Behrens <me@kloenk.dev>
Signed-off-by: Finn Behrens <me@kloenk.dev>
Co-developed-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Signed-off-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Signed-off-by: Asahi Lina <lina@asahilina.net>
---
 rust/macros/helpers.rs | 10 +++++++++-
 rust/macros/module.rs  | 30 +++++++++++++++++++++++++-----
 2 files changed, 34 insertions(+), 6 deletions(-)
  

Comments

Greg KH Feb. 24, 2023, 7:38 a.m. UTC | #1
On Fri, Feb 24, 2023 at 04:25:57PM +0900, Asahi Lina wrote:
> Modules can (and usually do) have multiple alias tags, in order to
> specify multiple possible device matches for autoloading. Allow this by
> changing the alias ModuleInfo field to an Option<Vec<String>>.

Note, manually specifying the MODULE_ALIAS is only really ever done for
platform drivers today (and I would argue we need to fix that up),
otherwise the use of MODULE_DEVICE_TABLE() should really really be used
instead of having to manually specify aliases.

And why would a module alias be needed for new (i.e. rust) code anyway?
You aren't trying to do any backwards-compatibility stuff yet :)

Or is this just for a platform driver?  It's hard to review
infrastructure changes without seeing any real users :(

thanks,

greg k-h
  
Asahi Lina Feb. 24, 2023, 12:41 p.m. UTC | #2
On 24/02/2023 16.38, Greg KH wrote:
> On Fri, Feb 24, 2023 at 04:25:57PM +0900, Asahi Lina wrote:
>> Modules can (and usually do) have multiple alias tags, in order to
>> specify multiple possible device matches for autoloading. Allow this by
>> changing the alias ModuleInfo field to an Option<Vec<String>>.
> 
> Note, manually specifying the MODULE_ALIAS is only really ever done for
> platform drivers today (and I would argue we need to fix that up),
> otherwise the use of MODULE_DEVICE_TABLE() should really really be used
> instead of having to manually specify aliases.

That's the plan, I just added this before adding support for
MODULE_DEVICE_TABLE() when I first realized that it wasn't yet in there!
We were briefly hardcoding the bus aliases for downstream kernels
because the depmod stuff couldn't work with the way device ID tables
were done in Rust downstream at the time (and I only noticed the first
time I tried to build it as a module, since I always develop with
monolithic kernels). That's fixed now ^^

However, the issue is that right now the module macro already takes a
single optional alias, and that doesn't make sense as an API. We could
remove support for this entirely (if I get my Rust MODULE_DEVICE_TABLE()
implementation in, there will be zero users of the alias argument as far
as I know), or add support for multiple aliases. But I think just
leaving it as a single alias doesn't really make sense? It doesn't
represent the way module aliases work, which is 0..N.

I'm fine with removing it if people prefer that, I just thought that for
something as basic as module metadata we might as well do it properly
even if there are no users right now, since it's already half in there...

~~ Lina
  
Greg KH Feb. 24, 2023, 12:49 p.m. UTC | #3
On Fri, Feb 24, 2023 at 09:41:08PM +0900, Asahi Lina wrote:
> On 24/02/2023 16.38, Greg KH wrote:
> > On Fri, Feb 24, 2023 at 04:25:57PM +0900, Asahi Lina wrote:
> >> Modules can (and usually do) have multiple alias tags, in order to
> >> specify multiple possible device matches for autoloading. Allow this by
> >> changing the alias ModuleInfo field to an Option<Vec<String>>.
> > 
> > Note, manually specifying the MODULE_ALIAS is only really ever done for
> > platform drivers today (and I would argue we need to fix that up),
> > otherwise the use of MODULE_DEVICE_TABLE() should really really be used
> > instead of having to manually specify aliases.
> 
> That's the plan, I just added this before adding support for
> MODULE_DEVICE_TABLE() when I first realized that it wasn't yet in there!
> We were briefly hardcoding the bus aliases for downstream kernels
> because the depmod stuff couldn't work with the way device ID tables
> were done in Rust downstream at the time (and I only noticed the first
> time I tried to build it as a module, since I always develop with
> monolithic kernels). That's fixed now ^^
> 
> However, the issue is that right now the module macro already takes a
> single optional alias, and that doesn't make sense as an API. We could
> remove support for this entirely (if I get my Rust MODULE_DEVICE_TABLE()
> implementation in, there will be zero users of the alias argument as far
> as I know), or add support for multiple aliases. But I think just
> leaving it as a single alias doesn't really make sense? It doesn't
> represent the way module aliases work, which is 0..N.
> 
> I'm fine with removing it if people prefer that, I just thought that for
> something as basic as module metadata we might as well do it properly
> even if there are no users right now, since it's already half in there...

How about just removing it so that people don't think it is something
that they really should be doing and adding real MODULE_DEVICE_TABLE()
support instead?

Although the first filesystem that gets written will need the
MODULE_ALIAS() logic added back, oh well.

Anyway, no objection for me for this for now, just trying to point out
that drivers really should not be using MODULE_ALIAS() at all.

thanks,

greg k-h
  
Vincenzo Palazzo March 1, 2023, 5:19 p.m. UTC | #4
> Modules can (and usually do) have multiple alias tags, in order to
> specify multiple possible device matches for autoloading. Allow this by
> changing the alias ModuleInfo field to an Option<Vec<String>>.
>
> Note: For normal device IDs this is autogenerated by modpost (which is
> not properly integrated with Rust support yet), so it is useful to be
> able to manually add device match aliases for now, and should still be
> useful in the future for corner cases that modpost does not handle.
>
> This pulls in the expect_group() helper from the rfl/rust branch
> (with credit to authors).
>
> Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> Co-developed-by: Finn Behrens <me@kloenk.dev>
> Signed-off-by: Finn Behrens <me@kloenk.dev>
> Co-developed-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
> Signed-off-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
> Signed-off-by: Asahi Lina <lina@asahilina.net>
> ---

Reviewed-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
  

Patch

diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs
index 65706ecc007e..15bf0c892421 100644
--- a/rust/macros/helpers.rs
+++ b/rust/macros/helpers.rs
@@ -1,6 +1,6 @@ 
 // SPDX-License-Identifier: GPL-2.0
 
-use proc_macro::{token_stream, Punct, TokenTree};
+use proc_macro::{token_stream, Group, Punct, TokenTree};
 
 pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
     if let Some(TokenTree::Ident(ident)) = it.next() {
@@ -56,6 +56,14 @@  pub(crate) fn expect_string_ascii(it: &mut token_stream::IntoIter) -> String {
     string
 }
 
+pub(crate) fn expect_group(it: &mut token_stream::IntoIter) -> Group {
+    if let TokenTree::Group(group) = it.next().expect("Reached end of token stream for Group") {
+        group
+    } else {
+        panic!("Expected Group");
+    }
+}
+
 pub(crate) fn expect_end(it: &mut token_stream::IntoIter) {
     if it.next().is_some() {
         panic!("Expected end");
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
index 07503b242d2d..92cb35c235e1 100644
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@ -1,9 +1,27 @@ 
 // SPDX-License-Identifier: GPL-2.0
 
 use crate::helpers::*;
-use proc_macro::{token_stream, Literal, TokenStream, TokenTree};
+use proc_macro::{token_stream, Delimiter, Literal, TokenStream, TokenTree};
 use std::fmt::Write;
 
+fn expect_string_array(it: &mut token_stream::IntoIter) -> Vec<String> {
+    let group = expect_group(it);
+    assert_eq!(group.delimiter(), Delimiter::Bracket);
+    let mut values = Vec::new();
+    let mut it = group.stream().into_iter();
+
+    while let Some(val) = try_string(&mut it) {
+        assert!(val.is_ascii(), "Expected ASCII string");
+        values.push(val);
+        match it.next() {
+            Some(TokenTree::Punct(punct)) => assert_eq!(punct.as_char(), ','),
+            None => break,
+            _ => panic!("Expected ',' or end of array"),
+        }
+    }
+    values
+}
+
 struct ModInfoBuilder<'a> {
     module: &'a str,
     counter: usize,
@@ -78,7 +96,7 @@  struct ModuleInfo {
     name: String,
     author: Option<String>,
     description: Option<String>,
-    alias: Option<String>,
+    alias: Option<Vec<String>>,
 }
 
 impl ModuleInfo {
@@ -112,7 +130,7 @@  impl ModuleInfo {
                 "author" => info.author = Some(expect_string(it)),
                 "description" => info.description = Some(expect_string(it)),
                 "license" => info.license = expect_string_ascii(it),
-                "alias" => info.alias = Some(expect_string_ascii(it)),
+                "alias" => info.alias = Some(expect_string_array(it)),
                 _ => panic!(
                     "Unknown key \"{}\". Valid keys are: {:?}.",
                     key, EXPECTED_KEYS
@@ -163,8 +181,10 @@  pub(crate) fn module(ts: TokenStream) -> TokenStream {
         modinfo.emit("description", &description);
     }
     modinfo.emit("license", &info.license);
-    if let Some(alias) = info.alias {
-        modinfo.emit("alias", &alias);
+    if let Some(aliases) = info.alias {
+        for alias in aliases {
+            modinfo.emit("alias", &alias);
+        }
     }
 
     // Built-in modules also export the `file` modinfo string.