Design d'OS : Pourquoi le Hurd est-il si différent ?

Souvenez-vous de la « prise de becs » Tanenbaum / Torvalds il y a huit ans sur comp.os.minix. A l'époque, Andy Tanenbaum critiquait la décision de Linus Torvalds de développer un kernel monolithique. A grand recours d'arguments de toutes sortes, les deux « personnages » ont bataillé longuement sans aucun dénouement possible. Depuis, la guerre de position « Kernel monolithique » Vs « Micro Kernel » fait toujours rage dans certaines discussions. A l'époque, la question était surtout de savoir laquelle des deux architectures était la plus portable et la plus moderne. Un autre point de mire de ce genre de discussions était la vitesse des micro-kernels.

Aujourd'hui, le fond du problème n'est plus vraiment là. En effet, les micro-kernels sont maintenant tout aussi rapides que les kernels traditionnels et d'un autre côté, Linus a prouvé que la facilité de portage était une question de design du code et non du design de l'OS lui-même (voir explications de Linus dans « Tribune Libre » [O'Reilly]). Mais pourquoi, alors, s'intéresser aux micro-kernels si le design habituel fait l'affaire ? Le problème est ailleurs ...

La nouvelle version du kernel linux (2.4) totalisera quelques 100 Mo de code source. En plus du support matériel qui est naturellement la tâche d'un noyau, un très grand nombre de fonctionnalités « logicielles » sont présentes. On compte parmi celles-ci :

  • le support de protocoles réseaux (TCP/IP, IPX, AppleTalk, DECnet ...)
  • la gestion des systèmes de fichiers (disque ou réseau)
  • le support de différents formats d'exécutables (ELF, a.out ...)
  • la gestion sur pseudo fs /proc
  • ou encore le « kernel httpd acceleration daemon », qui est un serveur Web minimal intégré au kernel.

    Ces différents points représentent exactement ce qui, selon la philosophie du Hurd, doit être éliminé du kernel.

    Un OS

    Le but d'un OS est de permettre à différents programmes de partager un ordinateur de manière efficace et productive. Pour cela, il incorpore des mécanismes de protection de mémoire, de partage de temps, d'accès coordonnés aux périphériques d'entrées / sorties et d'autres services du même type. Les OS multi utilisateurs permettent également à plusieurs personnes de partager le même ordinateur. Dans ce cas, il faut mettre en place des mécanismes supplémentaires empêchant les utilisateurs de se nuire les uns les autres, tout en leur permettant le partage des ressources et l'accès aux dispositifs matériels. Voilà exactement ce qu'est un OS.

    Passons donc à l'implémentation de ces fonctionnalités. La méthode traditionnelle pour implémenter tout cela, est de tout regrouper dans un seul gros programme : le kernel. On fait alors une séparation distincte entre le système et les applications utilisateurs. Le kernel est accessible par tous les utilisateurs via ce qu'on appelle des appels systèmes. Lorsque les applications ont besoin d'une fonctionnalité système, elle font ainsi appel au kernel.

    L'endroit privilégié pour ajouter des fonctionnalité au système est, selon ce shéma de principe « le gros programme commun à tous ». De ce fait, le kernel monolithique grossi au fil du temps et des ajouts de fonctionnalités. Ceci finit par poser un gros problème. En effet, un utilisateur souhaitant ajouter une fonctionnalité (comme un nouveau support FS), doit connaître et comprendre une grande partie du code existant, avoir accès aux sources du kernel et posséder les permissions nécessaires. Ainsi, seule une petite partie des utilisateurs est en mesure d'ajouter son code au kernel. Une autre conséquence est la nécessité de centraliser le développement du kernel. Dans le cas de Linux, Linus, Alan Cox et quelques autres personnes ont la tâche ardue de choisir et de décider de l'ajout des contributions dans les sources officielles du kernel. Il arrive parfois que cela provoque quelques querelles (comme avec l'ajout d'LVM ou de ReiserFS). Bien que cela puisse paraître parfois totalitaire, l'impartialité de l'équipe de développement officielle de Linux DOIT être sans faille. En effet, ajouter une nouvelle interface dans le kernel est comme s'attacher une nouvelle chaîne au pied. Si cette interface est mal implémentée ou mal définie, vous ne pourrez rien corriger dans le futur. Des programmes utilisateurs en feront usage et vous serez obligé de garantir une compatibilité au fil des versions : vous traînez un boulet. Enfin, dernière conséquence importante de l'aspect monolithique du design traditionnel, le problème du debuggage. Debugger un kernel ou un simple module est une tâche difficile et risquée. Il est hors de question de tester un composant du kernel sur une machine de production. Le risque de crasher le système dans son intégralité est omniprésent et si cela arrivait, c'est l'ensemble des utilisateurs qui se retrouverait bloqué par votre faute.

    Les concepts définis dans le Hurd sont strictement opposés à ce qui vient d'être dit. Le kernel lui-même se borne à respecter la définition la plus stricte du terme, on parle alors de micro-kernel. Dans le cas du GNU / Hurd, il s'agit de GnuMach. Par dessus ce micro-kernel, sont lancés des serveurs, une horde de serveurs pour être précis. L'utilisation des micro-kernels n'est pas une idée récente. Le but poursuivi est de placer un maximum de fonctionnalités en dehors du kernel (mode système) pour les implémenter dans des applications (mode utilisateur). MkLinux est un système utilisant ce principe. Il s'agit d'un serveur Linux fonctionnant sur un micro-kernel Mach; on parle alors de système mono-serveur. Malheureusement, ceci ne résout qu'une partie du problème. Les fonctionnalités sont effectivement exportées vers le serveur Linux, mais le « gros programme » est toujours présent. Les problèmes de connaissance de « l'existant » restent présents.

    Le Hurd est un OS multi-serveurs. Ce n'est donc plus un serveur unique mais une « horde » de serveurs fonctionnant au dessus de Mach. Seule une très faible partie de ces serveurs a besoin de privilèges particuliers. C'est le cas, par exemple, du serveur d'authentification qui a la charge de vérifier les identités des utilisateurs.

    Pourquoi est-ce novateur ?

    L'architecture du Hurd permet le remplacement arbitraire de la majorité du système. Ainsi, implémenter un nouveau protocole réseau ou un nouveau support de système de fichiers se résume à l'écriture d'un nouveau serveur. En clair, n'importe quel utilisateur peut changer les parties du système qu'il n'aime pas. Chose absolument impossible avec un kernel monolithique traditionnel.

    Un exemple simple est le translator ftpfs (un translator est un serveur Hurd). Celui-ci permet le FTP transparent, c'est-à-dire l'accès aux serveurs FTP via l'arborescence du système de fichiers. Dans la pratique, vous liez un répertoire de votre arborescence avec le translator ftpfs. Ensuite, les commandes classiques (ls, cd, cp) vous permettent de manipuler les fichiers du serveur FTP comme s'il s'agissait de fichiers sur un FS local.

    Exemple :

    ls
    /ftp/ftp.debian.org/debian/dists/unstable/main/binary-hurd-i386
    
    cp
    /ftp/ftp.debian.org/debian/dists/unstable/main/binary-hurd-i386/Release ~/
    

    Il existe des FTP transparents dans d'autres systèmes, mais ils nécessitent les privilèges root en raison de l'accès direct au système de fichiers. Avec le Hurd, les translators s'exécutent avec les privilèges de l'utilisateur auquel appartient l'inode (point d'accès). Tout un chacun peut donc utiliser ftpfs sur un répertoire qu'il possède.

    Un autre exemple est le serveur crash. Celui-ci est sollicité lorsqu'une application recoit un signal d'erreur fatale (dans le cas d'une violation de l'espace mémoire par exemple). La tâche du serveur crash, est de réagir pour corriger le problème. Le serveur crash livré avec le Hurd permet de suspendre le groupe de processus, de tuer le processus ou de dumper un fichier core. Si l'utilisateur n'est pas satisfait de ces fonctionnalités, il peut développer son propre serveur crash pour, par exemple générer automatiquement, en plus du fichier core, un fichier d'état regroupant diverses informations (variable d'environnement, espace disque, etc). L'étendue des possibilités est presque infinie. Dernier exemple : le serveur shadowfs (ou unionfs). Ce serveur / translator permettra la fusion intelligente de systèmes de fichiers ou de répertoires. Pour imaginer cela, vous pouvez considérer le serveur comme une sorte d'inode symbolique. Il permettra par exemple, de fusionner les répertoires /bin, X11R6/bin et local/bin dans un seul répertoire de binaires. Ce dernier n'aura pas d'existence physique sur l'unité de stockage, il sera la fusion de plusieurs autres répertoires.

    Plus impressionnant, ceci permettra de mettre en place un système dans lequel une version originale de certaines données seront stockées en lecture seule. Ensuite, chaque utilisateur aura sa propre « vision » des fichiers. Il pourra apporter des modifications mais seules les différences entre l'original et sa version seront stockées, et ce, uniquement pour lui. Ainsi, chaque utilisateur aura sa version des fichiers à partir d'un seul et même groupe d'originaux non modifiables. Bien sûr, au regard de chaque utilisateur, tout ceci sera parfaitement transparent et il sera même possible pour un utilisateur possédant les permissions adéquates de fusionner les versions pour obtenir des données communes. Pour le moment, ce serveur n'est pas encore implémenté mais l'architecture du Hurd et les fonctionnalités des bibliothèques (glibc, etc) le permettent facilement.

    Nous avons parlé plus haut des problèmes de debuggage de kernel. Avec le Hurd, la quasi totalité du système est placé dans le domaine utilisateur. Ceci implique le Hurd lui-même. Il est ainsi possible de lancer un sous-système Hurd depuis une session en marche. On appelle cela le sub-Hurd. Ainsi, plus besoin de redémarrer l'ensemble du système lors de tests. Les autres utilisateurs ne sont pas concernés et si votre implémentation déstabilise le système, cela ne concernera, au pire, que votre sous système. En clair, vous pouvez parfaitement « planter » votre sous-système Hurd sans nuire au système principal et aux autres utilisateurs de la machine.

    Nous terminons ce petit tour d'horizon en précisant quelques points importants :

  • Le but du Hurd n'est pas de prouver que Linux est obsolète mais simplement de créer un système novateur et véritablement ouvert.
  • Le Hurd doit beaucoup à Linux. Une grande partie des pilotes de périphériques de Linux sont comprises dans les sources de GnuMach et il en va de même pour quelques fonctionnalités des serveurs Hurd (implémentation TCP/IP par exemple).
  • Le Hurd est fonctionnel. Vous pouvez dès à présent l'installer, l'utiliser et développer avec le Hurd.
  • Vous pouvez facilement aider le développement du Hurd. Le simple fait d'installer le Hurd, d'y compiler quelques programmes Linux (ou autre) et de rapporter vos expériences et vos déboires aide grandement les développeurs actifs du Hurd. Si vous êtes plus compétent, vous pouvez, bien sûr, participer à la correction des bugs en envoyant vos patch et vos idées.

    Liens

    http://www.debian.org/ports/hurd/

    Site officiel
    http://www.gnu.org/software/hurd/

    Sur Sourceforge
    http://hurddocs.sourceforge.net
    http://hurd.sourceforge.net

    En français
    http://www.hurd-fr.org

    Linux Magazine France n° 21 - Octobre 00