Les fichiers de sortie des noyaux 2.6 Peter Johanson Benny Chuang Olivier Fisette Ce guide est destiné aux développeurs et couvre en détails les récents changements relatifs aux fichiers de sortie des noyaux dans Gentoo. 1.2 26 mars 2004 Préface
Le nouveau système

Parmi la myriade d'améliorations apportées au noyau Linux dans la série 2.6, une nouvelle infrastructure nommée « kbuild » a été développée afin de fournir un système de compilation hautement configurable et versatile. La portée de ce changement ne sera pas étudiée dans le présent document ; nous nous intéresserons plutôt à la nouvelle méthode recommandée pour la compilation de modules externes contre l'arbre des sources d'un noyau 2.6. Voici une traduction libre d'un extrait de Documentation/kbuild/modules.txt :

Compiler des modules hors du noyau officiel
-------------------------------------------
Des modules sont fréquemment développés hors du noyau officiel. Afin d'être à
jour relativement aux changements apportés au système de compilation, la manière
la plus transposable d'un système à un autre pour compiler un module hors du
noyau est d'utiliser la commande suivante :

make -C chemin/vers/noyau/src SUBDIRS=$PWD modules

En écrasant la variable SUBDIRS, la plus récente architecture kbuild permet de compiler aisément des modules externes. En soit, il s'agit d'une amélioration énorme, mais les choses deviennent problématiques lorsque l'on s'attarde aux détails du procédé.

Le problème

Ayant configuré et compilé un noyau de la série 2.6 dont les sources résident dans /usr/src/linux, il n'est pas déraisonnable de supposer que je veuille ensuite compiler quelques modules externes contre l'arbre de ce noyau. De plus, on peut raisonnablement s'attendre à ce que cela puisse être fait par un utilisateur non-privilégié. Pourtant, ceux qui ont essayé savent que ce n'est pas le cas. Une telle tentative se solde par un échec car make tente de mettre à jour des fichiers dans /usr/src/linux alors que les utilisateurs non-privilégiés n'ont pas accès à cet emplacement en mode écriture.

Les modules compilés par le système Portage ont exactement le même problème : lorsqu'une mise à jour est lancée, elle échoue à cause de violations de l'environnement bac à sable. Le système kbuild a complexifié la compilation de modules de telle manière qu'il est difficile d'utiliser le principe sécuritaire des privilèges minimum.

Une recherche sur le système Bugzilla de Gentoo montre que beaucoup de bogues causés par ce problème ont été rapportés. Aussi, beaucoup d'articles présentant la désactivation du bac à sable comme seule solution ont été postés dans les forums. Considérant l'état des choses à ce moment, il semblait en effet inévitable d'avoir à écrire ou à mettre à jour des fichiers dans /usr/src/linux lors de la compilation de modules des noyaux 2.6.

Lutter contre le système

Plusieurs façons de « hacker » le système kbuild afin de le contourner ont été proposées, dont une suggérant de lier symboliquement les éléments de /usr/src/linux dans un répertoire temporaire. Ultimement, toutes les solutions menaient à des problèmes de sécurité, car /usr/src/linux devait être touché d'une façon ou d'une autre. Toutefois, priver les utilisateurs d'un chemin permettant une mise à jour relativement facile n'est pas une option acceptable. C'est pourquoi le nouveau kmod.eclass peut conférer à Portage l'accès en mode écriture à /usr/src/linux pour les noyaux 2.6 plus anciens.

Comme il s'agit d'un risque de sécurité majeur, les utilisateurs sont forcés d'accepter cette option lors de sa première utilisation, par le bias d'un nouvel outil : config-kernel. Les utilisateurs peuvent exécuter config-kernel une fois pour accepter l'option, puis ils ne recevront qu'un avertissement chaque fois que Portage compilera un module du noyau en utilisant cette fonctionnalité.

# config-kernel --allow-writable yes
Accepter le changement

