Pourquoi compiler en dur plutôt qu'en modules ?

Bonjour à tous

Lorsqu’on recompile son kernel, il est possible d’inclure des fonctionnalités soit en dur dans le noyau, soit sous forme de modules (ou pas du tout si on n’en pas besoin).

Je vois très bien l’intérêt d’inclure un contrôle RAID en dur dans le noyau : ça permet au noyau d’être capable d’utiliser le disque dur pour démarrer. Ceci dit ce n’est plus indispensable depuis que GRUB 2 existe, puisqu’il prend en charge le chargement de modules et peut donc permettre de charger une fonction qui ne serait pas dans le kernel avant même que le kernel soit lancé.

D’où ma question : à quoi peut bien encore servir une compilation en dur des fonctions ?? Ca alourdi le noyau, ça le rend moins flexible (puisqu’il faut recompiler tout le kernel si on veut apporter une modif sur une fonction en dur), et ça bouffe de la mémoire inutilement. Et ce n’est plus indispensable pour booter.

D’abord, tu mélanges deux choses différentes. Les modules de grub 2 et les modules du noyau Linux sont deux choses totalement différentes qui n’ont strictement aucun lien et ont des rôles bien distincts. Un petit rappel sur le déroulement du démarrage d’un système GNU/Linux :

  1. Le chargeur (grub, lilo…) est chargé en mémoire et exécuté.
  2. Le chargeur charge en mémoire l’image du noyau et optionnellement de l’initramfs ou initrd et démarre le noyau.
  3. Si un initramfs ou initrd est présent, le noyau le monte comme racine provisoire et exécute un programme ou script de démarrage chargé notamment de monter la racine définitive (ce qui peut nécessiter d’exécuter d’autres programmes et de charger des modules du noyau qui se doivent se trouver dans l’initramfs ou initrd). Sinon le noyau monte directement la racine définitive.
  4. Le programme /sbin/init est exécuté et lance les scripts de démarrage.

Les modules de grub lui permettent de lire diverses structures de données comme un volume RAID logiciel afin de charger l’image du noyau et de l’initramfs ou initrd. Mais à partir du moment où grub passe la main au noyau, grub n’existe plus et ses modules non plus. Le noyau a besoin de ses propres pilotes pour accéder à la racine finale et la monter. Si ces pilotes sont en module, le recours à un initramfs ou initrd les contenant est nécessaire. Le fait que grub 2 a des modules pour lire le RAID logiciel n’a aucune influence sur la capacité du noyau Linux a lire le RAID logiciel, que se soit avec les pilotes en dur ou en modules.

Je vois deux raisons pour compiler en dur plutôt qu’en module :

  • Dans le cas d’un noyau entièrement monolithique sans module, où toutes les fonctions nécessaires sont en dur et où le chargement des modules est désactivé. C’est plus simple (pas besoin de module-init-tools) et plus sûr car la possibilité de charger des modules peut constituer un risque de sécurité.

  • Dans le cas où on n’utilise pas d’initramfs ni initrd (mon cas), il faut au minimum que les pilotes nécessaires au montage de la racine soient compilés en dur. Cela ne consomme pas de mémoire en plus puisque les modules correspondants seraient chargés de toute façon. Par contre le noyau ainsi construit est moins polyvalent. A noter qu’il n’est pas possible de se passer d’initramfs ou d’initrd dans tous les cas.

Merci pour cette réponse très complète !

Aaah, j’ai enfin une vision claire de la séquence de boot de Linux :smiley:
Ceci dit en cherchant avec les bons termes j’aurais pu trouver… On est toujours trop paresseux.

Par exemple ?

D’accord, c’est donc surtout dans la flexibilité du noyau que réside l’intérêt pour un utilisateur lambda qui se limiterait à du surf, de la bureautique et du multimedia. Après, l’aspect sécurité peut intervenir dans un contexte plus spécifique, comme en entreprise. Pour ce qui est des performances, il n’y a donc pas vraiment d’intérêt pour un utilisateur classique qui ne percevra probablement pas de différences.

Maintenant tout dépend du niveau d’exigence de l’utilisateur en question.

Si quelqu’un voit d’autres raisons, n’hésitez pas.

Un initramfs ou initrd est nécessaire dans les cas où le noyau n’est pas capable seul d’accéder ou de monter la racine, où l’intervention d’un programme externe est requis. Cela inclut les situations suivantes :

  • volume racine spécifié par son UUID (root=UUID=xxx) ou son label (root=LABEL=xxx) ou un alias et non par son nom de périphérique canonique (root=/dev/xxx)
  • racine sur volume RAID logiciel non auto-assemblé, doit être assemblé par mdadm [1]
  • racine sur volume pseudo-RAID de carte mère (fakeraid/ataraid), doit être assemblé par dmraid
  • racine sur volume LVM
  • racine sur volume chiffré

