7.9. Gestion des périphériques et modules sur un système LFS

Dans le Chapitre 6, nous avons installé le paquet Udev. Avant d'aller dans les détails concernant son fonctionnement, un bref historique des méthodes précédentes de gestion des périphériques est nécessaire.

Les systèmes Linux en général utilisent traditionnellement une méthode de création de périphériques statiques avec laquelle un grand nombre de nœuds périphériques est créé sous /dev (quelque fois des milliers de nœuds), que le matériel correspondant existe ou pas. Ceci se fait typiquement avec un script MAKEDEV, qui contient des appels au programme mknod avec les numéros de périphériques majeurs et mineurs pour chaque périphérique possible qui pourrait exister dans le monde.

En utilisant la méthode udev, seuls les périphériques détectés par le noyau obtiennent des nœuds périphériques créés pour eux. Comme ces nœuds périphériques seront créés à chaque lancement du système, ils seront stockés dans un tmpfs (un système de fichiers qui réside entièrement en mémoire). Les nœuds périphériques ne requièrent pas beaucoup d'espace disque, donc la mémoire utilisée est négligeable.

7.9.1. Historique

En février 2000, un nouveau système de fichiers appelé devfs a été intégré au noyau 2.3.46 et rendu disponible pour la série 2.4 des noyaux stables. Bien qu'il soit présent dans le source du noyau, cette méthode de création dynamique de périphérique n'a jamais reçu un support inconditionnel des développeurs du noyau.

Le principal problème de l'approche adopté par devfs était la façon dont il gérait la détection, la création et le nommage des périphériques. Ce dernier problème, le nommage des périphériques, était peut-être le plus critique. Il est généralement accepté que s'il est possible de configurer les noms des périphériques, alors la politique de nommage des périphériques revient à l'administrateur du système, et du coup n'est pas imposée par un ou des développeur(s) en particulier. Le système de fichiers devfs souffre aussi de conditions particulières inhérentes à son concept et ne peut pas être corrigé sans une revue importante du noyau. Il a aussi été marqué comme obsolète pendant une longue période — à cause d'un manque de maintenance — et a finalement été supprimé du noyau en juin 2006.

Avec le développement du noyau instable 2.5, sorti ensuite en tant que la série 2.6 des noyaux stables, un nouveau système de fichiers virtuel appelé sysfs est arrivé. Le rôle de sysfs est d'exporter une vue de la configuration matérielle du système pour les processus en espace utilisateur. Avec cette représentation visible de l'espace utilisateur, la possibilité de voir un remplacement de l'espace utilisateur pour devfs est devenu beaucoup plus réaliste.

7.9.2. Implémentation d'Udev

7.9.2.1. Sysfs

Le système de fichier sysfs a été brièvement mentionné ci-dessus. On pourrait se demander comment sysfs connaît les périphériques présents sur un système et quels numéros de périphériques devraient être utilisés. Les pilotes qui ont été compilés directement dans le noyau enregistrent leur objet avec sysfs quand ils sont détectés par le noyau. Pour les pilotes compilés en tant que modules, cet enregistrement surviendra quand le module sera chargé. Une fois que le système de fichier sysfs est monté (sur /sys), les données enregistrées par les pilotes internes avec sysfs sont disponibles pour les processus en espace utilisateur ainsi qu'à udev pour la création des nœuds périphériques.

7.9.2.2. Scripts de démarrage d'Udev

Le script de démarrage S10udev s'occupe de créer les nœuds périphériques au lancement de Linux. Le script supprime la gestion des uevents de /sbin/hotplug par défaut. On fait cela car le noyau n'a plus besoin de faire appel à un binaire externe. À la place, udevd écoutera sur un socket netlink les uevents que le noyau fait apparaître. Puis, le script de démarrage copie les nœuds des périphériques statiques qui existent dans /lib/udev/devices vers /dev. Cela est nécessaire car certains périphériques, répertoires et liens symboliques sont requis avant que les processus de gestion du périphérique dynamique ne soient disponibles pendant les premières étapes du démarrage d'un système, ou car udevd lui-même les exige. La création des nœuds statiques dans /lib/udev/devices fournit aussi un environnement de travail facile pour les périphériques qui ne sont pas supportés par l'infrastructure de gestion des périphériques en dynamique. Ensuite le script de démarrage lance le démon Udev, udevd, qui agira sur tous les uevents qu'il reçoit. Enfin, le script de démarrage oblige le noyau à répéter des uevents pour chaque périphérique qui a été déjà enregistré puis attend que udevd les gère.

