Devfs : Device File System

Chacun connaît le répertoire /dev et ces quelques 1500 entrées (noeuds). L'arrivée du kernel 2.4 marque peut-être la fin, pour la plupart d'entre nous, de l'utilisation classique de cette collection de points d'entrée vers le matériel ...

Le principe ayant conduit à la création du système de fichiers des périphériques est simple : la récurrence des informations est mauvaise pour le fonctionnement et la maintenance d'un système. En effet, il est nécessaire de garder une correspondance manuellement ou pseudo-manuellement (avec MAKDEV) entre les valeurs Majeurs/Mineurs du kernel et les entrées dans /dev. Dans le même esprit, il est absolument nécessaire de garder une unicité de chaque couple Majeur/Mineur, ce qui oblige à procéder à un harassant travail quasi administratif. Une très bonne raison pour justifier la recherche d'une autre manière de voir et de gérer /dev est le nombre d'entrées inutiles dans ce répertoire. En effet, qui peut bien prétendre utiliser 300 ou 400 de ces noeuds sur son système ? Personne, sans doute.

Enfin, une raison plus technique est avancée par Richard Gooch dans la FAQ livrée avec le kernel. Il s'agit d'une question de vitesse et, en particulier, à propos des périphériques divers en mode caractère. Lorsque vous accédez à un noeud dans /dev, une recherche est faite pour trouver le pilote correspondant à partir des numéros Majeur/Mineur définis par le noeud. Pour l'heure, ces recherches sont faites sur des tables de 128 entées (8 bits) chacune. Mais le jour viendra où cette table ne sera plus suffisante et il faudra passer sur des numérotations à 16 bits. Ceci porterait les tableaux à 65536 entrées, soit, en toute logique, une recherche 512 fois plus lente ...

Le principe

Pour éviter les désagréments actuels et à venir, devfs n'utilise pas le principe des combinaisons Majeur/Mineur. Avec devfs, les connexions sont créées au moment où vous entrez dans le répertoire /dev. Lorsque l'on souhaite enregistrer un périphérique, une entrée dans une table interne est créée. Si cette entrée dans le cache ne possède pas encore de noeud, celui-ci est également créé. En revanche, si l'entrée est déjà présente dans le cache, aucune opération n'est nécessaire et, de ce fait, aucune recherche n'est effectuée. Dans ce cache ne se trouveront que des entrées pour des périphériques existants réellement sur votre système. Les recherches dans le cache seront donc rapides.

Cette manière de procéder possède, en outre, un autre avantage intéressant. En effet, si un périphérique que vous savez présent dans la machine n'est pas listé dans /dev, c'est le signe d'un mauvais fonctionnement du périphérique ... Un autre avantage concerne les systèmes de fichier en lecture seule, comme certaines stations diskless. Le répertoire /dev n'ayant pas d'existant physique, vous pouvez modifier les permissions à loisir sur les noeuds. Un bel exemple est, bien sûr, un système GNU/Linux complet sur CD-Rom. Avec devfs, vous n'êtes plus obligés de passer par un ramdisk.

Mais devfs va encore plus loin. Il est par exemple possible d'envoyer des messages au démon devfsd lors d'événements tels que l'ouverture ou la création d'une entrée. Il est ainsi possible d'associer des scripts à ces événements pour, par exemple, automatiquement monter un système de fichiers ou garder une trace de l'accès à un périphérique.

Installation

Vous vous en doutez, ceci est une fonctionnalité du kernel 2.4, il est donc impératif de prévoir tous les changements nécessaires au passage vers cette version avant d'envisager l'utilisation de devfs. Il est même fortement conseillé de démarrer et de bien tester un nouveau kernel sans devfs afin de s'assurer que toutes les dépendances sont respectées.

Avant de préparer et de compiler le kernel utilisant devfs, vous devez posséder sur votre système le démon devfsd prêt à être utilisé. Il vous est donc nécessaire d'en récupérer les sources (les plus récentes possibles) sur le site de Richard Gooch, http://www.atnf.csiro.au/~rgooch/linux/.

L'archive fait quelques dizaines de kilo-octets. Après décompression, vous pourrez compiler les sources à l'aide d'un simple "make". Avec les sources est livré un fichier de configuration devfsd.conf. Celui-ci permet de conserver une compatibilité avec l'ancienne implémentation de /dev. Les valeurs par défauts présentes dans ce fichier ne doivent pas être changées. Celles-ci doivent parfaitement fonctionner sur votre système et si vous désirez prendre le risque d'y faire des changements, faites-le après avoir testé les valeurs d'origine. Ce fichier de configuration prendra place dans votre répertoire /etc et le binaire devfsd dans /sbin.