|1] Le noyau peut assembler directement seulement les volumes RAID dont le type de partition est “RAID autodetect” (0xfd) et le superbloc en version 0.90, si le support du RAID logiciel (md) est compilé en dur. A noter que l’auto-assemblage par le noyau pourrait disparaître à l’avenir car il pose certains problèmes et est découragé au profit de l’assemblage par mdadm.

Je ne suis pas sûr de comprendre cette phrase. La flexibilité est du côté d’un noyau modulaire et d’un initramfs qui s’adaptent à une grande variété de matériels. Un noyau en dur se justifie davantage quand le matériel est figé. Quant à l’utilisation surf/bureautique/multimédia, je ne vois pas le rapport avec le caractère modulaire ou non du noyau.

Concernant la sécurité, par exemple un module du noyau est un vecteur de choix pour installer un rootkit. D’où l’intérêt de désactiver le support des modules. A ma connaissance il n’y a pas de différence de performance significative entre une fonction en dur et une fonction en module, les deux s’exécutent en espace noyau.

Je place ce fil, provisoirement en post-it car il me semble éminemment instructif, particulièrement les explications de Pascal.
Par la suite, il faudra en tirer l’essence et placer le résultat bien en vue. :023

À noter cependant qu’il existe des périphériques ne fonctionnant pas si le driver est compilé en dur, par exemple la gestion des speedtouch, la gestion de certains périphériques USB, etc. Dans ce cas l’activation des modules est indispensable.
Pour l’aspect sécurité, si un rootkit peut être installé sur les modules, beaucoup de rootkit modifient le noyau en RAM (pour cacher des arborescences ou des processus essentiellement).
La parade simple à une modification des modules consiste à avoir le noyau et le boot sur un système de fichiers en lecture seule (ça peut être un CDROM).

Qu’est-ce qui coince ?

Les modules sont dans /lib/modules donc sur la racine qui est généralement modifiable (à cause de /etc), pas dans /boot.

Qu’est-ce qui coince ?
[/quote]
Le speedtouch qui s’initalise mal et qui du coup ne fonctionnait pas, je n’ai jamais réussi à comprendre pourquoi(note que ça date), il était impératif que toute la chaine USB soit en modules. Dans le même genre, unionfs par exemple fonctionnait très mal en module sur le 2.6.26 et le 2.6.31, j’ai du me taper de le mettre en module pour clefagreg, va savoir pourquoi.
Sinon sur les 2.4, l’USB ne fonctionnait tout simplement pas si uhci-usb ou ohci-usb était mis en dur, les périphériques n’étaient pas détectés (en tout cas sur le 2.4.19 par exemple).

[quote]

Les modules sont dans /lib/modules donc sur la racine qui est généralement modifiable (à cause de /etc), pas dans /boot.[/quote]

Non, pas nécessairement, il te suffit d’avoir un répertoire /lib/modules sur lequel tu montes l’arborescence. Si tu veux bouter ta machine, tu met dans le répertoire d’origine que les modules nécessaires au montage de la racine, puis tu montes /lib/modules par dessus celui qui a servi au boute. Tu peux également mettre les modules nécessaires au boute dans l’initrd. Bref, il n’y a aucune raison que /lib/modules soit en lecture/écriture.

[quote=“fran.b”]
Sinon sur les 2.4, l’USB ne fonctionnait tout simplement pas si uhci-usb ou ohci-usb était mis en dur, les périphériques n’étaient pas détectés (en tout cas sur le 2.4.19 par exemple).[/quote]C’était sous quel Roi de France, ça ? :laughing:

Debian 3.0 (Woody) avait un noyau 2.4.18. Mon premier noyau 2.4, et mon premier contact avec netfilter/iptables (souvenir ému).

J’ai toujours compilé tout ce qui concerne l’USB en module, et n’ai donc jamais rencontré ce genre de problème.

Pas les modules nécessaires au montage de la racine (qui sont déjà dans l’initramfs), puisqu’à ce stade la racine est déjà montée. Plutôt les modules nécessaires avant le montage de /lib/modules. C’est un peu délicat car si ce dernier est monté de façon classique via une entrée dans /etc/fstab le montage a lieu après le démarrage d’udev qui va énumérer le matériel et chercher à charger les modules correspondants. On ne peut pas les mettre dans l’initramfs car à ce stade la racine finale a été montée par dessus.

