9.3. Manipulation des périphériques et modules

Au Chapitre 8, nous avons installé le paquet udev en construisant systemd. Avant d'entrer 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.

Traditionnellement, les systèmes Linux utilisaient une méthode de création de périphériques statiques avec laquelle un grand nombre de nœuds de périphériques étaient créés sous /dev (quelques fois littéralement des milliers de nœuds), que le matériel correspondant existe ou non. Ceci était le plus souvent réalisé 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 nœuds des périphériques détectés par le noyau sont créés. Comme ces nœuds de périphériques sont créés à chaque lancement du système, ils sont stockés dans un système de fichiers devtmpfs (un système de fichiers virtuel qui réside entièrement dans la mémoire du système). Les nœuds de périphériques ne requièrent pas beaucoup d'espace, donc la mémoire utilisée est négligeable.

9.3.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 les sources du noyau, cette méthode de création dynamique des périphériques 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 entendu 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 non imposée par quelque développeur. Le système de fichiers devfs souffrait aussi de restrictions particulières inhérentes à sa conception et qui ne pouvaient être corrigées 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 de la branche instable 2.5 du noyau, sortie ensuite avec 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 en espace utilisateur, la possibilité de développer un remplacement en espace utilisateur de devfs est devenu beaucoup plus réaliste.

9.3.2. Implémentation d'Udev

9.3.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 leurs objets avec le sysfs (en interne, devtmpfs) 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 avec sysfs sont disponibles pour les processus en espace utilisateur ainsi que pour udevd pour traitement (y compris des modifications aux nœuds de périphériques).

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

Les fichiers de périphérique sont créés par le noyau avec le système de fichiers devtmpfs. Tout pilote souhaitant enregistrer un nœud de périphérique ira dans le devtmpfs (par le cœur du pilote) pour le faire. Quand une instance devtmpfs est montée sur /dev, le nœud de périphérique sera créé dès le départ avec un nom, des droits et un propriétaire figés.

Peu de temps après, le noyau enverra un uevent à udevd. À partir des règles indiquées dans les fichiers contenus dans les répertoires /etc/udev/rules.d, /usr/lib/udev/rules.d et /run/udev/rules.d, udevd créera les liens symboliques supplémentaires vers le nœud de périphérique, ou bien il modifiera ses droits, son propriétaire ou son groupe, ou l'entrée dans la base de données interne d'udevd concernant cet objet.

Les règles de ces trois répertoires sont numérotées et les trois répertoires sont fusionnés. Si udevd ne peut pas trouver de règles pour le périphérique qu'il crée, il en donnera la propriété et les droits à n'importe quel devtmpfs utilisé au départ.

9.3.2.3. Chargement d'un module

Il se peut que les pilotes des périphériques compilés en module aient aussi des alias compilés. Les alias sont visibles dans la sortie du programme modinfo et sont souvent liés aux identifiants de bus spécifiques des périphériques pris en charge par un module. Par exemple, le pilote snd-fm801 prend en charge les périphériques PCI ayant l'ID fabricant 0x1319 et l'ID de périphérique 0x0801 a aussi un alias « 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 ». Les règles par défaut fournies par Udev feront que udevd appellera /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 obsolète (et non désiré) forte 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 prise en charge pour des systèmes de fichiers et de prise en charge native des langues sur demande.

9.3.2.4. Gestion des périphériques dynamiques ou montables à chaud

Lorsque vous connectez un périphérique, comme un lecteur MP3 USB, 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.

9.3.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 de périphériques.

9.3.3.1. Un module noyau n'est pas chargé automatiquement

Udev ne chargera un module que s'il possède un alias spécifique au bus et que le pilote du bus envoie correctement les alias nécessaires vers sysfs. Autrement, il faut organiser le chargement des modules par d'autres moyens. Avec Linux-6.0.6, 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 prend en charge udev, lancez modinfo avec le nom du module en 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.

Si le fichier modalias existe dans sysfs, alors le pilote prend en charge 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é ultérieurement.

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 prise en charge de modalias à ce type de bus. Avec Linux-6.0.6, c'est le cas pour les bus ISA. Attendez que ce problème soit corrigé dans les versions ultérieures du noyau.

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

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

Si le module « enveloppe » 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 modprobe pour charger l'enveloppe après qu'udev a chargé le module enveloppé. Pour cela, ajoutez une ligne « softdep » dans tous les fichiers /etc/modprobe.d/<filename>.conf. Par exemple :

softdep snd-pcm post: snd-pcm-oss

Remarquez que la commande « softdep » autorise aussi les dépendances pre:, ou un mélange de pre: et de post:. Voir la page de manuel de modprobe.d(5) pour plus d'informations sur la syntaxe et les possibilités de « softdep ».

9.3.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 réalisé 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.

9.3.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 lacunaire peut correspondre à un disque SCSI (comme désiré) et au périphérique SCSI générique du même fabricant (de façon incorrecte). Trouvez la règle défectueuse et affinez-la, à l'aide de la commande udevadm info.

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

Cela peut être une autre manifestation du problème précédent. Si ce n'est pas le cas, 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 cela en créant une règle qui attend l'attribut sysfs utilisé et en le 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.

9.3.3.6. Udev ne crée pas un périphérique

Les textes suivants supposent que le pilote est compilé statiquement dans le noyau ou bien sont déjà chargés comme modules et que vous avez déjà vérifié que udev ne crée pas un périphérique mal nommé.

Udev n'a pas les informations pour créer un nœud si un pilote noyau n'exporte pas ses informations vers sysfs. C'est le plus souvent le cas des pilotes tiers ne provenant pas du noyau. Créez un nœud de périphérique statique dans /usr/lib/udev/devices avec les numéros majeurs/mineurs appropriés (regardez le fichier devices.txt dans la documentation du noyau du vendeur du pilote tiers). Le nœud statique sera copié dans /dev par udev.

9.3.3.7. L'ordre de nommage des périphériques change de manière aléatoire après le redémarrage

Cela est dû au fait qu'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 supposer 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 nombres ou la sortie de divers utilitaires *_id installés par udev. Voir la Section 9.4, « Gérer les périphériques » et la Section 9.2, « Configuration générale du réseau » pour des exemples.

9.3.4. Lecture utile

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