C’est déjà la dixième édition de notre rubrique sur le noyau. Nous la fêtons en vous proposant de découvrir les nouveautés qu’apporte la version 2.6.21 du noyau Linux. Parmi celles-ci, la virtualisation y prend une bonne place, mais d’autres bonnes nouvelles nous attendent. Ainsi, une première étape vers une architecture de noyau tickless a été franchie avec l’intégration du patch dyntick. L’écriture de pilotes est maintenant facilitée par l’intégration du patch devres, lequel propose une infrastructure de gestion des ressources et des erreurs. Aussi, bien d’autres fonctionnalités et mises à jour prennent place dans cette nouvelle mouture et la lecture de ces lignes vous en apprendra davantage
[Actualité] Le noyau 2.6.21
La virtualisation
La virtualisation est un thème très actif dans le noyau Linux. Plusieurs solutions sont développées. Nous passons de la virtualisation à base d’isolateurs (containers) fondée sur un seul noyau avec différents espaces de nommage, à la virtualisation complète où les systèmes invités ont l’impression de s’exécuter directement sur le matériel. Entre ces deux mondes, nous trouvons la paravirtualisation. Dans cette approche, le système invité coopère avec l’hyperviseur afin que ce dernier puisse anticiper ses actions et ainsi améliorer les performances d’exécution.
Les containers
Concernant l’approche par containers, c’est au tour du système de fichiers Sysfs d’être modifié afin de supporter le principe des shadow directories : chaque répertoire peut être décliné en différentes versions tout en conservant le même nom. Ainsi, chaque espace de nommage (créé pour le besoin des applications profitant des containers) dispose de ses propres ressources lesquelles conservent le même nom. Ainsi, quelle que soit l’application qui est cloisonnée dans son espace de nommage, sa vision du système est toujours cohérente (l’interface réseau, par exemple, conservera le même nom au travers de Sysfs).
VMI
Le noyau 2.6.20 (cf. KC 91) intègre une interface standard, paravirt_ops, définissant l’ensemble des opérations (bas niveau comme l’activation des interruptions, etc.) que doit fournir (via leur implémentation) un hyperviseur supportant la paravirtualisation. C’est ensuite le noyau invité qui utilise ces opérations afin de communiquer avec l’hyperviseur sur le système hôte. Ainsi, n’importe qu’elle version du noyau Linux à partir de la version 2.6.20 peut tourner sur n’importe quel hyperviseur compatible avec la structure paravirt_ops. Il reste cependant nécessaire de recompiler le noyau invité afin d’intégrer les opérations définies par l’hyperviseur à chaque changement de celui-ci.
Au début de l’année 2006, Zachary Amsden, de la société VMware, a proposé le mécanisme VMI (Virtual Machine Interface) offrant un rôle similaire à paravirt_ops (défini que plus tard) avec des caractéristiques intéressantes. Le concept de base est qu’un hyperviseur compatible VMI fournit à un OS invité (également compatible VMI) une ROM VMI (c.-à -d. un fichier binaire) contenant la définition de toutes les opérations bas niveau pour que l’OS invité puisse interagir avec l’hyperviseur. Ainsi, l’OS invité n’a pas besoin d’être recompilé lors d’un changement d’hyperviseur.
VMI a été créé afin de résoudre différents problèmes. Parmi ceux-là , nous en citons trois ayant une importance notable. En premier lieu, un noyau compatible VMI peut s’exécuter directement sans modification sur le matériel et cela sans perte de performances ; ou bien sur tous les hyperviseurs compatibles VMI. Ensuite, l’interface fournit un moyen pour demander à l’hyperviseur quelles sont les capacités matérielles disponibles, d’aide à la virtualisation. Ainsi, un OS VMI-fié ne nécessite pas de modifications pour s’exécuter, quelle que soit la technologie matérielle de virtualisation déployée (présente et future). Finalement, un OS VMI-fié profite également des pilotes de périphériques dont disposent l’hyperviseur sur le système hôte.
Après un passage par la branche -mm, VMI a été intégré dans cette version 2.6.21 de Linux. Son implémentation a cependant été modifiée. VMI est dorénavant construit au-dessus de paravirt_ops et propose un panel de fonctionnalités plus important. Aussi, alors que la version originale n’était réalisée que pour l’architecture x86, l’intégration aux architectures de type x86_64 est en cours.
KVM
L’activité autour de KVM (Kernel-based Virtual Machine driver) est toujours très soutenue. Des fonctionnalités très attendues ont été ajoutées dans cette version de Linux.
Nous avions parlé dans le KC91 de l’ajout par Ingo Molnar du support de la paravirtualisation dans KVM. Cette fonctionnalité très intéressante en termes de performance a été incluse dans la mainline.
La migration à chaud de machines virtuelles, d’un hôte à un autre, est désormais disponible pour KVM. Cette action est effectuée en plusieurs étapes. Tout d’abord, l’image de la mémoire physique de la machine virtuelle (c.-à -d. la mémoire dont dispose le système invité) est transférée vers le système hôte destinataire (via une connexion directe en TCP ou en ssh). Cette opération est effectuée page après page. Pour chaque transfert réussi, la page correspondante sur la machine d’origine est alors positionnée en lecture seule. Ainsi, si la page est accédée en écriture par l’OS invité, une faute de page survient. Elle engendre alors le marquage de cette page, laquelle devient une page " sale " (ce mécanisme est appelé dirty page logging). Cela signifie qu’il est nécessaire de la retransférer sur la machine de destination. Lorsque le nombre de pages sales est inférieur à un certain seuil, la machine virtuelle est stoppée et les pages restantes sont copiées. Finalement, l’état de la machine virtuelle (c.-à -d. la valeur de ses registres) est transféré. L’hôte destinataire reprend alors l’exécution du système invité.
Une autre fonctionnalité notable est le support du suspend/resume pour les systèmes hôtes exécutant des machines virtuelles au travers de KVM. Ainsi, il est maintenant possible d’ajouter ou de retirer des processeurs, à chaud, (cpu hotplug) sur ces systèmes afin de répondre au besoin de puissance de calcul.
Annoncé pour cette version du noyau, la stabilisation de l’interface utilisateur de KVM est au final prévue pour la version 2.6.22. La 15ème révision de KVM qui est intégrée à Linux 2.6.21 a déjà été modifiée dans la 18ème révision de KVM.
La gestion du temps
Clockevents
La prise en charge des périphériques de gestion du temps (PIC, HPET, etc.) est effectuée depuis toujours de façon spécifique suivant le type d’architecture matérielle. Le patch clockevents implémente une API unifiée pour tous les types d’horloges matérielles. Les spécificités de chaque horloge (résolution, one-shot ou périodique, etc.) sont exposées au noyau, au travers de cette API, afin qu’il puisse créer des timers et les armer sans avoir à se soucier des particularités matérielles (Un driver minimal, bas niveau, dépendant de l’architecture, reste toutefois nécessaire). Le noyau profite ainsi pleinement des capacités matérielles lorsqu’il arme des timers.
Dyntick
Thomas Gleixner et Ingo Molnar ont mis en place dans la branche -rt (temps réel) du noyau Linux l’infrastructure dyntick (cf. KC91) pour se passer partiellement de l’utilisation de l’interruption du timer, le tick (architecture tickless). Ce patch a été intégré dans la version 2.6.21 de la mainline. Dans les versions précédentes, le noyau programme l’interruption du timer pour qu’elle se déclenche de façon périodique (300 fois par seconde par défaut depuis le 2.6.19). Cette interruption cadence notamment l’exécution des différents processus sur le système. Cependant lorsque aucune activité n’est à l’œuvre (c.-à -d. le processeur est en état oisif), l’interruption continue d’être levée au même rythme. Elle réveille ainsi le système constamment. À chaque interruption, le système effectue différentes opérations. Entre autres, il met à jour la variable jiffies (gardant le temps écoulé depuis le démarrage du système), met à jour le timeslice du processus en cours d’exécution, vérifie si le flag need_resched est positionné (auquel cas, l’ordonnanceur est appelé), etc.
Le déclenchement périodique du tick est toujours effectué pendant les périodes d’activité du système. Mais lorsque celui-ci se trouve dans un état oisif, ce déclenchement est désactivé. Le timer est alors programmé pour lever une interruption à la date du prochain évènement temporel devant être traité (celui-ci pouvant être programmé à une résolution très fine via l’utilisation des clockevents). Ainsi le processeur n’a plus à se réveiller constamment pour exécuter le gestionnaire d’interruption du timer. Cette façon de procéder aboutit à une économie d’énergie significative ainsi qu’au refroidissement du processeur.
Finalement, au travers du système de fichiers /proc, les entrées timer_list et timer_stats listent, respectivement, l’ensemble des timers en suspens et différentes statistiques sur leurs utilisations.
La gestion des ressources et des erreurs
Vous vous rappellerez peut-être le sujet du Kernel Corner 92, traitant de la stabilité des pilotes. Un pas prometteur vers l’amélioration de la qualité du code de ces derniers va pouvoir être franchi avec l’apparition d’un sous-ensemble de fonctions dédiées à la gestion de l’allocation de ressources. Partant du constat que, dans de nombreux cas, la libération de diverses ressources requises pour le fonctionnement d’un module n’est pas ou est mal faite par les développeurs, Tejun Heo propose un ensemble de fonctions qui remplacent celles traditionnellement appelées pour obtenir les ressources en question, et se chargent ensuite de les libérer. Cette approche veut pallier les problèmes survenant lorsque l’initialisation d’un pilote échoue ou qu’un module est déchargé. Les conséquences peuvent aller de l’impossibilité de charger à nouveau le module jusqu’au crash. Concrètement, le développeur doit explicitement appeler ces nouvelles fonctions en lieu et place des fonctions traditionnelles. Pour simplifier le développement, elles peuvent être placées par le développeur dans un groupe. Il suffit pour cela d’appeler devres_open_group() pour une structure device, et toutes les managed functions utilisées ensuite feront automatiquement partie de ce groupe. Il suffit au développeur d’appeler ensuite devres_release_group() pour désallouer l’ensemble des ressources contenues dans ce groupe, par exemple si le chargement du module provoque une erreur. Dans tous les cas, lors d’un déchargement du module (si vous demandez un rmmod par exemple), tout ce qui a été alloué via l’appel aux managed functions sera automatiquement libéré.
L’infrastructure de Tejun Heo sait détecter les erreurs survenant lors de l’appel de ses fonctions spéciales, et permet ainsi de programmer de manière similaire la gestion d’une transaction : si certains appels d’une série retournent une erreur, un simple appel à devres_release_group() libèrera l’ensemble des ressources acquises par la série d’appels.
Afin de garder une trace globale de ce qui a été alloué, chacune des fonctions de l’infrastructure devres appelle devres_alloc(nom_fonction_de_liberation_ressources, taille_réservée, type_allocation), qui se charge de garder une trace des ressources demandées dans une liste. Actuellement, les managed functions sont utilisables pour réserver des IO regions, des interruptions (IRQ), des zones DMA, PCI et ioMap. La libAta est d’ores et déjà convertie à ce sous-système. Gageons que la simplicité d’adaptation du code existant à cette infrastructure lui garantira une adoption rapide dans les prochaines versions du noyau. On peut également imaginer que cette technique d’assistance, ayant maintenant fait son entrée au sein de Linux, sera étendue et complétée, au bénéfice de la qualité et de la stabilité.
Les spécificités des architectures
Dans le code spécifique à chaque architecture processeur, quelques nouveautés méritent attention. Signalons le support de l’option noexec sur s390 : cette option permet d’activer le bit de contrôle "NX" pour les régions mémoire contenant des données. C’est une extension disponible matériellement sur certains processeurs (SPARC, AMD64, etc.), qui s’appuie sur la valeur du dernier bit des entrées des tables de pages mémoire pour autoriser ou non la page correspondante à être exécutée par le processeur. Cependant les s390 n’en disposent pas. C’est donc par émulation logicielle que l’implémentation a été réalisée. La gestion de cela sous Linux/s390 se fonde sur un mode d’adressage différent : on choisit les tables de pages qui sont utilisées pour la translation des adresses d’instructions et celles qui sont utilisées pour la translation des adresses de données. Ainsi, sont formés des couples de tables de pages, contenant une shadow table utilisée pour le code exécutable, et une table de page classique pour les données. Ce mode d’adressage n’est disponible que pour l’espace utilisateur (secondary-space mode dans la terminologie s390). Ainsi, la protection n’est effective que pour l’espace utilisateur. Pour résumer, le marquage de données en noexec permet d’éviter des attaques, entre autres, par débordement de tampon (buffer overflow).
Le rechargement de noyau " à chaud ", c’est-à -dire sans passer par la phase d’initialisation de la machine (BIOS, boot loader, etc.) via kexec est disponible sur architectures ARM.
Les utilisateurs d’architectures PPC32 peuvent maintenant profiter de Kprobes, infrastructure de débogage et de collecte d’informations sur le noyau en cours d’exécution.
Les systèmes de fichiers
L’ajout de volumes à chaud est maintenant géré en RAID6 (qui est un mode à 4 disques minimum, double parité autorisant la perte de deux disques). Les partitions UFS2 (Solaris, FreeBSD) peuvent, quant à elles, être montées en écriture. Cependant ceci est marqué expérimental donc... faites un backup avant de tester. Les systèmes de fichiers de Minix V3 peuvent dorénavant être utilisés sous Linux, en lecture et écriture. Quant à JFFS1 (système de fichiers optimisé pour stockages de type flash), son retrait planifié du noyau est rendu effectif ; considéré obsolète, il est abandonné au profit de JFFS2. Le récent eCryptfs peut, quant à lui, fonctionner avec des chiffres à clef publique. Enfin, un tuning notable est réalisé sur GFS2 pour réduire son utilisation mémoire et améliorer ses performances (écritures de gros blocs de données et appels à readdir() notamment).
Le réseau
Peu de choses à se mettre sous la dent cette fois-ci. Notons tout de même que le serveur NFS (knfsd) peut maintenant fonctionner en IPv6 et que Netfilter/IPtables gèrent maintenant les ports sources aléatoires NATés.
L’embarqué
Alsa propose une nouvelle organisation appelée ASoC (ALSA System On Chip), développée à l’origine pour le projet OpenZaurus. Le code se divise en trois groupes de composants indépendants : les codecs (code générique indépendant de la plate-forme), les pilotes d’interface audio (AC97, PCM, etc.) et, enfin, une partie spécifique à chaque architecture matérielle. Ceci permet avec peu d’effort de faire fonctionner Alsa sur une multitude de systèmes de type embarqué. ALSA intègre également un gestionnaire d’énergie qui lui est propre, permettant de désactiver et réveiller à la volée chaque module utilisé ou non ou encore de modifier un taux d’échantillonnage pour réclamer moins de ressources.
Les pilotes de périphériques
La libAta, développée à l’origine pour piloter les périphériques SATA, a été étendue depuis Linux 2.6.19 aux périphériques PATA (IDE), (cf. KC 91). Depuis, cette branche est en constante amélioration afin de gérer toujours plus de périphériques IDE, le but étant, à terme, de remplacer le code IDE actuel du noyau. La série 2.6.21 n’est pas en reste, avec :
- le support des contrôleurs Intel PIIX3 (IDE) ;
- la gestion des contrôleurs it8213 (IDE) ;
- la gestion des contrôleurs Initio 162x (SATA).
Cherchant à favoriser une rapide adoption de la nouvelle infrastructure PATA, Fedora Core 7 sera la première distribution à l’utiliser par défaut.
Nous vous signalions, pour la sortie du 2.6.20, l’apparition d’une couche générique dédiée aux périphériques d’interaction utilisateur (claviers, souris...). Elle a désormais le privilège d’être adoptée par les périphériques Bluetooth.
Du côté de l’USB, si vous faites partie de ceux rencontrant des problèmes de communication avec des périphériques automatiquement paramétrés en mode High Speed (USB 2.0, 480 Mbits/s), vous avez désormais la possibilité de forcer le mode Full Speed (mode haute vitesse de la norme USB 1.1, 12Mbits/s) via Sysfs. Il n’empêche que ce n’est pas forcément intuitif, user-friendly, people ready ou tout ce que vous voudrez. Explication : dans la norme USB, chaque contrôleur USB 2.0 est couplé à un second contrôleur appelé " companion ", qui se charge de gérer les périphériques dits " full speed ". Si le contrôleur USB a détecté un tel périphérique, il doit ouvrir un port sur son companion et lui transférer tous les échanges ayant lieu avec le périphérique. Par contre, si le périphérique s’annonce comme étant compatible high speed, il n’y avait jusqu’à présent aucun moyen sous Linux de le faire redescendre en mode full, autrement dit de l’attribuer à un contrôleur companion. À partir de Linux 2.6.21 chaque hôte USB dispose d’une entrée appelée " companion " dans /sys/class/usb_host/usb_hostXX/device/companion. Rapide démonstration pratique :
Lorsque nous branchons notre périphérique, une entrée dans dmesg indique son hôte :
usb 3-3: new high speed USB device using ehci_hcd and address 10
C’est donc l’hôte 3 qui accueille le matériel. Il nous faut attribuer un port companion disponible au périphérique. On choisit un numéro affiché par :
# cat /sys/class/usb_host/usb_host3/companion 1 2
Et enfin on indique à l’hôte de l’utiliser :
# echo -n 2 > /sys/class/usb_host/usb_host3/companion
La gestion du périphérique est alors assurée par le sous-système UHCI.
Le domaine de l’ACPI voit l’apparition d’une classe de périphériques réservée aux rétroéclairages (affichages de périphériques mobiles, PC portables, etc.) dans Sysfs : /sys/class/backlight. Linux profite également d’un nouveau gestionnaire de tables ACPI entièrement réécrit, moins gourmand en mémoire.
Terminons par un rapide résumé des nouveautés dans la gestion de matériel :
- ajout du support des contrôleurs IDE Toshiba TC86C001, pour l’" ancienne " couche IDE uniquement (option noyau
BLK_DEV_TC86C001) ; - ajout de la gestion des cartes Ethernet PCI Silan SC92031 (option SC92031) ;
- apparition d’un petit module permettant de charger les PDA BlackBerry par USB (option
USB_BERRY_CHARGE) ; - support des puces Qlogic 4032 dans le pilote SCSI qla3xx ;
- de nombreuses améliorations dans la gestion de cartes tuner et d’acquisition vidéo.
Divers
L’espace utilisateur peut maintenant marquer le noyau comme tainted (corrompu) via /proc/sys/kernel/tainted, dans le cas où une application effectuerait des opérations pouvant mettre en péril le fonctionnement normal du noyau. Un nouveau marqueur ‘U’ a été créé pour l’occasion.
La taille totale des options passées au noyau lors de son démarrage devient variable et non plus limitée à une valeur fixe. Cela fait tomber une limitation parfois gênante lorsque l’on a des options à passer pour un grand nombre de modules.


