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.
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.
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