Il vous faut à présent modifier votre script de démarrage initial afin de lancer /sbin/devfsd /dev durant les toutes premières étapes du démarrage. Il est impératif que cette ligne soit ajoutée avant n'importe quelle vérification des disques locaux. Selon votre distribution, la ligne est à ajouter dans un script placé dans le répertoire /etc/rc.d/, /sbin/init.d/ ou encore /etc/rc/. Nous avons fait nos tests sur un système basé, à l'origine, sur une distribution SuSE 6.2. Nous avons donc ajouté notre ligne concernant devfsd dans /etc/rc.d/boot, juste après le montage de /proc. Ceci n'est, bien sûr, pas à prendre pour argent comptant. Assurez-vous de la correcte exécution de la ligne en testant avec un simple

echo -n "--- COUCOU ICI SERA DEVFSD ---"

Après cette ultime vérification et la mise en place effective du lancement de devfsd via votre bootscript, votre système est prêt à accueillir une version du kernel 2.4 utilisant devfs. Recompilez donc celui-ci avec le support qui vous intéresse.

Pour les petits curieux : Mais comment fera le système pour démarrer avec comme racine la partition adéquate puisque les entrées dans /dev n'existent pas encore ? En réalité, le kernel ne fait pas référence aux entrées de /dev lors du démarrage. En précisant root=<périph> sur la ligne de commande du kernel, c'est en fait le bootloader qui interprétera ce paramètre. Il placera dans un emplacement mémoire une valeur correspondante au périphérique dont le kernel se servira. Ce dernier n'utilise donc pas /dev mais uniquement la valeur passée par le bootloader.

Attention : ne redémarrez pas le système avant d'avoir lu la partie qui va suivre !