7.9.2.3. Création de nœuds de périphérique

Pour obtenir le bon nombre majeur ou mineur d'un périphérique, Udev s'appuie sur les informations fournies par sysfs dans /sys. Par exemple, /sys/class/tty/vcs/dev contient la chaîne « 7:0 ». Cette chaîne est utilisée par udevd pour créer un nœud de périphérique avec un nombre majeur 7 et et un nombre mineur 0. Les noms et les droits des nœuds sous le répertoire /dev sont déterminés par des règles spécifiés dans des fichiers à l'intérieur du répertoire /etc/udev/rules.d/. Celles-ci sont numérotées d'une façon similaire au paquet LFS-Bootscripts. Si udevd ne peut trouver une règle pour le périphérique qu'il est en train de créer, il attribuera par défaut des droits 660 et la propriété à root:root. La documentation sur la syntaxe des fichiers de configuration des règles Udev est disponible dans /usr/share/doc/udev-161/writing_udev_rules/index.html.

7.9.2.4. Chargement d'un module

Il se peut que les pilotes des périphériques compilés en module aient des aliases compilés en eux. Les aliases sont visibles dans la sortie du programme modinfo et sont souvent liés aux identifiants spécifiques du bus des périphériques supportés par un module. Par exemple, le pilote snd-fm801 supporte les périphériques PCI ayant l'ID fabricant 0x1319 et l'ID de périphérique 0x0801, et il a un alias qui est « pci:v00001319d00000801sv*sd*bc04sc01i* ». Pour la plupart des périphériques, le pilote du bus définit l'alias du pilote qui gérerait le périphérique via sysfs. Par exemple, le fichier /sys/bus/pci/devices/0000:00:0d.0/modalias pourrait contenir la chaîne « pci:v00001319d00000801sv00001319sd00001319bc04sc01i00 ». Il résultera des règles par défaut fournies avec Udev que udevd fera appel à /sbin/modprobe avec le contenu de la variable d'environnement de l'uevent MODALIAS (qui devrait être la même que le contenu du fichier modalias dans sysfs), donc chargera tous les modules dont les alias correspondent à cette chaîne après les expansions génériques.

Dans cet exemple, cela signifie que, outre snd-fm801, le pilote forte obsolète (et non désiré) sera chargé s'il est disponible. Voir ci-dessous les moyens d'empêcher le chargement des modules indésirables.

Le noyau lui-même est aussi capable de charger des modules de protocole réseau, de support pour des systèmes de fichiers et des NLS sur demande.

7.9.2.5. Gestion des périphériques dynamiques/montables à chaud

Quand vous connectez un périphérique, comme un lecteur MP3 USB (Universal Serial Bus), le noyau reconnaît que le périphérique est maintenant connecté et génère un uevent. Cet uevent est alors géré par udevd comme décrit ci-dessus.

7.9.3. Problèmes avec le chargement des modules et la création des périphériques

Il existe quelques problèmes connus pour la création automatique des nœuds périphériques :

7.9.3.1. Un module du noyau n'est pas chargé automatiquement

Udev ne chargera un module que s'il a un alias spécifique au bus et si le pilote du bus envoie correctement les alias nécessaires vers sysfs. Sinon, il faut organiser le chargement de modules par d'autres moyens. Avec Linux-2.6.32.44, Udev est connu pour charger les pilotes correctement écrits pour les périphériques INPUT, IDE, PCI, USB, SCSI, SERIO et FireWire.

Pour déterminer si le pilote du périphérique dont vous avez besoin a le support nécessaire pour Udev, lancez modinfo avec le nom du module comme argument. Puis, essayez de localiser le répertoire du périphérique sous /sys/bus et vérifiez s'il y a un fichier modalias là-bas.

Si le fichier modalias existe dans sysfs, alors le pilote supporte le périphérique et peut lui parler directement, mais s'il n'a pas d'alias, c'est un bogue dans le pilote. Chargez le pilote sans l'aide d'Udev et attendez que le problème soit corrigé plus tard.

S'il n'y a pas de fichier modalias dans le bon répertoire sous /sys/bus, cela signifie que les développeurs du noyau n'ont pas encore ajouté de support modalias à ce type de bus. Avec Linux-2.6.32.44, c'est le cas pour les bus ISA. Attendez que ce problème soit réparé dans les versions ultérieures du noyau.

