3. Signaler une anomalie

Contenu de cette section

Soumis à des contraintes de place, les développeurs des parties SCSI de Linux ne maintiennent pas obligatoirement les vieilles versions du code. Si vous ne tournez pas avec la dernière version du noyau (la plupart des distributions de Linux, (MCC, SLS, Yggdrasil, etc.) peuvent avoir jusqu'à une vingtaine de patches de retard sur le dernier noyau), il y a une forte probabilité pour que vous ne soyez pas capable de résoudre votre problème. Avant de signaler une anomalie, vérifiez si elle existe encore avec la toute dernière version du noyau.

Si après avoir mis à jour votre noyau et lu entièrement ce document, vous pensez vraiment avoir découvert un problème, envoyez par email un rapport d'anomalie à la liste de diffusion SCSI, où il aura des chances d'être lu par la plupart des personnes ayant participé au développement des pilotes SCSI pour Linux.

Mettez dans votre rapport d'anomalie le maximum d'information sur votre configuration matérielle, le texte exact des messages que Linux affiche au démarrage, le moment où l'erreur se produit et à quel endroit dans les sources l'erreur a été levée. Référez-vous aux chapitres Capture des messages SCSI et Localisation de l'origine d'un panic() .

Des informations incomplètes peuvent conduire à de mauvais diagnostics ou à un classement vertical de la part du développeur du pilote, qui risque d'estimer qu'il a plus important à corriger.

Retenez bien ceci : si nous ne pouvons pas reproduire le problème et si vous ne pouvez pas nous dire ce qui ne marche pas, l'anomalie ne sera jamais corrigée.

3.1 Capture des messages SCSI

Si aucun archiveur (logger) de messages ne tourne, il va falloir en lancer un. Vérifiez que le système de fichiers /proc est monté :

grep proc /etc/mtab

S'il ne l'est pas, il faut le monter :

mkdir /proc
chmod 755 /proc
mount -t proc /proc /proc

Recopiez ensuite la version du noyau et ses messages dans un fichier de log :

cat /proc/version > /tmp/log
cat /proc/kmsg >> /tmp/log

Attendez une seconde ou deux (le temps que le cat /proc/kmsg se termine) puis tapez CTRL-C.

Si un logger de messages tourne, vous allez devoir chercher dans le fichier de traces adéquat (jetez un oeil à /etc/syslog.conf pour trouver où se cache ce fichier). Vous pouvez aussi taper la commande dmesg.

Si Linux n'est pas lancé, formatez une disquette sous DOS. Si votre distribution monte la disquette en tant que racine (root) plutôt qu'un disque RAM, vous allez devoir formater une disquette et la mettre dans le lecteur non utilisé par la racine (si vous disposez de deux lecteurs). Si vous n'avez pas de second lecteur, il vous faudra utiliser l'option de démarrage 'ramdisk'.

Maintenant, démarrez depuis la disquette de boot de votre distribution, de préférence en mode utilisateur simple (single user) et en demandant à placer la racine (root) dans un disque RAM.

mkdir /tmp/dos

Insérez la disquette dans un lecteur non utilisé pour monter la racine et montez-la :

mount -t msdos /dev/fd0 /tmp/dos

ou

mount -t msdos /dev/fd1 /tmp/dos

Copiez-y ensuite votre fichier de traces :

cp /tmp/log /tmp/dos/log

Démontez votre disquette DOS

umount /tmp/dos

et arrêtez Linux.

shutdown

Redémarrez sous DOS puis incluez le fichier de traces dans votre mail.

3.2 Localisation de l'origine d'un panic()

Ainsi que d'autres Unix le font, Linux appelle la fonction du noyau panic() lorsqu'une erreur fatale est détectée. Par contre, contrairement à d'autres Unix, Linux ne produit pas un fichier de dump dans la swap. Il ne redémarre pas non plus. Il laisse dans le fichier de traces des informations intéressantes. Par exemple :

Unable to handle kernel NULL pointer dereference at virtual address c0000004
current->tss,cr3 = 00101000, %cr3 = 00101000
*pde = 00102027
*pte = 00000027
Oops: 0000
EIP:    0010:0019c905
EFLAGS: 00010002
eax: 0000000a   ebx: 001cd0e8   ecx: 00000006   edx: 000003d5
esi: 001cd0a8   edi: 00000000   ebp: 00000000   esp: 001a18c0
ds: 0018   es: 0018   fs: 002b   gs: 002b   ss: 0018
Process swapper (pid: 0, process nr: 0, stackpage=001a09c8)
Stack: 0019c5c6 00000000 0019c5b2 00000000 0019c5a5 001cd0a8 00000002 00000000
       001cd0e8 001cd0a8 00000000 001cdb38 001cdb00 00000000 001ce284 0019d001
       001cd004 0000e800 fbfff000 0019d051 001cd0a8 00000000 001a29f4 00800000
Call Trace: 0019c5c6 0019c5b2 0018c5a5 0019d001 0019d051 00111508 00111502
            0011e800 0011154d 00110f63 0010e2b3 0010ef55 0010ddb7
Code: 8b 57 04 52 68 d2 c5 19 00 e8 cd a0 f7 ff 83 c4 20 8b 4f 04
Aiee, killing interrupt handler
kfree of non-kmalloced memory: 001a29c0, next= 00000000, order=0
task[0] (swapper) killed: unable to recover
Kernel panic: Trying to free up swapper memory space
In swapper task - not syncing

Prenez la valeur hexadécimale du registre EIP (le compteur de programme ; ici, en l'occurence, 19c905). Cherchez ensuite dans le fichier /usr/src/linux/zSystem.map (ou le fichier System.map correspondant au noyau que vous êtes en train d'exécuter) la plus grande valeur inférieure à la valeur du registre EIP. Par exemple,

0019a000 T _fix_pointers
0019c700 t _intr_scsi
0019d000 t _NCR53c7x0_intr

indique dans quelle fonction l'erreur fatale s'est produite. Recompilez ce fichier en ayant autorisé les options de debug (vous pouvez aussi les autoriser à un niveau plus global en éditant le fichier /usr/src/linux/Makefile et en ajoutant l'option "-g" à la variable CFLAGS).

#
# standard CFLAGS
#

Par exemple :

CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe

devient

CFLAGS = -g -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe

Regénérez le noyau, incrémentalement ou en tapant

make clean
make

Rendez le noyau démarrable (bootable) en créant une entrée dans le fichier /etc/lilo.conf :

image = /usr/src/linux/zImage
label = experimental

N'oubliez pas de relancer LILO en tant que root (/sbin/lilo). Vous pouvez aussi créer une disquette de démarrage :

make zImage

Redémarrez et notez le nouvel EIP pour l'erreur.

Si vous avez installé script, lancez-le ; il va tracer toute votre session dans un fichier.

Maintenant, lancez

gdb /usr/src/linux/tools/zSystem

et tapez

info line *<votre EIP>

Par exemple,

info line *0x19c905

GDB devrait répondre quelque chose du genre

(gdb) info line *0x19c905
Line 2855 of "53c7,8xx.c" starts at address 0x19c905 <intr_scsi+641&>
   and ends at 0x19c913 <intr_scsi+655>.

Mémorisez cette information. Entrez ensuite

list <numero de ligne>

Par exemple,

(gdb) list 2855
2850    /*      printk("scsi%d : target %d lun %d unexpected disconnect\n",
2851                host->host_no, cmd->cmd->target, cmd->cmd->lun); */
2852            printk("host : 0x%x\n", (unsigned) host);
2853            printk("host->host_no : %d\n", host->host_no);
2854            printk("cmd : 0x%x\n", (unsigned) cmd);
2855            printk("cmd->cmd : 0x%x\n", (unsigned) cmd->cmd);
2856            printk("cmd->cmd->target : %d\n", cmd->cmd->target);
2857            if (cmd) {;
2858                abnormal_finished(cmd, DID_ERROR << 16);
2859            }
2860            hostdata->dsp = hostdata->script + hostdata->E_schedule /
2861                sizeof(long);
2862            hostdata->dsp_changed = 1;
2863        /* SCSI PARITY error */
2864        }
2865
2866        if (sstat0_sist0 & SSTAT0_PAR) {
2867            fatal = 1;
2868            if (cmd && cmd->cmd) {
2869                printk("scsi%d : target %d lun %d parity error.\n",

quit vous permet de sortir de GDB.

Sauvegardez également cette information, car elle permettra de fournir le contexte dans lequel l'erreur s'est produite, pour le cas où les développeurs n'auraient pas exactement la même arborescence.


Chapitre suivant, Chapitre Précédent

Table des matières de ce chapitre, Table des matières générale

Début du document, Début de ce chapitre