Une solution plus appropriée a vu le jour lorsqu'il est devenu évident que lutter contre les nouvelles fonctionnalités de kbuild ne causerait que des problèmes de plus en plus nombreux dans le futur. En fait, la solution réside dans la nouvelle capacité de kbuild d'envoyer tous ses fichiers de sortie dans un répertoire séparé. Garder l'arbre des sources complètement propre et permettre aux modules externes de compiler contre des sources propres tout en envoyant leurs fichiers de sortie dans un répertoire temporaire est la clé.

Les détails des interactions de tous ces éléments sont plutôt complexes. La section suivante essaie de faciliter l'assimilation de ces concepts en les décomposant en morceaux plus simples.

Les fichiers de sortie du noyau
Les variables KBUILD_OUTPUT et O

kbuild fournit deux variables dictant où le noyau devrait placer ses fichiers de sortie.

KBUILD_OUTPUT Cette variable peut être définie dans le Makefile de plus haut niveau du noyau si vous voulez spécifier un répertoire de sortie par défaut différent de l'arbre des sources lui-même. O Cette variable devrait être utilisée sur la ligne de commande pour écraser tout autre paramètre et indiquer où les fichiers de sortie produits par la commande actuelle devraient être placés.
Variable Utilisation

La combinaison de ces deux variables est la clé pour une utilisation adéquate de kbuild et Portage pour installer des modules du noyau.

Changements relatifs à l'installation des noyaux

Pour utiliser les fonctionnalités de redirection de la sortie du noyau, le nouveau kernel-2.eclass, écrit par John Mylchreest a été corrigé pour ajouter un chemin par défaut KBUILD_OUTPUT dans le makefile de plus haut niveau du noyau (/usr/src/linux/Makefile). Par défaut, ce chemin a la valeur /var/tmp/kernel-output/${KV} puisque /var/tmp est un emplacement approprié pour les fichiers temporaires qui doivent être préservés lors des redémarrages.

Une fois que cette variable est paramétrée, toutes les commandes make exécutées dans l'arbre des sources du noyau envoyent leurs fichiers de sortie dans ce nouveau répertoire. Rien de plus n'est nécessaire de la part de l'utilisateur et le changement est essentiellement (voyez la section suivante pour les exceptions) transparent. Une fois un noyau installé, l'utilisateur n'a qu'à faire :

# make menuconfig

et ils pourront configurer leur noyau puis le compiler.

Changements importants concernant les emplacements des fichiers

Comme tous les fichiers générés sont maintenant placés dans un répertoire séparé, quelques fichiers clés aboutiront dans un endroit inattendu pour l'usager. Plus particulièrement, les .config et bzImage de l'utilisateur ne seront plus dans /usr/src/linux comme ils l'étaient auparavant. Peter Johanson a écrit un nouveau guide du noyau 2.6 disponible ici et destiné aux utilisateurs finaux. Il souligne les changements apportés à kbuild et, en particulier, les nouveaux emplacements de ces fichiers.

Ebuilds pour les modules externes
Approche générale

Maintenant que les noyaux génèrent leurs fichiers dans un emplacement différent, écrire des ebuilds adhérant à ce nouveau système est l'étape suivante. Mettre à jour les ebuilds pour qu'ils vérifient la présence de certains fichiers et en-têtes dans l'emplacement approprié et pour qu'ils utilisent la magie Makefile appropriée est le secret.

L'idée générale est de corriger les Makefiles des paquets pour qu'ils utilisent, lors de la compilation contre des noyaux 2.6, la variable O afin de générer leurs fichiers dans un répertoire temporaire à l'intérieur de l'environnement bac à sable. Il ne reste qu'à ajouter quelques pièces pour faire fonctionner le tout et obtenir un nouveau paquet pour un module externe qui s'intégrera avec succès.

L'obtention d'un module utilisable et fonctionnel après la compilation et l'installation n'est pas abordée dans ce document. Il s'agit d'un problème totalement différent que les auteurs du module devraient gérer en amont.

Des changements ont été apportés à kmod.eclass pour inclure quelques variables et outils que les auteurs d'ebuilds peuvent utiliser pour implémenter plus aisément les changements requis dans les ebuilds.