Entièrement d’accord, mais cela est vrai non seulement pour /lib/modules mais aussi pour tout /lib, /sbin, /bin… en fait grosso modo tout le système de fichiers racine sauf /etc (et encore, pas tout) et /root.

[quote=“PascalHambourg”]Debian 3.0 (Woody) avait un noyau 2.4.18. Mon premier noyau 2.4, et mon premier contact avec netfilter/iptables (souvenir ému).
[/quote]Nostalgie:

bic:/# uname -a Linux bic 2.0.38 #6 sam jui 1 16:42:18 CEST 2000 i486 unknown bic:/# ls -lct /etc | tail -1 | awk '{print $6, $7, $8}' Aug 6 1997 bic:/# dpkg -l libc5 Desired=Unknown/Install/Remove/Purge | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad) ||/ Name Version Description +++-===============-==============-============================================ ii libc5 5.4.38-1.1 The Linux C library version 5 (run-time libr bic:/# ls -l /boot/vmlinuz-2.0.38 -rw-rw-r-- 1 boisson boisson 446895 Feb 17 2000 /boot/vmlinuz-2.0.38 (la machine tourne toujours (486SX25 à 25MHz). Note qu’il n’y a pas de module sur ce noyau.
J’en déduis que tu n’as pas connu ipfwadm et ipportfw ni ipchains…

[quote]
J’ai toujours compilé tout ce qui concerne l’USB en module, et n’ai donc jamais rencontré ce genre de problème.

[quote=“fran.b”]
Tu peux les charger par anticipation
[/quote] C’est un peu délicat car si ce dernier est monté de façon classique via une entrée dans /etc/fstab le montage a lieu après le démarrage d’udev qui va énumérer le matériel et chercher à charger les modules correspondants. On ne peut pas les mettre dans l’initramfs car à ce stade la racine finale a été montée par dessus.[/quote]
C’est vrai qu’il faut tripatouiller le démarrage. Le mieux est de considérer que ça rentre dans la construction de la racine et d’intégrer ça dans l’initrd.

[quote]

Entièrement d’accord, mais cela est vrai non seulement pour /lib/modules mais aussi pour tout /lib, /sbin, /bin… en fait grosso modo tout le système de fichiers racine sauf /etc (et encore, pas tout) et /root.[/quote]
Il est amusant de voir aufs pour ça, ça te montre quels sont les répertoires où il y a une écriture nécessaire. Essentiellement /var/run, /var/tmp, /var/lib, /tmp et quelques rares fichiersou répertoires de /etc (/etc/mtab, /etc/dhcpc (pendant un temps, je crois que c’est inutile maintenant), /etc/cups (ce qui m’énerve)

J’ai écrit que c’était mon premier noyau 2.4, pas mon premier noyau Linux. J’ai commencé avec le noyau 2.2.19 qui était dans Coyote Linux (ma première distribution, sur une disquette pour faire une passerelle) et Debian 2.2 (Potato) qui fut donc ma première Debian un peu plus tard. J’ai bien connu ipchains, et j’ai donc été conscient de l’amélioration apportée par iptables et l’infrastructure netfilter. C’est aussi le premier noyau que j’ai compilé, je ne me souviens plus bien pour quelle raison, peut-être pour activer une option qui était désactivée dans le noyau précompilé. Pour le noyau 2.4 en revanche je me souviens : c’était pour le patch-o-matic de netfilter.

Il y a aussi /etc/network/run/ifstate, mais on peut le faire pointer vers un emplacement en lecture/écriture avec un lien symbolique. En fait quand j’écris “tout le système racine sauf /etc/ et /root”, je pense aux répertoires qui sont traditionnellement laissés sur le même système de fichiers que la racine, donc pas /var ni /tmp sur lesquels il est courant de monter des systèmes de fichiers distincts.

PS : tu ne te serais pas un peu emmêlé avec les balises de citation ?

Oups, rectifié.

Quid de la phrase “Tu peux les charger par anticipation” marquée comme citation mais que je ne retrouve pas dans les messages antérieurs - et dont je n’ai pas compris le sens par ailleurs ?

Hum, je croyais que je l’avais dit avant, tant pis je laisse le truc en citation.

Tu peux charger les modules nécessaires au moment de l’initrd. En fait l’initrd lance un udev qui (je crois) met les évènements qu’il ne peut initier correctement dans une files d’attente (/dev/.udev/queue), rien n’empêche d’initialiser tous les périphériques à ce moment là (il suffit de rajouter les règles complètes et les modules nécessaires). Tu peux aussi te passer d’udev et tout initialiser à la main. Mais cela demande de tripatouiller l’initrd ce qui n’est pas très dur.