Accueil > Linux & Logiciels Libres > Recompilation automatique d’un pilote après mise à jour du noyau (...)
277 visites

Recompilation automatique d’un pilote après mise à jour du noyau Linux

vendredi 1er mai 2015

Version imprimable de cet article Version imprimable

Certaines distributions Linux, ou certaines versions de ces distributions, ne disposent pas toujours pour certains matériels de pilotes pré-compilés en paquets rpm/apt (RedHat/Debian) que l’on peut installer simplement.

Il faut alors récupérer le pilote dans une archive, à décompresser et à compiler.
Dans le cas des cartes graphiques Nvidia, il s’agit d’un blob, un script contenant un logiciel.

Dans le monde des logiciels libres, le BLOB est un terme péjoratif pour désigner l’inclusion d’un pilote sous forme de fichier objet dans le noyau libre d’un système d’exploitation afin de ne pas divulguer le code source du programme. On retrouve ces blobs dans les systèmes NetBSD, FreeBSD, DragonFly BSD et la plupart des distributions GNU/Linux.
Source : Wikipedia

Dès lors, il faut, après chaque mise à jour du noyau Linux, le kernel, recompiler le module noyau correspondant au pilote ou ré-exécuter le script d’installation du pilote, dans le cas par exemple du pilote Nvidia.

Il est ici question du pilote Nvidia, mais le même type de procédure peut être utilisé pour d’autres modules, comme par exemple bbswitch.

Pour simplifier la procédure, il est possible de l’automatiser en la déclarant comme un "service" Linux, qui sera lancé au démarrage, et plus précisément dès le niveau d’exécution 2 ou 3, c’est à dire avant le lancement de l’interface graphique (niveau 5).

Le module étant bêtement copié à partir du répertoire des modules de l’ancien kernel, il faudra d’abord l’effacer dans le répertoire du nouveau kernel pour que l’installation automatique puisse s’effectuer au prochain démarrage.

nvidialibpath=$(find /usr/lib/modules/ -maxdepth 1 -mmin -10 | tail -n 1); # modifié il y a moins de 10 minutes = /usr/lib/modules + le sous dossier du nouveau kernel
est_present=$(find $nvidialibpath -iname "nvidia.ko"  | grep -i "nvidia.ko" | wc -l);
if [ $est_present -gt 0 ]
then
       echo "Le module nvidia.ko a été bêtement copié dans $nvidialibpath, on le nettoie pour que l'installation automatique puisse se faire au prochain démarrage";
       find $nvidialibpath -iname "nvidia.ko" -exec rm -f {} \; # au pire, le script d'installation automatique peut le recréer
fi

Ce petit script, à lancer juste après une mise à jour du kernel, recherche les éléments modifiés il y a moins de 10 minutes dans le dossier /usr/lib/modules, sans aller dans les sous-répertoires.
Le répertoire du nouveau kernel sera renvoyé, mais le répertoire des modules aussi, on ne prend donc que la dernière ligne avec le tail -n 1
Puis on utilise le même code que celui expliqué plus bas pour chercher le module et vérifier son existence.
Auquel cas on efface le module nvidia.ko bêtement copié dans le répertoire des modules du nouveau kernel afin que le service d’installation/recompilation automatique du module nvidia puisse s’exécuter.

Le "service" est déclaré dans un fichier de /etc/init.d

#!/bin/bash Ce fichier commence, comme tous les scripts, par faire référence à son environnement de commande.
# chkconfig: 23 99 10 On indique à chkconfig que ce service sera à démarrer aux niveaux 2 et 3, avec une priorité de démarrage de 99 (après tout le reste donc), et une priorité d’arrêt de 10 (sans importance, pas d’action d’arrêt pour ce service).

Les informations pour chkconfig sont documentées dans le man de la commande

On indique ensuite quelques informations

# description: Recompile le pilote nvidia pour le noyau en cours si besoin
#
### BEGIN INIT INFO
# Provides: install_nvidia
# Default-Start: 2 3
# Default-Stop: 0 6
# Description: Recompile le pilote nvidia pour le noyau en cours si besoin
### END INIT INFO

Puis on initialise le script en lui même, en récupérant la version du noyau en cours, le chemin dans lequel est par conséquent sensé se trouver le module Nvidia pour la version du noyau Linux, avant de compter le nombre de modules présents.

rc=0;
nvidia_installer="NVIDIA-Linux-x86_64-375.20.run";
kernelver=$(uname -a | awk '{ print $3 }');
nvidialibpath="/usr/lib/modules/$kernelver";
est_present=$(find $nvidialibpath -iname nvidia.ko  | grep -i nvidia.ko | wc -l);
logfile="/var/log/install_nvidia.log";

Comme tout service, on déclare une action "start", stop et status", à minima.

case "$1" in
 start)

L’action "start" consistera à vérifier si le module est présent, et si non, lancer la ré-exécution du blob Nvidia.
Les sorties sont redirigées vers le fichier journal de l’installeur Nvidia.

