Le code initial de l'infrastructure Rust a été fusionné dans l'arbre Git principal de Linux 6.1 le 3octobre par Linus Torvalds. Ce nouveau code initial de 12 500 lignes ne fournit que l'infrastructure de base et une intégration très élémentaire, tandis que les futures demandes d'extraction ajouteront plus d'abstractions de sous-systèmes, divers pilotes écrits en Rust, et plus encore. La construction du noyau Linux avec le support Rust reste facultative.
Dans un message adressé à la communauté du noyau, Torvalds a déclaré : « l'arbre a une base récente, mais est fondamentalement dans linux-next depuis un an et demi. Il a été mis à jour sur la base des retours du Kernel Maintainer's Summit. Miguel est le mainteneur principal, et j'aide quand c'est nécessaire. Notre plan est que l'arbre passe à la pratique standard de non-rebasage une fois que cette série initiale d'infrastructures sera terminée. Le contenu est le minimum absolu pour permettre la construction du code Rust dans le noyau, avec beaucoup plus d'interfaces (et de pilotes - NVMe, 9p, M1 GPU) sur le chemin ».
Selon Jonathan Corbet, aucun système doté d'un noyau 6.1 de production n'exécutera de code Rust, mais ce changement donne aux développeurs du noyau une chance de jouer avec le langage dans le contexte du noyau et de se faire une idée de la façon dont le développement Rust se déroule. La conclusion la plus probable pour la plupart des développeurs est qu'il n'y a pas encore assez de Rust dans le noyau pour faire quoi que ce soit d'intéressant.
Jonathan Corbet a eu son premier aperçu des sources BSD Unix en 1981, lorsqu'un instructeur de l'Université du Colorado l'a laissé « corriger » l'algorithme de pagination. Depuis, il n'a cessé de fouiller dans tous les systèmes sur lesquels il a pu mettre la main, travaillant au passage sur des pilotes pour les systèmes VAX, Sun, Ardent et x86. Il a obtenu son premier système Linux en 1993, et n'a jamais regardé en arrière. Corbet est actuellement cofondateur et rédacteur en chef de Linux Weekly News.
Le travail sur Rust pour le noyau Linux est en cours depuis quelques années, et il a abouti à la création de beaucoup de code de soutien et de quelques pilotes intéressants à regarder. D'autres initiatives sont en cours, notamment l'écriture d'un pilote graphique Apple en langage Rust. Pour la fusion initiale dans le noyau principal, Linus Torvalds a clairement indiqué qu'il fallait inclure le moins de fonctionnalités possibles. Ces pilotes et leur code de support ont donc été supprimés et doivent attendre une future version du noyau. Ce qui est présent est le support nécessaire pour construire un module qui peut être chargé dans le noyau, ainsi qu'un petit module d'exemple.
Pour rappel, le projet Rust for Linux vise à introduire un nouveau langage de programmation système dans le noyau. Rust a une propriété clé qui le rend très intéressant à considérer comme le deuxième langage du noyau : il garantit qu'aucun comportement indéfini n'a lieu (tant que le code non sécurisé est sain). Cela inclut l'absence d'erreurs de type use after-free, double frees, data races, etc. Après 31 ans, un deuxième langage sera donc admis pour le développement du noyau. Les débats y relatifs tournent au tour de la possibilité d’une mise au rebut du C au profit du langage Rust.
Construction du support Rust
« Le premier défi que les développeurs intéressés rencontreront est de construire le support Rust », déclare Jonathan Corbet. Le processus de configuration du noyau recherche les prérequis sur le système de construction et, s'ils ne sont pas présents, désactive silencieusement les options Rust afin qu'elles n'apparaissent même pas dans, par exemple, make menuconfig. Jonathan Corbet, bien qu'ayant installé Rust sur le système en question, s'est heurté à ce problème et a donc été contraint au processus ignominieux de lire la documentation pour comprendre ce qui manquait.
La construction du support Rust nécessite des versions spécifiques du compilateur Rust et de l'utilitaire bindgen - plus précisément, Rust 1.62.0 et bindgen 0.56.0. Si le système cible possède des versions plus récentes, le processus de configuration émettra des avertissements mais se poursuivra quand même. Plus gênant pour quiconque essaie de construire avec la chaîne d'outils Rust fournie par son distributeur, le processus de construction a également besoin de la source de la bibliothèque standard Rust afin de pouvoir construire sa propre version des crates core et alloc.
« Jusqu'à ce que les distributeurs commencent à fournir des paquets "Rust pour le noyau", il sera un peu difficile de placer ce code à un endroit où le processus de construction le trouvera », déclare Jonathan Corbet. « La façon d'obtenir facilement cette dépendance est de jeter l'éponge, d'abandonner la chaîne d'outils du distributeur et d'installer tout depuis les dépôts Rust à la place », poursuit-il.
La page getting started décrit comment le faire ; inévitablement, cela implique une de ces opérations de mise en confiance curl|bash. Le programme d'installation ne s'intéresse absolument pas à l'endroit où l'on souhaite que les éléments Rust soient installés (ils vont dans ~/.cargo) et modifie silencieusement les scripts de démarrage Bash de l'utilisateur pour ajouter le nouveau répertoire dans la variable PATH. Le résultat final fonctionne cependant et permet d'installer facilement les dépendances nécessaires.
Le module d'exemple
Une fois cela fait, le système de configuration du noyau consentira à définir l'option CONFIG_RUST ; une option supplémentaire permettra de construire le module d'exemple. Ce module (samples/rust/rust_minimal.rs) est en effet minimal, mais il est suffisant pour avoir une idée de ce à quoi ressemblera le code du noyau en Rust. Il commence par l'équivalent Rust d'une ligne #include :
use kernel::prelude::*;
Il reprend les déclarations trouvées dans rust/kernel/prelude.rs, en rendant disponibles quelques types, fonctions et macros.
Un module de noyau écrit en C comprend un certain nombre d'appels à des macros comme MODULE_DESCRIPTION() et MODULE_LICENSE() qui stockent des métadonnées sur le module dans une section ELF séparée. Les macros module_init() et module_exit() identifient respectivement les fonctions constructeur et destructeur du module. L'équivalent Rust met une grande partie de ce passe-partout dans un seul appel de macro :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 | module! { type: RustMinimal, name: b"rust_minimal", author: b"Rust for Linux Contributors", description: b"Rust minimal sample", license: b"GPL", } |
Cette macro est exigeante quant à l'ordre des différents champs et se « plaindra » si le développeur se trompe. En plus de rassembler toutes ces informations en un seul appel, la macro module ! inclut une entrée type : qui sera le pointeur vers le code réel du module. Le développeur devra fournir un type qui fait quelque chose d'intéressant. Dans l'exemple de module, ce type ressemble à ceci :
Code : | Sélectionner tout |
1 2 3 | struct RustMinimal { numbers: Vec<i32>, } |
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | impl kernel::Module for RustMinimal { fn init(_module: &'static ThisModule) -> Result<Self> { pr_info!("Rust minimal sample (init)\n"); pr_info!("Am I built-in? {}\n", !cfg!(MODULE)); let mut numbers = Vec::new(); numbers.try_push(72)?; numbers.try_push(108)?; numbers.try_push(200)?; Ok(RustMinimal { numbers }) } } |
La fonction init() est censée faire le travail habituel d'initialisation du module. Dans ce cas, elle bavarde un peu dans le journal du système (montrant au passage la macro cfg !() qui peut être utilisée pour interroger les paramètres de configuration du noyau au moment de la compilation). Il alloue ensuite un Vec mutable et tente d'y placer trois nombres. L'utilisation de try_push() est importante ici : un Vec se redimensionnera lui-même si nécessaire. Cela implique l'allocation de mémoire, qui peut échouer dans l'environnement du noyau. Si cette allocation échoue, try_push() renverra un statut d'échec et cela, à son tour, fera que init() renvoie un échec (c'est ce que fait le "?" à la fin de la ligne).
Enfin, si tout se passe bien, elle renvoie une structure RustMinimal avec le Vec alloué et un statut de réussite. Puisque ce module n'a pas interagi avec d'autres sous-systèmes du noyau, il ne fera rien d'autre que d'attendre patiemment d'être retiré. Il n'y a pas de fonction pour la suppression du module dans le trait Kernel::Module ; à la place, un simple destructeur pour le type RustMinimal est utilisé :
Code : | Sélectionner tout |
1 2 3 4 5 6 | impl Drop for RustMinimal { fn drop(&mut self) { pr_info!("My numbers are {:?}\n", self.numbers); pr_info!("Rust minimal sample (exit)\n"); } } |
Cette fonction affiche les nombres qui ont été stockés dans le Vec au moment de l'initialisation (confirmant ainsi que les données ont survécu entre-temps) et retourne ; après cela, le module sera retiré et sa mémoire libérée. Il ne semble pas y avoir de moyen de faire échouer la suppression d'un module, ce qui doit parfois se produire dans les modules du monde réel.
« C'est, en première estimation, l'étendue de ce qui peut être fait avec les modules du noyau Rust en 6.1. Torvalds a demandé quelque chose qui pourrait faire "hello world" et c'est ce que nous avons obtenu. C'est quelque chose avec lequel on peut jouer, mais qui ne peut être utilisé pour aucune sorte de programmation réelle du noyau à ce stade », déclare Jonathan Corbet.
« Cette situation va, espérons-le, changer dans un avenir proche. La prochaine étape pour les développeurs de Rust-for-Linux sera de commencer à ajouter une partie de l'infrastructure qu'ils ont créée pour s'interfacer avec d'autres sous-systèmes du noyau. Cela permettra d'écrire du code réel pour le noyau et, tout aussi important, de montrer à quoi ressembleront les abstractions nécessaires pour travailler avec d'autres sous-systèmes du noyau », ajoute-t-il.
Source : LWN
Et vous ?
Quel est votre avis sur le sujet ?
Partagez-vous l'avis de qui estime qu'« il n'y aurait pas encore assez de Rust dans le noyau pour faire quoi que ce soit d'intéressant » ?
Voir aussi :
L'inclusion de Rust for Linux à la version 6.1 du noyau est désormais en cours comme souhaité par Linus Torvalds et va rendre possible le développement de pilotes dans un autre langage que le C
Rust for Linux est officiellement fusionné, le support initial de Rust for Linux fournit l'infrastructure de base et une intégration élémentaire