Critères à remplir pour les Makefiles

L'utilisation de koutput oblige les Makefile des paquets de modules du noyau à remplir certains critères. Plus particulièrement, ils devront utiliser la variable kbuild O afin de générer leurs fichiers dans un sous-répertoire donné de WORKDIR. Souvent, cela sera quelque chose de semblable à ${S}/tmp. Lorsque ce système est utilisé, le répertoire de sortie doit compter le .config du noyau parmi ses fichiers. La copie de ce fichier peut être faite à partir du makefile ou du ebuild, mais l'intégrer au makefile de façon appropriée pourrait mener à une correction en amont qui déchargerait les développeurs Gentoo de ce travail.

Fonctionnalités de kmod.eclass

Tous les ebuilds de modules du noyau devraient désormais utiliser kmod.eclass. Voici un aperçu de son utilisation. La fonction kmod_src_unpack() s'occupe du désarchivage, ainsi que du réglage de plusieurs variables extrèmement utiles qui pourront être utilisées par la suite. Deux variables peuvent être paramétrées par le ebuild afin de contrôler les fonctionnalités de kmod_src-unpack().

KMOD_SOURCES Si cette variable est réglée, ces fichiers (habituellement des archives tar) seront désarchivés dans WORKDIR. Autrement, ${A} sera désarchivé. Alternativement, la variable peut être réglée à « none » si un ebuild doit prendre en charge lui-même le désarchivage et autres processus. KMOD_KOUTPUT_PATCH Si KV_OUTPUT a une valeur différente de /usr/src/linux et que la présente variable est réglée, le correctif spécifié sera appliqué, en utilisant epatch dans ${S}. Bien que cela puisse être fait manuellement, la présente variable peut être utile pour ne pas avoir à définir src_unpack() dans un ebuild.
Variable Utilisation

La fonction kmod_src_unpack() s'applique à déterminer comment le pilote à compiler devrait être géré. Elle supporte d'ailleurs très bien les deux méthodes de compilation pour versions 2.6. Si la nouvelle méthode employant koutput est détectée, la fonction appliquera le correctif spécifié par KMOD_KOUTPUT_PATCH si celui-ci existe. Après que kmod_src_unpack() ait été appelée, une pléthore de variables deviennent disponibles et peuvent être utilisées par après dans le ebuild.

KV_OUTPUT Le chemin d'accès absolu utilisé par le noyau pour ses fichiers de sortie. Pour les noyaux 2.4, cela sera toujours /usr/src/linux. Pour les 2.6, cela devrait être un répertoire différent (sinon la compilation du module échouera). KV_OJB L'extension pour les modules du noyau pour cette version du noyau. Cela sera soit « ko », soit « o », dépendamment. KV_VERSION_FULLLa version complète du noyau.KV_MAJORLe numéro de version majeure du noyau.KV_MINORLe numéro de version mineure du noyau.KV_PATCHLe numéro de correction du noyau.KV_TYPELe type du noyau (par exemple : "-gentoo-r1" pour "2.4.23-gentoo-r1")
Variable Signification

La valeur de KV_OUTPUT est le facteur qui, ultimement, détermine quelle configuration de noyau a été détectée et quelle méthode de compilation sera utilisée. Voici un tableau montrant les trois différentes configurations du noyau possibles et la valeur assignée à la variable après l'appel de la fonction kmod_src_unpack().

/usr/src/linux Flexible. Certains makefiles utiliseront des instructions manuelles, d'autres emploieront make -C $(KV_BUILD). Les deux techniques sont faciles à utiliser avec les noyaux 2.4. /usr/src/linux Il s'agit de la méthode traditionnelle. kmod.eclass gère cette situation en utilisant config-kernel pour vérifier si la permission d'écrire dans /usr/src/linux a été accordée, puis procède à l'écriture si demandé. Cette méthode sera employée tant que la nouvelle méthode de compilation ne sera pas adoptée par tous. /un/autre/chemin La compilation avec cette configuration nécessite l'utilisation de la méthode « koutput ». Habituellement, des corrections sont requises pour les makefiles, et les variables « sources » et « output » seront alors réglées. Les modules compilent alors en utilisant les makefiles du noyau, mais leurs fichiers de sortie sont placés dans un sous-répertoire local.
KV_OUTPUT Approche pour compiler les modules
Noyau 2.4
Noyau 2.6, sortie normale
Noyau 2.6, sortie alternative