Le blob Nvidia (ici NVIDIA-Linux-x86_64-346.35.run, déposé dans /usr/local/src) accepte un certain nombre d’options, dont :

  • -a accepte automatiquement la licence.
  • -s lancement silencieux, sans question ni affichage, on suppose que toutes les réponses sont "oui" aux questions posées
    • compiler les librairies 32 bits en plus de 64
    • éditer le fichier de configuration de l’interface graphique avec nvidia-xconfig
  • -X lancer nvidia-xconfig à la fin de l’installation afin de configurer le fichier de configuration de l’interface graphique
  • -h, --help, -A pour afficher les différentes options, dont les options avancées.
  • --update se connecte automatiquement au serveur FTP de Nvidia et détermine puis télécharge et installe la dernière version du pilote.

Le fichier exécutable doit avoir un certain nombre de droits et éventuellement le bon contexte SeLinux :

ls -Z /usr/local/src/NVIDIA-Linux-x86_64-346.35.run
-rwxr--r--. root root unconfined_u:object_r:usr_t:s0   /usr/local/src/NVIDIA-Linux-x86_64-346.35.run

retour au script du service :

        echo "================================================================" >> $logfile;
        echo "Lancement du script d'installation (ou pas) de NVidia le $(date)" >> $logfile;
        echo "Le noyau Linux installé est $kernelver" >> $logfile;
        echo "on cherche le module nvidia.ko dans $nvidialibpath" >> $logfile;
        if [ $est_present -gt 0 ]
        then
                echo "Le module nvidia est présent dans $nvidialibpath" >> $logfile;
        else
                echo "Le module nvidia est absent, on le recompile" >> $logfile;
                #/usr/local/src/NVIDIA-Linux-x86_64-346.59.run -a -s -X
                #/usr/local/src/NVIDIA-Linux-x86_64-352.55.run -a -s -X
                echo "On lance /usr/local/src/$nvidia_installer -a -s -X" >> $logfile;
                IGNORE_CC_MISMATCH=1 /usr/local/src/$nvidia_installer -a -s -X 2>&1 >> $logfile
                if [ $? -ne 0 ]
                then
                        echo "On relance /usr/local/src/$nvidia_installer -a -s -X" >> $logfile;
                        IGNORE_CC_MISMATCH=1 /usr/local/src/$nvidia_installer -a -s -X 2>&1 >> $logfile
                fi
                if [ $? -eq 0 ]
               then
                        echo "Tout s'est bien passé" >> $logfile;
                        echo "Mise à jour du paquet kmod-nvidia" >> $logfile;
                        dnf update kmod-nvidia* -y 2>&1 1>>$logfile
                else
                        echo "La mise à jour du pilote NVidia s'est mal passée" >> $logfile;
                fi
        fi
        rc=$?
 ;;

Ce service n’a pas d’action particulière pour son arrêt.

stop)
               echo "Rien à faire, ce service est un lancement ponctuel au démarrage et non un démon.";
 ;;

L’action status se content d’indiquer si le module Nvidia est présent ou non.

status)
       echo "Le noyau Linux installé est $kernelver";
       echo "on cherche le module nvidia.ko dans $nvidialibpath";
       if [ $est_present -gt 0 ]
       then
               echo "Le module nvidia est présent dans $nvidialibpath";
       else
               echo "Le module nvidia est absent de $nvidialibpath";
       fi
 ;;
esac
exit $rc

Il faudra ensuite donner à ce script les droits d’exécution, ainsi que le propriétaire/groupe et éventuellement le contexte SeLinux
-rwxr-xr-x. root root unconfined_u:object_r:etc_t:s0   /etc/init.d/install_nvidia

Et enfin, on passera par systemctl pour activer le service, systemctl redirigera alors vers l’ancien "protocole" avec chkconfig.
systemctl enable install_nvidia

Un systemctl status permettra de voir si tout est bien paramétré.

systemctl status install_nvidia
install_nvidia.service - LSB: Recompile le pilote nvidia pour le noyau en cours si besoin
  Loaded: loaded (/etc/rc.d/init.d/install_nvidia)
  Active: active (exited) since ven. 2015-05-01 11:40:29 CEST; 1h 58min ago
 Process: 1718 ExecStart=/etc/rc.d/init.d/install_nvidia start (code=exited, status=0/SUCCESS)

Un coup d’œil à la fin du fichier journal permettra de s’assurer que tout s’est bien passé.
On aurait pu ajouter au début du script un vidage ou une rotation de fichier journal afin de limiter sa taille.

Et la commande service - status

service install_nvidia status
Le noyau Linux installé est 3.19.5-100.fc20.x86_64
on cherche le module nvidia.ko dans /usr/lib/modules/3.19.5-100.fc20.x86_64
Le module nvidia est présent dans /usr/lib/modules/3.19.5-100.fc20.x86_64

Répondre à cet article

Total 114990 visites depuis 2030 jours | Site réalisé par Vader[FR] | SPIP | | Plan du site | Suivre la vie du site RSS 2.0 | contact mail