Le sous système KVM va perdre l'une de ses structures de données les plus mal famées. Paolo Bonzini, l'ingénieur de Red Hat qui maintient KVM, a fusionné une branche nommée kvm-chainsaw dans l'arbre next de KVM, et Phoronix l'a relevé le vingt six juillet. Ce qu'elle fait, c'est découper struct kvm_mmu, une structure qui avait accumulé trois métiers sans rapport, en trois structures qui en assurent chacune un. Il n'y a ici aucune fonctionnalité visible et aucun chiffre de performance à citer. Ce qu'il y a, si cela entre dans la fenêtre de fusion de Linux 7.3 attendue en seconde moitié d'août, c'est beaucoup moins de place pour une classe précise de bugs de virtualisation imbriquée.
The short answer
Paolo Bonzini a fusionné la branche kvm-chainsaw dans l'arbre next de KVM, découpant struct kvm_mmu en kvm_pagewalk pour parcourir les tables de pages invitées, un kvm_mmu allégé pour construire les tables de pages fantômes, et kvm_page_format pour agir sur les entrées existantes. La série a d'abord été publiée sur les listes kernel et kvm le onze mai, et Phoronix a rapporté la fusion le vingt six juillet. La cible est la fenêtre de fusion de Linux 7.3, attendue en seconde moitié d'août. Aucun changement visible, mais une source documentée de confusion en virtualisation imbriquée disparaît.
Baptiser une branche kvm-chainsaw annonce à peu près la couleur du diff. Cela dit aussi que le mainteneur regardait cette structure depuis un moment.
Ce qu'était devenue kvm_mmu
KVM doit tenir beaucoup de comptabilité sur les tables de pages, parce qu'une machine virtuelle a sa propre idée de l'organisation de la mémoire et que l'hôte doit rendre cette idée vraie sans laisser l'invité toucher ce qu'il ne devrait pas. La structure qui portait l'essentiel de cette comptabilité était struct kvm_mmu.
Avec le temps, elle a pris trois responsabilités distinctes. Elle décrivait le format des tables de pages de l'invité, c'est à dire la forme des entrées et la signification de chaque bit selon le mode dans lequel tourne l'invité. Elle parcourait ces tables de pages, traduisant une adresse fournie par l'invité en quelque chose sur quoi l'hôte peut agir. Et elle construisait des tables de pages, en bâtissant les structures fantômes que KVM maintient côté hôte.
Ces trois choses touchent aux mêmes données, ce qui explique qu'elles aient fini au même endroit. Ce ne sont pas les mêmes choses, ce qui explique pourquoi elles n'auraient pas dû.
Le coût pratique s'est manifesté en duplication et en confusion. Bonzini pointe la relation entre guest_mmu et nested_mmu, où le nommage avait suffisamment dérivé par rapport au comportement pour que les commentaires les décrivant soient faux. Quand vous lisez du code de virtualisation imbriquée, un invité L2 tournant dans un invité L1 tournant sur l'hôte, un commentaire trompeur sur ce que décrit telle structure n'est pas un problème cosmétique.
Le découpage
kvm_pagewalk devient le parcoureur de tables de pages. Dans la branche fusionnée il y en a deux par vCPU, gva_walk et ngpa_walk. L'ancien pointeur walk_mmu, qu'il fallait basculer selon qu'un invité L1 ou L2 tournait, est remplacé par un unique gva_walk qui couvre les deux cas. Supprimer une condition qui traversait les chemins de code imbriqués est une grande partie de l'intérêt.
kvm_mmu garde le rôle de construction, et seulement celui là. Elle bâtit des pages fantômes, et utilise un parcoureur pour le faire : toujours gva_walk quand elle est le root_mmu, toujours ngpa_walk quand elle est le guest_mmu. C'est une règle qui s'énonce en une ligne, ce qui n'était pas le cas avant.
kvm_page_format couvre les opérations sur les entrées déjà existantes, et absorbe du code jusque là éparpillé : la logique autour de permission_mask() fusionne avec les structures rsvd_bits préexistantes, si bien que la question de savoir quels bits sont réservés et quelles permissions s'appliquent trouve sa réponse au même endroit.
La publication de mai comptait vingt deux correctifs, avec un diffstat de quelques centaines de lignes dans chaque sens sur quinze fichiers, ce qui rappelle utilement que l'importance d'une réécriture ne se mesure pas à sa taille. La quasi totalité du changement consiste à déplacer des accès de champs d'une structure à une autre. La valeur est dans ce qui devient possible ensuite, et Bonzini en cite un exemple direct : prendre en charge des entrées de tables de pages fantômes où le bit d'exécution diffère entre mode superviseur et mode utilisateur, exprimé via les attributs mémoire, se logeait mal dans l'ancienne structure.
La note sur l'outillage
Bonzini a déclaré avoir utilisé un grand modèle de langage pour les parties mécaniques de la réécriture, et la comparaison qu'il choisit est le point intéressant. Il a parlé d'un Coccinelle en langage naturel.
Coccinelle est un outil que les développeurs noyau utilisent depuis des années pour appliquer un patch sémantique, une transformation décrite, à un arbre entier. Quand il faut changer le même motif d'appel à quatre mille endroits, on écrit la règle plutôt que les quatre mille modifications. Placer un LLM dans ce créneau est une affirmation sur le périmètre : il a fait la transformation, pas la conception. Bonzini est explicite sur le fait que les décisions d'architecture sont restées les siennes.
Savoir si ce cadrage tient est une chose que la communauté du noyau tranchera d'elle même, et ce n'est pas une question réglée là bas. Debian a justement voté ce mois ci une résolution générale sur les contributions rédigées par des LLM. Ce qu'il faut retenir ici, c'est simplement que la déclaration a été faite, et faite assez précisément pour qu'un relecteur sache quoi chercher.
Que faire
Rien, pour l'instant, ce qui est la bonne réponse à la plupart des nouvelles d'internes du noyau.
Si vous faites tourner de la virtualisation imbriquée pour de vrai, c'est à dire des VM dans des VM en production et pas comme curiosité de laboratoire, cela vaut la peine d'être au courant, parce que c'est exactement là que vivait la confusion en cours de nettoyage. Les bugs dans cette zone ont toujours été difficiles à reproduire et difficiles à lire, et le code qui devient plus clair est la façon dont cela s'améliore sur les prochaines versions.
Si vous maintenez quoi que ce soit hors arbre qui touche aux internes du MMU de KVM, le tableau est différent et le travail est réel. Des accès de champs se déplacent, walk_mmu disparaît, et il n'y a pas de couche de compatibilité pour une structure qui n'a jamais été une interface stable. La branche est dans next maintenant, la fenêtre où le vérifier ne coûte pas cher.
Sources et pour aller plus loin
- LWN : KVM, apply chainsaw to struct kvm_mmu
- Phoronix : le KVM chainsaw attendu dans Linux 7.3 pour traiter la god data structure
- La lettre d'accompagnement de la série sur la liste du noyau
- L'arbre git de KVM
- Documentation du noyau : le MMU fantôme x86 de KVM
Questions fréquentes
Qu'est ce qui n'allait pas avec struct kvm_mmu ?
Elle faisait trois métiers à la fois. Elle décrivait le format des tables de pages de l'invité, elle parcourait ces tables de pages, et elle construisait les tables de pages que KVM utilise lui même. Ce sont des activités liées mais ce n'est pas la même activité, et les entasser dans une seule structure obligeait tout code qui cherchait l'une des trois à traîner les deux autres. La lettre d'accompagnement de Bonzini parle d'une god data structure, le nom standard exactement pour ce genre de problème : un type qui a grossi par accrétion jusqu'à ce que plus personne ne puisse décrire son rôle en une phrase.
Quelles sont les trois structures de remplacement ?
kvm_pagewalk est le parcoureur de tables de pages, et il y en a deux par vCPU dans la branche fusionnée, nommés gva_walk et ngpa_walk. kvm_mmu garde le rôle de construction des tables de pages et utilise un parcoureur pour bâtir les pages fantômes. kvm_page_format gère les opérations sur les entrées de tables de pages qui existent déjà, et absorbe le code qui gravitait autour de permission_mask() ainsi que les structures rsvd_bits préexistantes. Chacune des trois porte désormais un nom qui dit à quoi elle sert.
Est ce que cela change quelque chose pour qui fait tourner des VM aujourd'hui ?
Pas directement. Aucune fonctionnalité nouvelle, aucune option de configuration et aucune promesse de performance n'accompagne ce travail. C'est une réécriture interne, et une réécriture réussie est une réécriture que personne ne remarque. L'effet indirect est celui qui compte sur la durée : du code plus clair est du code où le prochain bug se voit mieux, et cette structure se trouvait sous la virtualisation imbriquée, l'une des parties de KVM les plus difficiles à raisonner. Elle débloque aussi des travaux difficiles à exprimer avant, dont la prise en charge d'entrées de tables de pages fantômes où les bits d'exécution diffèrent entre mode superviseur et mode utilisateur.
Quand cela arriverait il dans un noyau installable ?
La branche est dans l'arbre next de KVM, la zone de préparation de la fenêtre de fusion suivante. La fenêtre de fusion de Linux 7.3 est attendue en seconde moitié d'août, donc si cela y entre, la version stable 7.3 suit après les deux mois habituels de versions candidates. Les noyaux des distributions le reprennent ensuite selon leur propre calendrier, ce qui pour une distribution d'entreprise peut vouloir dire un an ou plus. Rien là dedans n'est urgent du point de vue de l'exploitation.
Est il exact qu'un LLM a été utilisé sur cette série de correctifs ?
Bonzini l'a lui même déclaré, et la formulation qu'il emploie mérite une lecture attentive. Il a décrit un usage du modèle comme un Coccinelle en langage naturel, en le comparant à l'outil de patch sémantique que les développeurs noyau utilisent déjà pour appliquer la même transformation mécanique à des milliers d'endroits d'appel. Les décisions d'architecture, c'est à dire la conception même du découpage en trois, sont restées les siennes. C'est un usage étroit et clairement délimité, et c'est la déclaration qui rend la chose relisable.