Udev n'a pas du tout pour but de charger des pilotes « wrappers » (qui emballent un autre pilote) comme snd-pcm-oss et des pilotes non matériels comme loop.

7.9.3.2. Un module du noyau n'est pas chargé automatiquement et Udev n'est pas prévu pour le charger

Si le module « wrapper » n'améliore que la fonctionnalité fournie par un autre module (comme snd-pcm-oss améliore la fonctionnalité de snd-pcm en rendant les cartes son disponibles pour les applications OSS), configurez la commande modprobe pour charger le wrapper après qu'Udev ait chargé le module emballé. Pour cela, ajoutez une ligne « install » dans tous les fichiers /etc/modprobe.d/<filename>.conf. Par exemple :

install snd-pcm /sbin/modprobe -i snd-pcm ; \
    /sbin/modprobe snd-pcm-oss ; true

Si le module en question n'est pas un emballage et s'avère utile en tant que tel, configurez le script de démarrage S05modules pour charger ce module sur le système de démarrage. Pour cela, ajoutez le nom du module au fichier /etc/sysconfig/modules sur une ligne séparée. Cela fonctionne aussi pour les modules emballage, mais ce n'est pas optimal dans ce cas.

7.9.3.3. Udev charge un module indésirable

Ne compilez pas le module, ou mettez-le en liste noire dans un fichier /etc/modprobe.d/blacklist.conf comme on le fait avec le module forte dans l'exemple ci-dessous :

blacklist forte

Les modules en liste noire peuvent toujours être chargés manuellement avec la commande explicite modprobe.

7.9.3.4. Udev crée mal un périphérique, ou crée un mauvais lien symbolique

Cela se produit habituellement si une règle correspond à un périphérique de façon imprévue. Par exemple, une règle écrite avec des lacunes peut correspondre à un disque SCSI (comme désiré) et au périphérique générique SCSI correspondant (de façon incorrecte) du fabricant. Trouvez la règle défectueuse et rendez-la plus précise, à l'aide de la commande udevadm info

7.9.3.5. Une règle Udev fonctionne de manière non fiable

Cela peut être une autre manifestation du problème précédent. Sinon, et si votre règle utilise les attributs de sysfs, il se peut que ce soit un problème de timing du noyau, sur le point d'être corrigé dans les noyaux ultérieurs. Pour le moment, vous pouvez contourner en créant une règle qui attend l'attribut sysfs utilisé et en la mettant dans le fichier /etc/udev/rules.d/10-wait_for_sysfs.rules (créez ce fichier s'il n'existe pas). Merci d'informer la liste de développement de LFS si vous faites ainsi et que cela vous aide.

7.9.3.6. Udev ne crée pas de périphérique

Le texte ci-après assume que le pilote est compilé de manière statique dans le noyau ou qu'il est déjà chargé comme module, et que vous avez déjà vérifié qu'Udev ne crée pas de périphérique mal nommé.

Udev n'a pas besoin d'information pour créer un nœud périphérique si le pilote du noyau n'envoie pas ses données vers sysfs. C'est ce qu'il y a de plus courant avec les pilotes de tierces parties à l'extérieur de l'arborescence du noyau. Créez un nœud de périphérique statique dans /lib/udev/devices avec les numéros majeurs/mineurs appropriés (voir le fichier devices.txt dans la documentation du noyau ou la documentation fournie par le fabricant du pilote tierce partie). Le nœud du périphérique statique sera copié vers /dev par le script de démarrage S10udev.

7.9.3.7. Le nommage des périphériques change de manière aléatoire après le redémarrage

Cela est dû au fait que Udev, par nature, gère les uevents et charge les modules en parallèle, donc dans un ordre imprévisible. Cela ne sera jamais « corrigé ». Vous ne devriez pas espérer que les noms des périphériques du noyau sont stables. Créez plutôt vos propres règles qui rendent les liens symboliques stables basés sur des attributs stables du périphérique, comme une série de nombre ou la sortie de divers utilitaires *_id installés par Udev. Voir Section 7.10, « Création de liens symboliques personnalisés vers les périphériques » et Section 7.13, « Configurer le script network » pour des exemples.

7.9.4. Lecture utile

Des documentations supplémentaires sont disponibles sur les sites suivants :