Catégorie : Administration système     Tags : ,      

    Fidèles à notre rendez-vous mensuel, pour cette sixième édition, nous vous avons concocté trois brèves. La première traite de la virtualisation complète fournie par le module KVM, mettant à profit les extensions matérielles d’AMD et Intel : respectivement SVM et VT-x. La suivante se penche sur la gestion de l’énergie en développant plus particulièrement le suspend-to-disk (hibernation). Finalement, une introduction à Sysfs explique la façon choisie par le noyau de représenter le système sous-jacent à l’espace utilisateur.

    [Technique] KVM : Kernel based Virtual Machine : la virtualisation complète au sein du noyau

    Préambule

    KVM est une solution de virtualisation complète fondée sur les technologies de virtualisation matérielle. Son principal développeur est Avi Kivity. Elle séjourne pour l’instant dans la branche de test (-mm) du noyau et son développement est très actif. Au départ, KVM ne supportait que la technologie d’Intel : VT-x (Virtual technology) pour architecture x86. Depuis, l’architecture a été repensée de façon à extraire la partie générique de la technologie matérielle sous-jacente. Ainsi, le module originel kvm.ko, se retrouve découpé actuellement en trois modules : kvm.ko, kvm-intel.ko et kvm-amd.ko (ce dernier n’est présent que depuis le 28 novembre et apporte, comme son nom l’indique, le support de la technologie Pacifica d’AMD, renommée SVM – Secure Virtual Machine). Il est probable (sous le conseil avisé d’Ingo Molnar) que ce sous-système, résidant actuellement au sein des pilotes (<linux-src-directory>/drivers/kvm), finisse dans un répertoire consacré à la racine des sources du noyau. En effet, le projet prend de l’ampleur et ajoute surtout à Linux une capacité notoire, celle d’hyperviseur (aussi appelé "VMM" pour Virtual Machine Monitor, à ne pas confondre avec Virtual Memory Manager).
    Revenons brièvement sur la différence entre la virtualisation complète et la paravirtualisation. Cette dernière, exploitée par Xen par exemple, repose sur l’hypothèse que le système invité est au courant qu’il tourne sur une machine virtuelle. Par conséquent, un système invité va devoir coopérer avec l’hyperviseur afin que celui-ci puisse gérer de manière performante une multitude d’invités. Le problème avec cette approche est qu’il est nécessaire de patcher le système invité afin qu’il puisse tourner sur le système hôte. De l’autre côté, nous avons la virtualisation complète qui est censée fournir une abstraction totale de l’architecture matérielle sous-jacente aux systèmes invités, évitant ainsi leurs modifications (nécessaires à la paravirtualisation). Cette approche a souvent été problématique pour ces performances, car, jusqu’alors, "tout" se faisait au niveau logiciel. Aucun support matériel n’était fourni pour la virtualisation. À présent, Intel et AMD fournissent une extension matérielle à la virtualisation dans leurs microprocesseurs. Il faut savoir toutefois qu’ils ne sont pas les précurseurs en la matière. IBM a débuté le mouvement dès 1999 avec les Power5 via une technologie appelée "Logical Partitioning" (LPAR).
    Le support de ces technologies matérielles est donc intégré à Linux directement via KVM. Le travail de l’hyperviseur est alors bien plus succinct que pour la version logicielle complète et les performances sont, par conséquent, bien supérieures. Décrivons succinctement ce qu’apporte l’extension matérielle de virtualisation. Rappelons que la structure en anneaux des architectures x86 est utilisée pour différencier le mode noyau (ring 0) du mode utilisateur (ring 3). Pour fournir à l’hyperviseur une structure plus adéquate à son travail, il a fallu trouver une abstraction de la CPU au-delà de ces anneaux. Sous Intel (la technologie développée par AMD est analogue). La CPU fonctionne en deux modes distincts : le VMX (le X pour eXtension) root (fully privileged ring 0) réservé à l’hyperviseur et le VMX non root (less privileged ring 0) utilisé par les systèmes invités. Un nouveau jeu d’instructions relatif à la gestion des VM (Virtual Machine) par l’hyperviseur n’est utilisable qu’en VMX root. Nous y trouvons entre autres, des instructions de chargement/lancement de VM. L’autre support fondamental que fournit le matériel est la façon dont est provoqué le passage de l’OS invité à l’hyperviseur. Cette sortie de l’OS invité est événementielle. Certaines instructions matérielles (rdmsr, invd, etc.), un ensemble d’exceptions (choisies par l’hyperviseur), l’accès aux E/S des périphériques et l’accès à certains registres, déclenchent cette transition de modes. Ainsi l’hyperviseur logiciel dispose d’un environnement propice à son développement. Pour conclure sur cette extension matérielle, notons que l’état (i. e. les registres de contrôle, RSP, RIP, RFLAGS, les sélecteurs, les caractéristiques des segments, les MSR, etc.) des machines virtuelles, ainsi que celui de l’hôte est stocké en mémoire dans des structures appelées VMCS (Virtual Machine Control Structure). Le matériel manipule ces structures de manière transparente via les instructions matérielles spécifiques fournies.
    D’un point de vue pratique, KVM gère ces machines virtuelles aux travers des abstractions fournies par Linux. Ainsi, chaque machine virtuelle est vue sur le système hôte comme un processus. Les outils top, ps, etc. sont donc opérationnels et renseignent sur l’état des machines virtuelles. Ces dernières possèdent leur propre instance privée du matériel virtualisé (disques, carte réseau, chip graphique, etc.). Notons que les travaux sur les containers (la notion d’instance privée) du 2.6.19 (voir le KC 89) ont été nécessaires à cela. Aussi, un autre aspect très intéressant de cette approche est de profiter de toutes les dernières optimisations de Linux en ce qui concerne par exemple l’ordonnanceur. Ainsi la gestion du SMP, les dernières heuristiques de l’ordonnanceur, etc. sont disponibles de façon transparente pour KVM. Finalement, terminons sur le fait que cette solution rend possible l’exécution de machines virtuelles sans émulation (à l’exception toutefois de quelques instructions) ou traduction binaire.

    AMD a dévoilé l’intégralité des spécifications de Pacifica lors de LinuxWorld en mai 2005. Preuve que le marché Linux est clairement le terrain de jeu pour ce type de technologie.

    Tour d’horizon de l’implémentation

    L’infrastructure de virtualisation repose sur l’implémentation de certaines primitives, notamment ioctl() et mmap() (sur le périphérique virtuel /dev/kvm) pour la mise en place des machines virtuelles. La gestion du contexte de ces VM passe par les primitives vcpu_load()/vcpu_put() qui s’occupent du chargement/déchargement des structures de contrôle (i. e. les VMCS). Les VMCS sont initialisées de façon à fournir une plate-forme adéquate pour les bootstraps s’appuyant sur le mode-réel des systèmes x86. Finalement, une certaine logique du traitement des registres de contrôle est mise en place afin de gérer correctement les systèmes invités.
    Comme nous l’avons vu en préambule, certains évènements peuvent causer la sortie de la VM, i. e. le passage du processeur du mode VMX non-root au mode VMX root, entraînant l’exécution de gestionnaires spécifiques. KVM les implémente pour : les exceptions (seulement les fautes de pages, actuellement), l’accès aux registres de contrôle, l’instruction invlpg (pour l’invalidation d’une entrée dans le TLB – Translation Look-aside Buffer : utilisé par la MMU pour stocker les correspondances entre les adresses linéaires et physiques, et ainsi éviter à chaque reprise le parcours fastidieux des tables de pages en mémoire), les instructions d’E/S, l’interruption du gestionnaire de fenêtre (lorsque les interruptions invitées sont activées), l’accès au MSR (Model-Specific Registers), les registres de debug et l’instruction cpuid. Notons au passage que la détermination des MSR est dynamique et que seulement ceux qui sont présents sur le système sont sauvegardés et chargés (permettant ainsi de corriger totalement une classe de bugs qui posait problème).
    Pour passer en mode invité (i. e. le mode VMX non-root pour Intel), la commande KVM_RUN pour ioctl() est définie. La gestion des chemins de sortie des VM (i. e. le passage du VMX non-root au VMX root) mise en œuvre, traite les deux cas de sortie correspondant au mode noyau ou au mode utilisateur du système invité. KVM implémente également l’injection d’interruptions, ainsi que le débogage des systèmes invités, offrant une alternative aux debogueurs ring 0 (citons (promouvons ;) en exemple rr0d – rasta ring 0 debogueur de Fabrice Desclaux – fonctionnant en théorie ;) quel que soit le système d’exploitation) employés lors du debogage (ou autres ;) de noyaux.
    Une partie importante dans la virtualisation concerne la gestion de la MMU. Dans notre cas : un modèle de virtualisation complète. Il est couramment utilisé une technique dite de "shadow page tables". Il s’agit de maintenir deux jeux de table de pages : l’un appartenant au système invité (non visible du matériel via le registre de contrôle cr3) et l’autre maintenu par l’hyperviseur et utilisé directement par le matériel. A la charge ensuite de l’hyperviseur de synchroniser les tables de pages "réelles" avec celles des systèmes invités. KVM implémente pour l’instant une solution peu évoluée utilisant les instructions de gestion du TLB afin de garder la synchronisation entre les shadow page tables et celles des systèmes invités. Le problème avec cette implémentation (temporaire) est qu’à chaque transition entre espace d’adressage d’un système invité, il est nécessaire de reconstruire les shadow page tables pour le nouvel espace d’adressage :/ Pour pallier ce problème, AMD et Intel pourraient fournir leur support en proposant des processeurs intégrant une gestion de tables de pages imbriquées. En attendant cela ;), la solution envisagée pour KVM est un système de cache pour ces tables, comme nous allons le voir un peu plus loin.

    La MMU est la Memory Management Unit. La MMU a été intégrée aux processeurs Intel x86 à partir du 80386. C’est ce composant du processeur qui, piloté par le noyau, permet de détecter une tentative d’accès à de la mémoire hors plage réservée et donc de générer une interruption et un signal SIGSEGV sous Linux.

    Concernant la gestion mémoire à un niveau plus élevé, KVM met en place une gestion fondée sur des "slots", notion plus ou moins proche de la notion de slot DIMM qui permet des allocations non contiguës. Cela rend possible, entre autres, le support du hotplug de mémoires et l’ajout de framebuffer PCI en cours d’exécution des machines virtuelles.
    Un autre bloc important correspond à l’émulation x86 fournie par KVM. Attention, il ne s’agit pas d’émuler une machine complète dans ce cas, fort heureusement (sinon, il n’y aurait aucun intérêt à KVM ;). La nécessité d’une émulation s’explique par les raisons suivantes. Les instructions mmio sont interceptées par le matériel comme des fautes de pages sans aucune information sur l’opération qui doit s’effectuer autre que l’adresse virtuelle (i. e. linéaire) impliquée. Ensuite, le mode-réel est émulé via le mode vm86 qui ne fournit pas d’interception spécifique pour les instructions privilégiées. Ainsi, il est nécessaire d’émuler les instructions mov cr*, lgdt et lidt. Notons cependant pour cette dernière raison qu’elle ne concerne que le cas d’Intel, car AMD implémente, dans son extension SVM, un support complet du mode-réel. Ainsi le module kvm-amd.ko n’a pas besoin d’émuler les instructions concernées. Cependant, pour l’instant KVM utilise encore l’émulation pour AMD, car le support de SVM est très récent et n’a pas eu le temps d’être modifié à ce niveau. Quand ce changement prendra place, il sera alors possible de gérer un nombre bien plus important de systèmes invités pour l’architecture d’AMD. Finalement, la dernière raison de la mise en place d’un émulateur vient de la future gestion de la MMU. Nous venons de voir que l’actuelle solution n’était pas exceptionnelle en termes de performance. Pour pallier ces soucis, il est prévu de mettre en cache les shadow page tables afin d’éviter le circuit coûteux du "construire-détruire-reconstruire-...". Cependant, mettre en cache ces tables suppose de protéger en écriture celles des systèmes invités afin de conserver leur synchronisation. Ainsi, chaque écriture sur une table de pages invitée doit être émulée. Notons au passage que l’implémentation de cet émulateur est fondée sur celui de l’hyperviseur de Xen, en n’en gardant que les parties nécessaires.
    Finissons ce tour d’horizon sur une anecdote ;) Pour éviter d’avoir une version de binutils plus récente que celle présente dans le fichier concernant les exigences sur la compilation de Linux (Documentation/Changes), les instructions des extensions de virtualisation matérielle sont définies directement dans le code de la manière suivante. Par exemple, pour les instructions de SVM, nous avons :

    #define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda"
    #define SVM_VMRUN ".byte 0x0f, 0x01, 0xd8"
    #define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb"

    La virtualisation est très en vogue dans les milieux du Logiciel libre, mais c’est également le cas pour la concurrence, à commencer par Vista de Microsoft et ses éditions Business et Ultimate (Ultimate ? :)

    Les développeurs noyau préfèrent pour l’instant cette solution "hideuse" ;) afin d’éviter le bouleversement que pourrait entraîner la mise à jour de binutils dans certains environnements, notamment pour ceux dédiés à la cross-compilation.

    L’interface utilisateur

    En ce qui concerne l’interface utilisateur, tout passe par l’appel système ioctl() sur /dev/kvm. Ainsi, il est possible d’ajouter de la mémoire à une machine virtuelle, d’ajouter une CPU virtuelle, de transférer le contrôle à une CPU virtuelle, de se renseigner sur les pages mémoires modifiées par les machines virtuelles, etc.
    Un aspect important de la virtualisation est de pouvoir migrer facilement une machine virtuelle d’un hôte vers un autre. Pour effectuer cela, une solution naturelle est de suspendre la VM, de la transférer et finalement de reprendre son exécution. KVM rend possible cela depuis peu, en fournissant à l’espace utilisateur de l’hôte le support nécessaire. Ainsi, les interruptions en suspens sont disponibles pour l’espace utilisateur. Les fonctionnalités de sauvegarde et de restauration du TSC (Time-Stamp Counter) et des MSR (nécessaires pour le suspend/resume) sont possibles depuis l’espace utilisateur.
    Cette nouvelle fonctionnalité de migration (décrite par son auteur comme une zombie migration, puisque le système invité ne continue pas, pour l’instant, son exécution lors de sa migration) peut être utilisée de la façon suivante en considérant deux hôtes A et B (exemple fourni par Avi Kivity) :
    1. A : Démarrez une VM. Jouer avec pour un temps.
    2. B : Démarrez une VM avec exactement les mêmes options et en plus ‘-S’. Les images de disques doivent être partagées.
    3. A : Switchez sur l’hyperviseur (alt-ctrl-2), tapez ‘stop’.
    4. B : Switchez sur l’hyperviseur, tapez ‘migration listen’.
    5. A : Tapez ‘migration connect’
    6. A : Tapez ‘migration start offline’
    7. A : Tapez ‘quit’
    8: B : Tapez ‘cont’, et switchez sur le système ([alt]-[ctrl]-[1]).
    Concluons cette brève en signalant l’activité débordante autour de KVM depuis le mois de novembre (des patchs se succèdent quasiment tous les jours). Gageons que le séjour au sein de la branche -mm ne sera que de courte durée avant inclusion dans la mainline. Sur ces mots, nous vous laissons le loisir de suivre ce projet via http://kvm.sourceforge.net et/ou de sa liste de diffusion http://lists.sourceforge.net/lists/listinfo/kvm-devel ou encore via la LKML ;)
    Parmi les domaines dans lesquels notre OS doit toujours faire ses preuves, est celui de la gestion d’énergie, et pour un des côtés les plus visibles à l’utilisateur, le suspend-to-disk (hibernation) et le suspend-to-ram. Nous développons dans la suite uniquement la gestion de l’hibernation.
    Fonctionnalité présente dans MS-Windows depuis sa version 2000, et dans MacOS depuis 10.4.3 seulement, Linux a tardé à proposer quelque chose de fonctionnel et doit encore faire des efforts pour concurrencer ses alter ego commerciaux. Comme vous pouvez vous en douter, la raison en est qu’une implémentation robuste et satisfaisante de ces fonctions, si utiles aux ordinateurs portables et configurations légères, dites "embarquées", est complexe.

    Historique et ACPI :

    La gestion de l’énergie fit son apparition sur PC via le système Advanced Power Management, qui était en fait géré par le BIOS et permettait une interaction minimaliste avec l’OS. Un consortium comprenant entre autres Intel, HP et Microsoft se met en place pour définir le standard Advanced Configuration and Power Interface (ACPI), qui normalise l’interaction entre le matériel et le système d’exploitation concernant les questions de configuration et de gestion de consommation d’énergie.
    L’ACPI fonctionne au moyen de tables descriptives (Differentiated System Description Table) qui font la liaison entre appels de l’OS et matériel associé. Ces tables, compilées via le compilateur ACPI et stockées dans le BIOS, sont rédigées dans un langage spécifique appelé "AML" (ACPI Machine Language), dont voici un extrait (ici, pour la description de différents états de consommation d’énergie d’un processeur) :

    Processor (
    \_SB.CPU0, // Nom du processeur
    1,           // Numéro ACPI du processeur
    0x120,
    6)
    {Name (_CST, Package()
     { 3,
     Package(){ResourceTemplate(){Register(FFixedHW, 0, 0, 0)}, 1, 20, 1000},
     Package(){ResourceTemplate(){Register(SystemIO, 8, 0, 0x161)}, 2, 40, 750},
     Package(){ResourceTemplate(){Register(SystemIO, 8, 0, 0x162)}, 3, 60, 500}
    })
    Name(_CSD, Package()
    { Package(){6, 0, 0, 0xFD, 2, 1},
      Package(){6, 0, 0, 0xFD, 2, 2}
    }) }

    Rendue actuellement en version 3.0a, la norme est devenue très (trop pour certains) compliquée, et existe en seulement deux implémentations complètes : celle de Microsoft, utilisée par ses OS, et celle d’Intel, utilisée par tous les autres, qu’ils soient Linux, Solaris, Mac OS... Le compilateur de Microsoft est tolérant aux erreurs et supporte des déviances par rapport aux spécifications officielles, tandis que celui d’Intel les implémente strictement. Ce dernier ne peut donc pas traiter certaines tables de constructeurs peu respectueux, tandis que celui de MS compilera une table qui sera buggée aux yeux de notre OS favori, friand (à raison) de normes strictement respectées. C’est la première cause qui peut entraîner que sur votre système, la gestion de la consommation énergétique est inexistante ou inefficace. En ayant activé les options nécessaires dans le noyau (Power Management Support -> ACPI), le système devrait présenter des entrées dans /proc/acpi telles que battery, fan, thermal_zone, button... et peut ainsi détecter des événements tels que l’appui sur le bouton "mise en veille", le branchement/débranchement de l’alimentation au secteur, la fermeture d’un ordinateur portable... Il peut connaître par exemple la température du processeur, la vitesse de rotation des ventilateurs, le niveau de charge de la batterie... Il peut permettre de régler la vitesse du ventilateur, d’allumer/éteindre le rétro-éclairage...
    La gestion de la consommation d’énergie du processeur est un domaine un peu à part, qui dépend de cpufreq.
    Si les options listées ci-dessus sont absentes, elles peuvent donc indiquer qu’une table ACPI, appelée table DSDT, est défectueuse. Pour autant, la situation n’est pas bloquée. Voyons ensemble comment faire en sorte que le noyau Linux gère correctement l’ACPI. Le but ici va être de trouver une table DSDT déjà corrigée, de la compiler et de la faire utiliser par le noyau en lieu et place de celle du BIOS.
    Les moteurs de recherche seront vos alliés les plus efficaces pour dénicher une table DSDT corrigée correspondant à votre configuration. Elle se présentera sous forme d’un fichier .asl.
    Téléchargeons le compilateur Intel (http://www.intel.com/technology/IAPC/acpi/downloads.htm) et installons-le (désarchivage, make && make install suffisent).
    Compilons la table récupérée :
    $ iasl -on /ma/table.asl
    La table corrigée doit normalement se compiler sans erreur et deux fichiers sont générés dans le répertoire courant, portant le nom de la table de départ, avec les extensions .aml et .hex.
    Il nous reste à indiquer au noyau de l’utiliser systématiquement. Nous avons le choix de le spécifier lors de la configuration du noyau pour les dernières versions, ou de l’inclure dans le fichier initrd.

    ACPI est l’acronyme d’Advanced Configuration and Power Interface, interface avancée de configuration et de gestion de l’énergie. Une norme co-développée par Microsoft, Toshiba, Intel, Phoenix Technologies et Hewlett Packard.

    La première solution implique de renseigner le chemin vers la table compilée dans l’option Power Management -> ACPI -> Include Custom DSDT -> Custom DSDT table file to include.
    Une recompilation de noyau plus tard, vous pouvez rebooter pour tester le bon fonctionnement de l’ACPI. Inclure la table dans une image initrd est légèrement plus complexe. Il vous faut le patch noyau acpi-dsdt-initrd ; ajouter le fichier .aml à l’image initrd/initramfs est presque spécifique à chaque distribution, mais a pour avantage de ne pas obliger une recompilation noyau lors du changement de table DSDT.
    Côté espace utilisateur, le démon acpid est chargé de collecter les événements ACPI via /proc/acpi/event et d’exécuter les scripts que vous aurez définis en réaction à tel où tel événement dans le dossier /etc/acpi/events/. A un niveau plus haut encore, rassemblant tous les moyens de récupérer des informations et d’agir sur la consommation du système (ACPI, lm_sensors, hdparm...), se trouvent des utilitaires comme kpowersave ou gnome-power-manager qui méritent le détour.
    Toutes les configurations ne sont cependant pas capables d’exposer toutes ces informations via ACPI ; dans ce cas (ordinateurs non portables par exemple), il est possible d’interroger le bus i2c et son dérivé SMBUS. Ce bus, très simple dans sa conception et destiné à des transferts en petit volume à faible débit, est souvent présent sur nos configurations actuelles. L’utilitaire sensors-detect du projet lm_sensors vous dira s’il détecte de tels composants, mais ceci sort du cadre de notre article.

    L’i2c pour Inter Integrated Circuit Bus a été développé par Philips pour les applications de domotique et électronique. L’i2c est un bus présent partout, de votre téléphone mobile à votre ordinateur en passant par votre téléviseur. i2c est une marque déposée par Philips. Les constructeurs de composants compatibles utilisent souvent le terme SPI en lieu et place d’i2c.

    L’hibernation

    L’ACPI définit 4 états globaux du système et du matériel : Working, Sleeping, Soft Off et Mechanical Off. En état Sleeping, nous distinguons quatre sous-états appelés S1 à S4.
    S1 et S2 sont deux états de veille légère, peu utilisés.
    S3 représente le suspend-to-RAM (encore appelé "sleep"), c’est-à-dire que le processeur et les périphériques sont stoppés, tandis que l’état du système est sauvegardé en mémoire vive, qui reste l’un des seuls composants alimentés.
    S4 est connu sous l’appelation "suspend-to-disk" ou "hibernation". Le système n’est plus électriquement alimenté, son état est stocké sur le disque.
    Sous Linux, trois implémentations différentes de l’hibernation existent. La première est appelée "swusp", se déroule en espace noyau et est la méthode par défaut de Linux. La seconde, nommée "Software Suspend 2", est fournie sous forme de patchs à appliquer aux sources du noyau. Parfois réputée pour mieux fonctionner que la méthode traditionnelle et de manière plus rapide, elle a été critiquée pour la qualité de son code. Elle offre des possibilités telles que la compression ou le chiffrage de l’image d’état du système. La dernière possibilité est d’utiliser le récent uswusp, qui effectue le plus de travail possible en espace utilisateur. Débattu ces derniers mois sur la LKML et au Power Management Summit 2006, le choix d’une méthode définitive d’hibernation semble surtout se porter vers la première (les développeurs ont jugé qu’uswusp, le petit troisième, apportait peu de choses utiles justifiant un code séparé en espace utilisateur, bien que son devenir ne soit pas encore tranché). Nous nous intéresserons ici à la méthode traditionnelle.
    Pour effectuer un suspend-to-disk, muni d’un noyau ayant l’option CONFIG_SOFTWARE_SUSPEND sélectionnée, nous pouvons entrer :

    # echo disk > /sys/power/state (hibernation, ou suspend to disk, état ACPI S4)
    # echo “mem” > /sys/power/state (suspend to RAM, état ACPI S3)

    Pour revenir à l’état dans lequel nous avions laissé le système précédemment, nous devons spécifier au noyau qu’il doit démarrer en chargeant une image du système depuis la partition de swap, via l’option resume = /dev/hdX.
    Si la manipulation ne fonctionne pas, nous avons très certainement un problème avec un pilote de périphérique ou de système de fichiers qui gère mal l’hibernation. En effet, ils sont la première source d’erreurs et de plantages lors des opérations de veille/hibernation. Cependant, depuis ses dernières versions, notre noyau gère le suspend pour les périphériques SATA, traite mieux ceux de type USB, bénéficie d’un mode debug lors de ces opérations, et, comme annoncé dans notre Kernel Corner spécial 2.6.19, définit des fonctions supplémentaires pouvant venir compléter et affiner la gestion des périphériques lors des phases de mise en veille et de réveil.
    Justement, au niveau du noyau, que se produit-il lorsque nous lui demandons d’entrer en mode S4 ?
    La fonction pm_suspend_disk() (kernel/power/disk.c) appelle les fonctions prepare_processes() qui se chargent de lancer disable_non_boot_cpus() (passage en mode monoprocesseur), puis freeze_processes() (gel des processus en cours d’exécution). Retour à pm_suspend_disk(), qui appelle alors device_suspend() (stoppage de l’ensemble des périphériques). S’ils sont stoppés sans encombre, c’est ensuite swsusp_suspend() (kernel/power/swsusp.c) qui entre en action, créant une image de la mémoire vive. Les périphériques sont alors rallumés, afin de permettre l’écriture de l’image mémoire sur la partition de swap ; enfin, le système suivra la procédure que nous lui avons indiquée, reboot ou extinction.

    Sysfs, système de fichiers virtuel

    Les systèmes Unix utilisent souvent des systèmes de fichiers dits "virtuels" à différentes fins. Fidèles au vieux principe selon lequel tout doit être fichier, nous retrouvons ainsi les périphériques sous formes d’entrées dans la hiérarchie /dev. Cette notion a été étendue à la représentation d’éléments supplémentaires, tels que l’état du système et de ses tâches en cours, via le célèbre /proc. Présentant des informations variables suivant les systèmes d’exploitation, il est très fourni sous Linux et dépasse même le cadre d’utilisation qu’il devait avoir à l’origine. Ainsi, notre OS nous présente un petit fouillis d’informations diverses, comme /proc/modules, /proc/fs, /proc/cpuinfo...
    A l’occasion de la sortie de la série 2.6 du noyau, les développeurs ont souhaité intégrer un FS virtuel chargé d’exposer la configuration matérielle du système, de manière plus structurée que l’existant présent dans /proc. Ainsi Sysfs a été créé et représente un moyen d’accéder simplement à tout ce qui se passe du côté noyau, périphériques et drivers, et de configurer certains des paramètres présents. D’une manière générale, Sysfs peut présenter les paramètres de tout élément considéré comme kobject (Kernel Object, éléments du noyau pouvant être chargés et retirés, par exemple les modules en font partie). Voyons ensemble son organisation et les informations qu’il expose.
    Sysfs apparaît comme un FS à part entière :

    $ mount
    /dev/hdc1 on / type reiserfs (rw,acl,user_xattr)
    /dev/hdc4 on /home type reiserfs (rw,acl,user_xattr)
    proc on /proc type proc (rw)
    sysfs on /sys type sysfs (rw)

    Dérivé de ramfs, il réside en mémoire vive. A sa racine, plusieurs catégories apparaissent : block, bus, class, devices, firmware, fs, kernel, module, power.
    Le dossier /sys/devices reflète la topologie physique des périphériques dans le système, tandis que /sys/bus reflète leur organisation par rapport au type de bus qu’ils utilisent, au moyen de liens symboliques vers les entrées correspondantes dans /sys/devices.
    Une fois atteint un périphérique particulier via la hiérarchie de dossiers /sys/devices/..., nous remarquons une liste d’éléments, de type fichier cette fois, qui lui sont dédiés. Ces fichiers sont appelés attributs. Ils représentent des paramètres et des informations sur l’objet qu’ils décrivent.
    Si nous y regardons de plus près, chaque type de bus présente des attributs communs pour tous les périphériques rattachés, mais ces attributs seront différents suivant le type de bus : chaque sous-système est responsable d’organiser ses entrées dans la hiérarchie Sysfs. Ainsi, les périphériques USB présentent tous une entrée "product" :

    $ find /sys/devices/ -name product -exec cat {} \;
    MuVo V200
    EHCI Host Controller
    UHCI Host Controller
    Dell USB Mouse
    UHCI Host Controller
    UHCI Host Controller

    Les périphériques de stockage (périphériques de bloc), classés dans /sys/block auront un attribut "media" (disk, cdrom...) et un attribut "removable" (0 ou 1). Le sous-dossier /sys/modules héberge les propriétés des modules actuellement chargés ; /sys/class, quant à lui, est une représentation des périphériques triée par classe (graphics, sound, input..) pointant tout comme /sys/bus vers /sys/devices. Enfin, /sys/power est dédié à la mise en veille du système.
    C’est le sous-système de bus qui crée une entrée /sys/device/le_bus/la_position/driver et un lien symbolique /sys/bus/le_bus/drivers/nom_driver lorsque le pilote spécifique au périphérique appelle une des fonctions register_xxx (register_chrdev par exemple).
    Dans ce sous-répertoire dédié, ce pilote pourra créer tous les attributs qu’il souhaite via la macro DRIVER_ATTR(nom_attribut, 0644, show_nom_attribut, store_nom_attribut) et l’implémentation des fonctions de lecture/écriture de la valeur de l’attribut, show_nom_attribut et store_nom_attribut.
    Une lecture ou une écriture de valeur dans cet attribut via son chemin Sysfs appelle la méthode correspondante.
    Sysfs est utilisé par des briques devenues très présentes sur nos systèmes, telles qu’udev, lspci... Peut-être voué à remplacer /proc un jour, il est encore en évolution et incomplet.

    Posté par Eric Lacombe (tuxiko) | Signature : Éric Lacombe & Matthieu Barthélemy | Article paru dans Creative Commons License

    Laissez une réponse

    Vous devez avoir ouvert une session pour écrire un commentaire.


    • Il y a actuellement

    • 666 articles/billets en ligne.