Une fonction assistante est fournie par kmod.eclass pour déterminer facilement quelle configuration est utilisée. is_koutput() permet à ebuild de déterminer comment procéder à la compilation. Un ebuild typique pourrait utiliser le test suivant :

	if is_koutput
	then
		# Utiliser sed pour corriger certaines choses pour l'utilisation de koutput.
		sed -i "s:foo:bar:" Makefile
	fi

La plupart des ebuilds nécessiteront un correctif pour les makefiles pour activer la sortie vers un répertoire différent, puis l'utilisation de sed si is_koutput() retourne la valeur « true ». L'ebuild donné comme exemple ci-dessous montre comment cela est géré. Pour les ebuilds nécessitant plus de travail (nvidia-kernel est l'un d'eux), il y a quelques fonctions qui peuvent être appelées pour exercer un contrôle plus fin.

kmod_make_linux_writable() Cette fonction sert à permettre l'écriture dans /usr/src/linux. Elle devrait être appelée préférentiellement à l'utilisation directe de addwrite, car elle réalisera les vérifications nécessaires afin d'être sûr que cela est nécessaire et que l'utilisateur l'a explicitement permis avec config-kernel. kmod_do_buildpatches() Cette fonction peut être appelée pour appliquer le correctif de KMOD_KOUTPUT_PATCH lorsque nécessaire. Habituellement, elle ne sera utilisée que si un ebuild est forcé de désarchiver les sources du module manuellement. is_kernel() Cette fonction requiert deux arguments, un numéro de version majeure du noyau, et un numéro de version mineure. C'est la façon recommandée de vérifier si l'on utilise une certaine version du noyau.
Fonction Utilisation

En plus de ces fonctions spéciales, kmod.eclass exporte src_unpack, src_compile, etc., qui peuvent être référencées par kmod_src_unpack, kmod_src_compile, etc.

Exemple de modification d'un ebuild et d'un Makefile

Ce qui suit est un exemple pratique détaillant comment le paquet hostap-driver a été modifié pour créer un ebuild tout à fait fonctionnel et compatible avec les noyaux des séries 2.4 et 2.6. Il utilise un correctif (assez général pour être utilisé en amont et permettre la simplification des futurs ebuilds) pour le Makefile de plus haut niveau, ainsi que quelques changements du ebuild pour prendre en compte les différences dans les emplacements de certains fichiers.

Vous trouverez ci-dessous des extraits du Makefile original, du Makefile modifié et des sections modifiées qui permettent une compilation correcte. D'abord, une ligne doit être corrigée car elle assume que .config sera dans le même répertoire que les sources du noyau.

La variable KERNEL_OUTPUT_PATH est ajoutée plus tôt dans le ebuild pour complémenter la variable KERNEL_PATH dans l'original.
include $(KERNEL_PATH)/.config

La version corrigée ci-dessous permet à la variable KERNEL_OUTPUT_PATH d'être réglée si elle ne l'est pas déjà (pour la compatibilité descendante avec 2.4) et cherche pour le fichier .config dans cet emplacement.

ifndef KERNEL_OUTPUT_PATH
KERNEL_OUTPUT_PATH=$(KERNEL_PATH)
endif

include $(KERNEL_OUTPUT_PATH)/.config

Comme nous avons maintenant la variable KERNEL_OUTPUT_PATH à notre disposition, corriger la déclaration de variable suivante impliquant le version.h généré est simple. L'original :

VERFILE := $(KERNEL_PATH)/include/linux/version.h

