次のページ 前のページ 目次へ

3. バグレポート

Linux の SCSI 開発者たちは、古いコードを取っておいているとは限りません。 したがって、リリースされた最新の Linux カーネル以外では (MCC、SLS、 Yggdrasil などのパッケージは最新カーネルから1つから12個も古い場合が あります) 問題解決が不可能な場合があります。 ですから、バグレポートを送る前に、リリースされた最新のカーネルでも その問題が起こるかどうか確かめて下さい。

カーネルをバージョンアップした後でも、またこの文書をよく読んだ後でも、 まだバグが存在すると信じられる場合には、Linux メーリング リストの SCSI チャネルにバグレポートを送ってください。 ここには Linux SCSI ドライバの作成に協力している多くの人々が参加しています。

バグレポートには、 ハードウェア構成、ブート時に Linux が表示する正確なメッセージ、 エラーが発生する場合、それにエラーが存在するソースコードの位置 など、なるべく多くの情報を書いてください。 メッセージの取得<tt>panic()</tt> の位置を特定する に記述されている手続きに従ってください。

最大限の情報が提供されないと、開発者が問題を誤って診断したり、 他の問題を修正することがより重要だと判断することになってしまうかも しれません。

要するに、我々がバグを再現させることができない場合、 どこがおかしいのかを具体的に指摘してくれなければ、 バグを修正することはできないということです。

3.1 メッセージの取得

カーネルメッセージロギングシステムを実行していない場合:

/proc ファイルシステムがマウントされていることを確かめて ください。

grep proc /etc/mtab

/proc ファイルシステムがマウントされていなければ、マウント してください。

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

カーネルのバージョンとメッセージをログファイルにコピーします。

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

1秒から2秒後に CNTRL-C を打ってください。

ロギングシステムを実行している場合、適当なログファイル (ログファイルの 情報は /etc/syslog.conf にあります) を覗くか、 dmesg コマンドを使用してください。

Linux が起動していない場合、DOS 上でフロッピーディスクをフォーマット してください。RAM ドライブではなく、ルートディスケットを直接マウント するパッケージを使っている場合には、ルートとしてマウントされるドライブ 以外で読み書き可能なディスケットを用意するか、 ramdisk ブートオプションの使用が必要であることに 注意して下さい。

Linux をパッケージのブートフロッピーからブートします。できればシングル ユーザモードで RAM ドライブをルートとしてマウントしてください。そして、

mkdir /tmp/dos

とし、さっきフォーマットしたディスケットを挿入し、マウントしてください。

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

あるいは

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

とします。

ログファイルをフロッピーにコピーします。

cp /tmp/log /tmp/dos/log

DOS フロッピーをアンマウントします。

umount /tmp/dos

そして Linux をシャットダウンします。

shutdown now

リブートして DOS を起動し、好みの通信ソフトを使ってログファイルを メールしてください。

3.2 panic() の位置を特定する

他の Unix と同じように、Linux は致命的なエラーが生じるとカーネルの panic() 関数を呼び出します。他の Unix とは違って、Linux は コアをスワップあるいはダンプデバイスにダンプして自動的にリブート することはありません。その代わり、ユーザが手で書き写すことができる ように有用なステート情報のサマリが表示されます。

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

EIP: 行の16進数 (この場合 19c905) を書き留め、 /usr/src/linux/zSystem.map を探してこのアドレス以下で最も大きな 数字を見つけてください。

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

これによってどの関数を実行中に panic() が呼ばれたかが分かります。 この関数を含むソースファイルをデバッグオプションつきでコンパイルし直すか、 /usr/src/linux/Makefile を編集して -g オプションを CFLAGS の定義に追加してカーネル全体をコンパイルし直してください。

#
# standard CFLAGS
#

つまり、次の行を

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

このように変更します。

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

カーネルを再構築します。

make clean
make

/etc/lilo.conf にエントリを作成してカーネルをブートできるように します。

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

そして root で LILO を再実行するか、ブートフロッピーを作成します。

make zImage 

リブートし、エラー発生時の EIP を記録します。

script がインストールされている場合、これを起動して 以下のデバッグの記録をタイプスクリプトファイルに記録して おくのが良いでしょう。

次のように gdb を実行します。

gdb /usr/src/linux/tools/zSystem

そして次のように入力します。

info line *<your EIP>

例えば以下のように。

info line *0x19c905

これに対して gdb は次のような情報を出力します。

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

この情報を記録して下さい。それから以下のように入力します。

list <line number>

次のような出力が得られるでしょう。

(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 と入力して gdb から抜けます。

上の情報も記録してください。開発者のカーネルがあなたのカーネルと違って いる場合に役立つコンテキスト情報が得られます。


次のページ 前のページ 目次へ