Problèmes et solutions

  • bibliothèques système : Certaines applications ne supportent pas d'accéder aux entrées de /dev alors qu'il s'agit de liens symboliques. Ceci est un problème qui, senmble-t-il, provient de la libc. Assurez-vous d'avoir une libc 5.4.46 ou, dans le cas d'une glibc, la 2.1.3 (au minimum).

  • PAM : les Pluggable Authentification Modules sont maintenant utilisés dans la plupart des distributions GNU/Linux. Ils permettent une gestion efficace et souple de l'authentification et du contrôle d'accès en fonction des services proposés. Seul souci, PAM a quelques problèmes avec les liens symboliques.

    L'un des modules PAM est utilisé pour la définition des terminaux "sûrs". Le fichier /etc/securetty contient la liste des terminaux via lequel, par exemple, l'utilisateur root peut se connecter. On y trouve habituellement ceci :

    tty1
    tty2
    tty3
    tty4
    tty5
    tty6

    Afin d'éviter les éventuels problèmes d'authentification, ajoutez ceci au fichier :

    1
    2
    3
    4
    5
    6
    7
    8

    Cela permettra de faire fonctionner devfs mais ouvrira une porte vers l'extérieur puisque, dans ce cas, un login root sera autorisé depuis le réseau (à condition d'avoir le mot de passe, bien sûr). Si vous pensez qu'il s'agit là d'un problème pour la sécurité de votre système, oubliez devfs.

  • XFree 86 : Il est fortement conseillé de passer à une version 4 d'XFree. Dans le cas contraire, vous pouvez rencontrer des problèmes dans le cas où un utilisateur classique désire lancer X. Un patch est proposé dans le README concernant devfs dans la documentation du kernel 2.4.

  • devpts : L'auteur de devfs a reçu des retours d'information concernant des problèmes de fonctionnement avec devpts. Il conseille donc d'éditer /etc/fstab afin de ne pas monter devpts, ce qui, d'après lui, ne sert de toute façon à rien.

  • /dev/mouse : Il n'y a pas réellement de problème majeur ici, mais le fait d'utiliser un lien symbolique en lieu et place du véritable noeud ajoute une redirection dans le cas de devfs. Il est donc conseillé de modifier vos fichiers de configuration afin de remplacer chaque occurence de /dev/mouse par le véritable périphérique où est connectée votre souris.

  • montage : Afin de vous assurer un maximum de sécurité lors du démarrage du système, placez devfs=mount dans le fichier de configuration de votre bootloader (/etc/lilo.conf pour LILO et /boot/grub/menu.lst pour Grub). Cela demandera explicitement au kernel d'utiliser devfs.

    Redémarrage

    Lors du premier démarrage avec le support devfs, le kernel va se lancer et la procédure de boot va commencer. Si, comme nous, vous avez lancez le démon devfsd juste après le montage de /proc, vous devez voir apparaître un message du démon vous informant de son exécution :

    Started device management daemon for /dev
    

    La procédure de boot continuera alors normalement jusqu'à la demande de login. Loggez-vous et, ne résistant sans doute pas à la tentation, faites un tour dans le répertoire /dev. Vous constaterez alors de nombreux changements. Dans le cadre de nos tests, le nombre d'entrées à la racine de /dev est passé de 1786 à 426. Force est de constater qu'un grand nombre de ces entrées ne servaient effectivement à rien.

    Autre constatation majeure, /dev est maintenant organisé sous la forme d'une arborescence élaborée et des liens symboliques permettent une compatibilité avec les applications et utilitaires faisant usage de l'ancienne organisation. Ainsi, on retrouve toutes nos partitions, nos disques et notre lecteur CD-Rom :

    hda -> ide/host0/bus0/target0/lun0/disc
    hda1 -> ide/host0/bus0/target0/lun0/part1
    hda2 -> ide/host0/bus0/target0/lun0/part2
    hdc -> ide/host0/bus1/target0/lun0/disc
    hdc1 -> ide/host0/bus1/target0/lun0/part1
    hdc2 -> ide/host0/bus1/target0/lun0/part2
    hdc3 -> ide/host0/bus1/target0/lun0/part3
    hdc4 -> ide/host0/bus1/target0/lun0/part4
    hdd -> ide/host0/bus1/target1/lun0/cd
    

    Tout fonctionne parfaitement, si ce ne sont les périphériques /dev/vcs* avec lesquels mingetty semblait avoir des problèmes. Ces périphériques correspondent à la mémoire d'affichage des consoles virtuelles. Elles permettent d'utiliser la séquence de touches MAJ+PageHaut. Malheureusement, nous n'avons pas eu le temps d'approfondir le sujet mais nous soupçonnons que le problème vienne de mingetty. En effet, celui-ci tenterait d'ouvrir les /dev/vcs* avant /dev/vcs.

    Compatibilité

    Le support devfs utilise la convention de nommage du kernel. Ceci signifie que les entrées dans /dev ne seront pas organisées de la même manière et, selon le noeud, ne porteront pas le même nom qu'avec l'ancien /dev. La configuration par défaut de devfsd permet de conserver une compatibilité avec l'ancien /dev sous la forme de liens symboliques. Cependant, il existe une autre manière de conserver une compatibilité. Celle-ci consiste à utiliser la nouvelle convention de nommage avec les kernels utilisant devfs mais également ceux qui ne l'utilisent pas.

    Ainsi, vous pouvez vous passer de la compatibilité offerte par devfsd en utilisant la convention de nommage du kernel ou en créant votre propre système de nommage. Attention cependant, la convention de nommage du kernel (sous la forme d'arborescence) peut paraître séduisante mais n'oubliez pas tout ce que cela implique :

  • cette convention n'a pas été créée pour servir dans les fichiers de configuration.
  • vous serez obligé de reconfigurer entièrement votre système sans rien oublier.
  • il vous sera peut-être nécessaire de recompiler un certain nombre d'applications.
  • vous ne devrez jamais oublier que les distributions actuelles n'utilisent et n'utiliseront sans doute jamais cette convention. Vous ne pourrez donc pas utiliser d'éventuels systèmes de gestion de packages de manière normale.

    Note sur la convention de nommage du kernel

    Comme nous venons de l'évoquer, le kernel utilise un schéma bien défini pour référencer les périphériques : autrement dit, une convention de nommage ou, encore plus simplement, une manière logique de donner un nom aux périphériques et de les classer. devfs vous permet d'avoir une représentation de ce schéma. En voici quelques exemples :

  • Disque

    Chaque disque (IDE, SCSI, ou autre) est référencé par un lien symbolique dans /dev/discs/. On trouvera ici tous les disques sous la forme du répertoire disc0, disc1, etc. Ces liens symboliques pointent vers un répertoire représentant l'organisation des contrôleurs/disques/partitions sous la forme :

    type/contrôleur/bus/cible/lun
    

    Exemples :

    SCSI: scsi/host1/bus2/target3/lun4
    Le périphérique est présent sur le second contrôleur, chaîne 3, ID 3, LUN (Logical Unit Number) 4.

    IDE: ide/host0/bus1/target0/lun0/part2
    Sur le premier contrôleur réside un disque en secondary (bus1) master (target0) où réside une seconde partition (part2).

    Ceci peut rendre de grands services. N'oubliez pas que seuls les périphériques supportés par le kernel sont présents dans devfs. Ainsi, pour connaître le nombre de périphériques présents sur le premier contrôleur SCSI, vous n'avez qu'à lister son répertoire.

    Dans chacun de ces répertoires on trouvera une entrée pour le disque entier (disc) et pour chacune des partitions (part*). Les liens symboliques pointant sur ces entrées sont nombreux. Ainsi, si vous possédez un ou plusieurs lecteurs CD-Rom, ils seront également symbolisés par /dev/cdroms/cdrom0, /dev/cdroms/cdrom1, etc.

  • TTY

    Nouveau nom            Ancien nom             Description
    /dev/tts/{0,1,...}     /dev/ttyS{0,1,...}     Ports série
    /dev/cua/{0,1,...}     /dev/cua{0,1,...}      Périphérique d'appel
    /dev/vc/{0,1,...}      /dev/tty{0,1,...}      Consoles Virtuelles
    /dev/vcc/{0,1,...}     /dev/vcs{0,1,...}      Mémoire des Consoles Virtuelles
    /dev/pty/m{0,1,...}    /dev/ptyp??            PTY maîtres
    /dev/pty/s{0,1,...}    /dev/ttyp??            PTY esclaves
    

    Comme vous pouvez le voir, l'organisation générale reste assez simple. Il en va de même pour les périphériques comme les ramdisk ou encore le loopback.

  • Sound

    Plus intéressant, l'organisation des entrées concernant le support des cartes son. Ici, un répertoire /dev/sound fournit une information sur les fonctionnalités du matériel installé. Ainsi, notre répertoire /dev/sound contient sur notre architecture de test :

    audio
    dspW
    sequencer
    sequencer2

    Configuration

    Une fois vous être assuré que tout fonctionnait correctement avec votre nouveau kernel supportant devfs, vous devez être en mesure de personnaliser le fichier de configuration du démon devfsd. En cas d'erreur dans ce fichier, vous aurez toujours la possibilité de démarrer sur un système de secours (CD ou disquette) pour revenir à l'ancienne version du fichier.

    La modification et l'ajout d'options dans /etc/devfs.conf est relativement simple. Une page de manuel étant fournie avec les sources de devfsd, nous n'allons pas nous lancer ici dans la description des options. Sachez simplement que par l'intermédiaire de ce fichier de configuration, vous pouvez non seulement enregistrer de nouveaux périphériques de manière manuelle, mais également mettre en oeuvre un grand nombre de fonctionnalités très intéressantes. C'est ici, par exemple, que vous pourrez définir avec précision quel comportement adopter lors d'un événement survenant sur l'une des entrées de /dev. L'événement en question pourra être l'un des suivants :

  • REGISTER : un pilote vient d'enregistrer l'entrée.
  • UNREGISTER : un pilote vient de supprimer une entrée.
  • ASYNC_OPEN : l'inoeud a été ouvert par un processus.
  • CLOSE : le fichier vient d'être fermé.
  • LOOKUP : une recherche d'inoeud est faite. L'événement n'aura pas lieu si le processus qui déclenche la recherche est le démon devfsd ou un de ses fils.
  • CHANGE : les attributs de l'inoeud on été changés.
  • CREATE : un inoeud a été créé par un processus.

    En réponse à ces événements, un certain nombre d'actions peuvent être exécutées. Parmi les plus intéressantes, on remarque :

  • EXECUTE : permet le lancement d'une application ou d'un script. Notez que le nombre maximum d'arguments que l'on peut passer au programme exécuté est de 6.
  • IGNORE : toutes les manipulations sur ce périphérique qui suivront seront ignorées.

    Nous arrivons au terme de cet article. Je tiens à préciser encore une fois que le support devfs du kernel 2.4 est encore à l'état expérimental. Il s'agit d'une fonctionnalité les plus remarquables du nouveau noyau et, n'en doutons pas, il semble bien que cela deviendra un standard pour les futures générations de système GNU/Linux.

    Un grand nombre de sujets concernant devfs n'ont pas été abordés ici. Il est donc conseillé de lire attentivement la documentation livrée avec le kernel à ce sujet et de vous inscrire à la liste de diffusion du kernel pour trouver des informations à jour.

    Liens

    Homepage de Richard Gooch
    http://www.atnf.csiro.au/~rgooch/linux/

    Documentation du kernel
    http://www.atnf.csiro.au/~rgooch/linux/docs/

    FAQ de la mailing list du kernel Linux
    http://www.tux.org/lkml/

    Linux Magazine France n°25 - Février 2001