Et la version éditée et corrigée :

VERFILE := $(KERNEL_OUTPUT_PATH)/include/linux/version.h

Finalement, notre correctif remplace la ligne qui invoque le système kbuild 2.6 afin d'incorporer l'utilisation de la variable O, paramétrant le système pour produire les fichiers dans le sous-répertoire tmp/ du répertoire courant.

kbuild s'attend à trouver un fichier .config valide dans le répertoire de sortie spécifié par O=foo. Le ebuild ou le makefile devrait être édité pour copier .config dans ${KV_OUTPUT} (variable paramétrée par kmod.eclass).

Voici l'original :

$(MAKE) -C $(KERNEL_PATH) SUBDIRS=$(PWD)/driver/modules \
	MODVERDIR=$(PWD)/driver/modules modules

Et voici la version éditée :

mkdir -p $(PWD)/tmp
-cp $(KERNEL_OUTPUT_PATH)/.config $(PWD)/tmp
$(MAKE) -C $(KERNEL_PATH) O=$(PWD)/tmp \
	SUBDIRS=$(PWD)/driver/modules \
	MODVERDIR=$(PWD)/driver/modules  modules

Les changements apportés au ebuild sont relativement simples. La eclass kmod rend d'ailleurs les choses très faciles. Voici quelques extraits de src_unpack et quelques variables paramétrées dans le ebuild :

KMOD_SOURCES="${P}.tar.gz"
KMOD_KOUTPUT_PATCH="${PN}-koutput.diff.gz"

src_unpack() {
    # Désarchive et paramètre quelques variables.
    kmod_src_unpack
	
    ## Désarchive les sources pcmcia-cs si nécessaire.
    pcmcia_src_unpack

    epatch "${FILESDIR}/${P}.firmware.diff.bz2"
    
    # Si koutput est utilisé, employer sed pour ajouter le chemin approprié.
    if is_koutput
    then
        sed -i -e \
	    "s:^# KERNEL_OUTPUT_PATH=.*:KERNEL_OUTPUT_PATH=${KV_OUTPUT}:" \
	    ${S}/Makefile
    fi
}

Remarquez l'utilisation des deux variables, KMOD_SOURCES et KMOD_KOUTPUT_PATCH. Ces dernières peuvent être réglées selon les besoins pour spécifier quelles sources doivent être désarchivées par kmod_src_unpack() et quel fichier de correctif employer si koutput est utilisé. KMOD_KOUTPUT_PATCH ne sera pas appliqué si le processus détecte que le noyau 2.6 est paramétré pour utiliser /usr/src/linux comme répertoire de sortie. Voici une version écourtée de la fonction src_compile() :

src_compile() {
    # Configurer les sources pcmcia-cs tel que nécessaire.
    pcmcia_configure

    einfo "Building hostap-driver for kernel version: ${KV}"
    case ${KV_MINOR} in
        [34])
            local mydrivers

            use pcmcia && mydrivers="${mydrivers} pccard"
            use hostap-nopci || mydrivers="${mydrivers} pci"
            use hostap-noplx || mydrivers="${mydrivers} plx"

            einfo "Building the following drivers: ${mydrivers}"
            emake ${mydrivers} || die "make failed"
            ;;
        [56])
            unset ARCH
            emake all || die "make failed"
            ;;
        *)
            eerror "Unsupported kernel version: ${KV}"
	    die
	    ;;
    esac
}
Pour les noyaux 2.6, la variable ARCH doit ne pas être réglée. Les makefiles du nouveau noyau utilisent ARCH pour déterminer quoi compiler et utilisent une syntaxe différente pour i386, etc.

La fonction src_install() de cet ebuild ne sera pas montrée ici, car elle ne fait essentiellement qu'installer tous les modules dans /lib/modules/${KV}/. Notez que les changements d'extension de .o à .ko pour les noyaux 2.6 sont pris en charge. kmod.eclass règle la variable KV_OBJ soit à o, soit à ko, tel qu'approprié, afin de simplifier les choses pour vous.