MIRACLE
メールサービス申込 ユーザー登録 パートナー情報
お問い合わせ FAQ サイトマップ
MIRACLE LINUXの特長 製品紹介 サービス案内 購入 サポート 技術フォーラム

2006年8月 7日 (月)

岡山カーネル勉強会

8/5(土)に無事、岡山カーネル勉強会を行うことができました。

その中で、私はcrashコマンドの使い方を中心に、一部ハンズオンのような形で
実際にみなさんで一緒にcrashを使ってみながら、カーネル内部を覗いていくということが簡単にできるんだということを体感していただきました。

私のセッションの流れとしては、
- VMwareでcrashをすぐに使えるMIRACLEV4.0環境をDVD-Rで配布。みなさんのノートPCで起動。
- 当日の資料にはdiskdumpやnetdumpに関する資料が無かったので、少し口頭で説明しました。
  - なぜダンプが必要か?
    - カーネルPANICが発生した瞬間のログやメッセージは、syslogでは記録されない。
    - カーネルダンプを取得することで、問題の原因が何であるか追及することができる。

- crashの使い方
  1. 稼働中カーネルのメモリ内容を簡単に見るためにcrashを使う方法
  2. sysrq+cによる強制PANICを実施。カーネルダンプファイルを作成
  3. 作成したダンプファイルを見ながらcrashの使い方を勉強

こういった流れで説明をしていきました。
カーネルの事を知らない方が対象でしたので、うまく伝えきることができない部分もありましたが、「crashを使ってカーネルの勉強することができる」というのは新しい発見でした。

当日の資料を載せておきますので、ぜひ参考にしてみてください。
kernel_study_20060805.pdfをダウンロード

2006年7月28日 (金)

ファイルシステムに関する情報源

みなさんは、WikiPediaを使ったことはありますか。

今回、たまたまGoogle検索の結果でWikiPediaのページがひっかかったのですが、
英語版は内容が充実していますね。

参考までに、Linuxの3つのファイルシステムに関するページを見てください。

弊社でもよくファイルシステムの制限値などに関して問い合わせを受けることがあるのですが、一般的な内容に関しては上記のページの内容で十分すぎるほどに記載されています。
日本語で記載されていないので、少し障壁が高いかもしれませんが情報源としては、非常に価値のあるものだと思います。
ぜひ、みなさんも活用してみてはいかがでしょうか。

2006年7月26日 (水)

岡山カーネル勉強会(詳細)

先日お知らせした岡山カーネル勉強会ですが、内容もほぼ固まりつつありますので、改めてご紹介しておきます。

8/5(土) 13:00-18:00に岡山理科大学にて実施します。
詳細確認、申し込みはこちらのwikiにてお願いします。
岡山カーネル勉強会

さて私の担当の時間ですが、MIRACLE LINUX V4.0を使って、「crashを使ってカーネル内部を覗いて見よう」という内容で実施しようと思い準備中です。

そこで、当日の実演用にVMware Player用のMIRACLE LINUX V4.0環境を用意しています。
MIRACLE LINUX V4.0の最小構成インストールに、kernel-debuginfoや、crashコマンドの最新版など、カーネル内部を覗いて見るのに必要なものを含めています。
X Windowなどを除くことで2GB程度のイメージに抑えることができましたので、DVD-Rで参加者のみなさんにも実行環境としてお渡しする予定です。
当日、ノートPCを持ってこられる方は、ぜひVMware Playerをインストールしておいてください。もちろんVMware Workstationとかがインストールされているならば、そちらでも構いません。

USB接続のDVD-ROMドライブを持参する予定ですので、DVD-ROMドライブが付いていない方でも、PCにコピーしてもらって使ってもらおうと思っています。

あとはリモートログインするために、Windows環境の方はputtyなどのssh端末を用意しておくと便利だと思います。

当日の私の発表資料については、後日、本BLOGに掲載する予定です。

それではみなさんの参加をお待ちしています。

2006年7月13日 (木)

岡山カーネル勉強会(告知)

最近、「ひらメソッド」で有名なひらさんとやりとりする中で、タイミングよく
岡山カーネル勉強会を8/5(土)に開きましょうということを決めました。

その名の通り、岡山駅周辺のどこかで開催しますので、西のほうでなかなか東京の
YLUGのような会に出れない方はぜひ参加してみてください。
今のところは、私とひらさんの2名なので、非常に濃い話になる可能性も捨て切れませんが、もしかすると、単にカーネル勉強会という名の飲み会になる可能性もあります。

ちなみになぜ岡山かというと、私とひらさんが岡山出身だからという都合のみです。

詳細は、こちらですが、内容についてはこれから詰めますので、参加者の方はぜひぜひ希望を伝えてください。
岡山カーネル勉強会

カーネルの勉強方法

最近、カーネルダンプの記事を執筆するにあたって気づいたことがあります。

crashコマンドはカーネルの解析だけでなく、カーネルの勉強にも使えるのではないかと。

実は弊社では昨年度、カーネル勉強会と称して、カーネル初心者も対象に、適当にカーネルのソース単位で割り振りを決めて、勉強会を実施しました。

また、数年前、私がまだカーネルのことを知らなかったころのカーネル勉強会では、コンポーネント単位に割り振りを決めて、「詳解Linuxカーネル 第1版」あたりを参考にしながらカーネルの概念を勉強していった記憶があります。

さらに今年度は趣向を変えて、パッチ単位でカーネルがどのように変更されていくのか攻めてみようかとおもったりしています。

このようにLinuxカーネルのことを勉強するにはいろいろな方法があり、各自が各自の方法でLinuxカーネルのことを勉強していると思います。
その中では実際にコードを書きながら、カーネルの勉強をしている方も多いかと思いますが、カーネルのコードを書くことはそれなりに敷居の高い作業になります。

そこで思いついたのがcrashコマンドの活用です。「ひらメソッド」のひらさんは、おそらく机上でカーネルのソースを解読しているのではないかと思うのですが、さらにそれを一歩進めて、机上解析に加えて、crashコマンドを使いながら、実機のデータを見ながら、ソースコードを読んでいくと、カーネルの動作の理解が進むのではないかと思います。

さらには、カーネル内のオブジェクトがお互いに何のメンバでリンクされているか、図示することで、ダンプ解析に非常に役立つ情報もできるのではないかと思いました。

単なるアイデアレベルですが、はっ!思いつきましたので書いてみました。

みなさんは、どうやってLinuxカーネルの勉強をされてますか?

2006年7月 3日 (月)

カーネル空間からコマンド実行

土日をはさんで4日間。取り掛かっていたダンプファイルの解析がほぼ完了した。と信じている、今この瞬間です。

ダンプ解析は難しいけれども、解析に成功したときはものすごくうれしい。間違いなくアドレナリンが出まくっている。でも調べている最中には何度も挫折しそうになる。
そんなときには、気分転換も大事だ。

今のお気に入りは、会社の目の前にあるファミリーマートで打っているあずきバーだ。ダンプ解析していると昼ごはん直後の2時間ぐらい、非常に眠くなる。メモリダンプの数値の羅列なぞ目に入らない状態になってしまう。
そんなときに、キンキンカチカチに冷えたあずきバーは私を何度でも甦らせる
って、いくら眠くてもそんなに何度も甦るほどあずきバーを食べると太ってしまいます。なにしろ練乳入りですから。

060703_2123

そんな与太話ばかり書くわけにもいかないので、ひとまず今日のソース解読研究所のTIIPS。
ホットプラグ機能を使うとき、カーネルは、ホットプラグすべきイベントが発生すると、/proc/sys/kernel/hotplugに設定されているコマンドを実行して、ユーザ空間でいろいろなコマンドを実行させてホットプラグを実現させている。

では、カーネルから、ユーザ空間のコマンドを実行するにはどうしているのか?

その答えはkernel/kmod.cにある。

kernel/kmod.c内のcall_usermodhelper()を使うと、ユーザ空間のコマンドを実行することができる。
------
        struct subprocess_info sub_info = {
                .complete       = &done,
                .path           = path,
                .argv           = argv,
                .envp           = envp,
                .wait           = wait,
                .retval         = 0,
        };
------
call_usermodehelper()では、上記のような値を設定して、コマンドを実行させる。当然、pathには、実行するファイルの絶対パスを指定する。argvには引数を。といった具合だ。

ここで呼び出すコマンドの情報は、カーネルスレッドの[khelper]に渡される。
khelperは、さらに新しい子供のカーネルスレッド[ khelper]を作成し、そのカーネルスレッドを、execve()で要望されたユーザコマンドに変身させ、実行させる。

そんなわけであなたのkernel 2.6のシステムにはkhelperが常駐して日々ホットプラグに勤しんでいることでしょう。

カーネルとアプリケーションの関係

ひさびさに今週はYLUGに参加しようと思っています。
第65回YLUG
時々、ミラクルのセミナールームでも実施していたりするにも関わらず、仕事に追われて出席していない日々が多かったのです。でも、今から思うともったいないことをしていました。昔は、横浜のOSDLまで行ってましたが、その頃に出会った方とは最近になって一緒に仕事したりといったこともあります。技術だけではなく、人脈の広がりといった面でも貴重な機会ですよね。みなさんもぜひ参加されてはいかがでしょう。

今回は、mixiのシステムの成長に関するお話ということで、ちょっと興味があります。ここ数年カーネルのお仕事中心でやってきましたが、この知識をもっと上のレイヤに生かせないかと思っていた丁度このごろでした。ぜひ、現実のシステムでの課題を聞いてみたいと思います。最近mixiを使い始めたこともあって、私の琴線にものすごくヒットしています。

さらに、7/15に神戸でLMS(LILO Monthly Seminar)というものがあるらしく、先日トラックバックいただいたひらさんに微妙に参加を期待されているようです。ここでもカーネルとアプリケーションといった縦方向の関係についてのお話がありそうな雰囲気です。また、私自身、ミラクルに来る前は7年間神戸で生活していたこともあってまんざらでもなかったりして、なんとか参加できないか画策中の今日このごろです。

Linuxって、今では無意識のうちに利用するインフラの存在になってしまっていて、ディストリビューションを使っていると提供されたカーネルを使うのが当たり前になっていますが、本当は目的に応じたチューニングというのがあるはずなんですよね。いろんな人の経験と知見をもとにした最大公約数を取って、汎用OSのカーネルとして今の設定で提供していますが、もっとアプリと協調してチューニングしたり、そのシステムのポイントを強化したりといったことができるところもあるのではないかと感じることも多々あります。
そういったことを実現するためにはカーネルの実装というより、カーネルがどのように動くのか、普通のエンジニアの方に理解してもらうための「ことば」を導く必要があって、そこが一番難しいところです。いきなり、「ページテーブルがメモリを圧迫する」とかいってもイメージできないですよね。

最近、会社のブログで私のページを独立して作成したのは、その難しい、ある意味経験としてつんできた部分を、何とか「ことば」として伝えられないかと思ったのもきっかけのひとつです。

私自身がなかなか外へ出て行く仕事ではないため、なかなか現実のシステムでの問題を解決するといったことに挑戦する機会がありませんが、もしLinuxのことでお困りのことがあれば、ミラクルに相談していただけると、もしかしたらお手伝いできるかもしれません。

2006年6月28日 (水)

最強の割り込み

カーネルストール。これは厄介な敵です。

カーネルPANICならば、最近のカーネルに備わっているdump機能が働いて、カーネルダンプが取れたりするので、さっさとrebootするのを待つばかりです。

一方でカーネルストールの場合、よくあるのはログインしようとしてもなぜかプロンプトが返ってこないとか、キーは入力できないけどマウスカーソルの位置だけ動くとか、微妙感漂う状況に陥ることがあります。

今日はそんな時の強い味方、NMIについて調べてみましょう。

まず、NMIって何でしょう。一般人の味方 Googleで調べてみます。

http://www.nifty.com/webapp/digitalword/word/020/02083.htm

こんなページがひっかかりました。何々? 「Non-Maskable Interrupt - マスク不可能な割り込みのこと。ソフトウェアでこのNMIを禁止することはできない。」と書かれています。

「割り込み」って何でしょう?  いろいろなデバイスは、自身が働いたことをCPUに伝えるために、「割り込み」という仕組みを使います。CPUが処理している最中に、「割り込み」、「割り込み」、「割り込み」と好き勝手に割り込むわけです。一方でCPUはコンピュータの中の王様(KING)なので、「勝手な割り込みは許さーん」と割り込みを禁止することができます。これが普通のデバイスと割り込みの関係です。

ところがNMIは違います。その名の通り、割り込みを禁止することができないのです。NMIによって割り込まれると、CPUは否応なしにそのNMI割り込みを処理しなければなりません。そのため、NMI割り込みは最強なのです。

このNMIを利用した機能に、「NMI watchdog」と呼ばれる機能があります。NMI watchdogとは、NMIの割り込みを利用して、OSのストールを検出するための機能です。

まず、通常動作中、タイマー割り込みと呼ばれる定期的な割り込みの中で、割り込み回数のカウンタが増えていきます。

linux-2.6.9-11.19AX/arch/i386/kernel/apic.c
-----
void smp_apic_timer_interrupt(struct pt_regs regs)
{
        union irq_ctx   *curctx;
        union irq_ctx   *irqctx;
        int             cpu;
        u32             *isp;

        /*
         * the NMI deadlock-detector uses this.
         */
        cpu = smp_processor_id();
        irq_stat[cpu].apic_timer_irqs++; ← ここでカウンタ増加
-----

この処理とは別に、定期的なNMI割り込みの中で、このカウンタの数値を確認します。
linux-2.6.9-11.19AX/arch/i386/kernel/nmi.c
-----
void nmi_watchdog_tick (struct pt_regs * regs)
{
        /*
         * Since current_thread_info()-> is always on the stack, and we
         * always switch the stack NMI-atomically, it's safe to use
         * smp_processor_id().
         */
        int sum, cpu = smp_processor_id();
        sum = irq_stat[cpu].apic_timer_irqs;
        if (last_irq_sums[cpu] == sum) {  /* もし前回と同じ値なら、タイマー割り込みが処理されていない */
                /*
                 * Ayiee, looks like this CPU is stuck ...
                 * wait a few IRQs (5 seconds) before doing the oops ...
                 */
                alert_counter[cpu]++;
                if (alert_counter[cpu] == 30*nmi_hz)
                        die_nmi(regs, "NMI Watchdog detected LOCKUP");  /* 問題発生を検出 */
        } else {
                last_irq_sums[cpu] = sum;
                alert_counter[cpu] = 0;
        }
-----

上記のコードでは、NMI割り込みのたびに、カウンタの数値をチェックし、カウンタの数値が変わらない時間が一定時間続くと、die_nmi() を呼び出しNMI独自のエラー処理を行うというものです。例えば割り込みが禁止された状態でカーネルがストールすると、タイマー割り込みの処理もできないので、カウンタの数値を変更する処理が行われません。しかし、NMIは割り込み禁止にすることができないので、たとえタイマー割り込みが行えなくとも、NMI割り込みによるカウンタのチェックは有効なのです。

こうして、カーネルは自分自身がストールしたことを検出し、カーネルダンプを取ったり、rebootしたりといった荒技を行うことで、システムの状態を元に戻すことができます。

さてこのNMI watchdogの機能ですが、使う際に1つだけ注意があります。それは、使えるマシンが限られているということです。カーネルのブートオプションに、nmi_watchdog=1、もしくはnmi_watchdog=2として付けてみて、/proc/interruptsを確認してみてください。

-----

$ cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3
  0:        139          0          0  184539452    IO-APIC-edge  timer
  1:          0          0          0         74    IO-APIC-edge  keyboard
  2:          0          0          0          0          XT-PIC  cascade
  9:          0          0          0          0   IO-APIC-level  acpi
14:          0          2          0         62    IO-APIC-edge  ide0
15:          0          0          0          0    IO-APIC-edge  libata
16:          0          0          0          0   IO-APIC-level  usb-uhci
18:          0          0          0          0   IO-APIC-level  usb-uhci
19:          0          0          0          0   IO-APIC-level  usb-uhci
23:          0          0          0          0   IO-APIC-level  ehci-hcd
24:          0          0          0    6935854   IO-APIC-level  eth0
30:          0          0          0    1676288   IO-APIC-level  aic79xx
31:          0          0          0         30   IO-APIC-level  aic79xx
NMI:    1481143    1360317          0          0
LOC:  184534393  184534414  184534414  184534414
ERR:          0
MIS:          0
-----

NMIの数値が増えていれば、NMI割り込みが発生していますので、NMI watchdogの機能を利用することができます。この数値が0のままのサーバの場合、残念ながらNMI watchdogの機能を利用することができません。

参考: http://slacksite.com/slackware/nmi.html

 

2006年6月23日 (金)

時間は無限?

マシンを立ち上げるとLinuxカーネルが立ち上がります。そして、マシンを停止するまでカーネルが動きつづけるわけです。この間、カーネルは刻々と時を刻んでいきます。
そこでカーネルでの時間の管理に使われるのが、jiffiesという変数です。
kernel-2.4では、kernel/timer.cで次のように定義されています。
----
unsigned long volatile jiffies __cacheline_aligned;
----

unsigned longなので、32bit環境では、0〜0xffffffffの範囲を表すことができます。
このjiffiesは、timer割り込みと呼ばれる処理の際に1ずつ増加していきます。timer割り込みの頻度は、"HZ"として定数で定義されています。
linux-2.4.21/include/asm-i386/param.h
----
#ifndef HZ
#define HZ 100
#endif
----
ということで、kernel-2.4のIA32環境では、1秒間に100回のタイマー割り込みが発生し、jiffiesが1秒間に100増えていくということになります。

それでは、jiffiesの値は無限に増やせるのでしょうか?
さきほど示したように、32bit環境では、jiffiesの最大値は0xffffffffなので、その時間までしかカウントできないことになります。計算してみると、約497日(1年5ヶ月)で最大値を迎えることになります。これが噂のjiffiesのオーバーフローです。jiffiesがオーバーフローすると、また0に戻ってカウントしていきます。

さて、jiffiesがオーバーフローすると何か困ることがあるでしょうか?
例えば、今の時間がjiffies変数に入っていて、n秒後にタイムアウトを判断するために、次のようなコードを書いたとします。
----

timeout = jiffies + n;

タイマーセット(timeout);

----

数秒後に、タイムアウト時間が過ぎているかどうか調べてみます。

----

if (jiffies < timeout){

   printk("まだタイムアウトしてないよ!\n");

}

----

こんなコードを書いた時、「噂のjiffiesのオーバーフロー」が発生するとどうなるでしょう? timeoutが32bitの最大値ぎりぎり(例えば 0xfffffff9)に設定されたりしていると、オーバーフロー直後にチェックすると、

-----

if ( 3 < 0xffffffff9 )

  → 真なので、「まだタイムアウトしてないよ!」出力。

-----

といったことになって、正しく処理できなくなってしまいます。

そこで、カーネルではそんな悲しい出来事が起きないように、ちょっとした工夫をしています。

それはここです。
linux-2.4.21/include/sched.h

-----

#define time_after(a,b)         \
        (typecheck(unsigned long, a) && \
         typecheck(unsigned long, b) && \
         ((long)(b) - (long)(a) < 0))
----

jiffiesのようなタイムアウトの判断に使うためのマクロが用意されています。ポイントはここですね。
----
((long)(b) - (long)(a) < 0))
----

こういう計算にすると、jiffiesがオーバーフローしても大丈夫ですね。ポイントは「キャスト」です。(キャストといっても装甲が飛んで軽くなるあれ系とは関係ありません。)

kernel 2.4の多くのコードがこのマクロを使うように書き換えられていますが、まだまだ完璧ではないようです。ちなみにkernel 2.6ではjiffiesが64bit化されているので、オーバーフローまで何日かかることやら...。

2006年6月 8日 (木)

Number -17

17番といっても、Redsの赤丸急上昇中 長谷部選手のことではありません。

最近のkernelでは、17という数字に関係した機能が1つあるというお話です。
みなさんは、syslogメッセージで次のようなメッセージを見たことはありますか?
messages:Apr 20 10:50:26 localhost kernel: oom-killer: gfp_mask=0xd0

これは、oom-killer、つまりOut Of Memoryが発生したことを知らせるカーネルのメッセージです。Out Of Memoryとは、カーネル内でのメモリのやりくりがどうにもつかなくてメモリが足りない状況に陥ったことを表します。このような場合、カーネルは仕方ないので、プロセスをkillしてメモリを確保しようとします。そのためoom-killerと呼ばれています。

このとき、カーネルがどのプロセスをkillするかは、いろいろな要素を加味して計算した結果で選択するのですが、必ずしも影響の小さいプロセスをkillしてくれるとは限りません。そのため、時にはアプリケーション内で最も重要なプロセスがkillされる可能性もあります。

そんな事態を少しでも避けたいというシステム管理者の思いが通じたのか、oom-killerによってkillされる対象から特定のプロセスを除外することができるようになりました。

linux-2.6.16/mm/oom_kill.cに次のようなコードがあります。
-----
                if (p->oomkilladj == OOM_DISABLE)
                        continue;
-----
ここで、pはプロセスを表します。この部分は、プロセスのoomkilladj変数がOOM_DISABLEだと、oom_killerの対象からはずすためのコードになっています。

このoomkilladjがどこで設定されるかというと、
linux-2.6.16/fs/proc/base.c
-----
static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
{
        struct task_struct *task = proc_task(file->f_dentry->d_inode);
        char buffer[8], *end;
        int oom_adjust;

        if (!capable(CAP_SYS_RESOURCE))
                return -EPERM;
        memset(buffer, 0, 8);
        if (count > 6)
                count = 6;
        if (copy_from_user(buffer, buf, count))
                return -EFAULT;
        oom_adjust = simple_strtol(buffer, &end, 0);
        if ((oom_adjust < -16 || oom_adjust > 15) && oom_adjust != OOM_DISABLE)
                return -EINVAL;
        if (*end == '\n')
                end++;
       task->oomkilladj = oom_adjust; ←ここです。
        if (end - buffer == 0)
                return -EIO;
        return end - buffer;
}
-----
ということで、/procで設定できるようです。
確認のために、/procの各プロセスのファイルを見てみると、
-----
$ ls
attr     cwd      fd        mem      oom_score  stat    task
auxv     environ  loginuid  mounts   root       statm   wchan
cmdline  exe      maps      oom_adj  smaps      status
-----
と、まさにそのもののファイルがありました。

さて、最後になりましたが、OOM_DISABLEの定数を確認します。
linux-2.6.16/include/linux/mm.h
-----
/* /proc/<pid>/oom_adj set to -17 protects from the oom-killer */
#define OOM_DISABLE -17
-----
ということで、-17を設定することでoom_killerから守ることができるという説明も付いてますね。

だからといって全てのプロセスに-17を設定してしまうと、カーネルがメモリが足りなくて困っているのにどうしようもなくなって、もっとひどい事態になると思いますので、設定は慎重に。

2006年6月 5日 (月)

ドライバはデバイスを認識できるか?

前回、あるシステムでaacraidドライバが必要になる例を紹介しました。
今回は、ドライバがデバイスを利用できるかどうか調べてみます。

前回の例と同様にaacraidドライバを例にします。
今回システムに搭載されているデバイスのベンダIDとデバイスIDは、それぞれ0x9005  0x0285でした。

それではいきなりですが、カーネルソースに含まれているドライバのソースをチェックしてみます。今回は、MIRACLE V4.0のkernel-2.6.9-11.25AXを使います。
aacraidのソースは、drivers/scsi/aacraidにあるので、とりあえず"PCI"でgrepしてみます。
-----
$ cd drivers/scsi/aacraid
$ grep PCI *
README:Christoph Hellwig <hch@infradead.org>    (updates for new-style PCI probing and SCSI host registration,
aacraid.h:                                              //       Local  |   PCIName
aacraid.h:      struct pci_dev          *pdev;          /* Our PCI interface */
aacraid.h:#define FSACTL_GET_PCI_INFO                   CTL_CODE(2119, METHOD_BUFFERED)
commctrl.c:     pci_info.slot = PCI_SLOT(dev->pdev->devfn);
commctrl.c:     case FSACTL_GET_PCI_INFO:
comminit.c:      * with the GART on x86-64. I've btw never tried DMA from PCI space
commsup.c: *    Allocate and map the shared PCI space for the FIB blocks used tocommsup.c: *    Free the PCI mappings and the memory allocated for FIB blocks
commsup.c: *    Allocate the PCI space for the fibs, map it and then intialise the
linit.c:        { 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */
linit.c:        { 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */
linit.c:        { 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 20 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */
linit.c:        { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 23 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
linit.c:        { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 24 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */
linit.c:        { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 25 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
linit.c:        { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 26 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
linit.c:        { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 27 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
linit.c:        { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 28 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
linit.c:        { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 29 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
linit.c:        { 0x9005, 0x0285, 0x0E11, 0x0295, 0, 0, 30 }, /* AAR-2610SA PCI SATA 6ch */
linit.c:        { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 41 }, /* Dell Catchall */
linit.c:        { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 42 }, /* Legend Catchall */
linit.c:        { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 43 }, /* Adaptec Catch All */
linit.c:        { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 44 }, /* Adaptec Rocket Catch All */
linit.c:        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020ZCR     ", 2 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */
linit.c:        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2025ZCR     ", 2 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */
linit.c:        { aac_rkt_init, "aacraid",  "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */
linit.c:        { aac_rkt_init, "aacraid",  "ADAPTEC ", "ASR-2130S PCI-X ", 1 }, /* ASR-2130S (Lancer) */
linit.c:        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020SA       ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
linit.c:        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2025SA       ", 1 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */
linit.c:        { aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2410SA SATA ", 1 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
linit.c:        { aac_rx_init, "aacraid",  "DELL    ", "CERC SR2        ", 1 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
linit.c:        { aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2810SA SATA ", 1 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
linit.c:        { aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-21610SA SATA", 1 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
linit.c:        { aac_rx_init, "aacraid",  "ADAPTEC ", "SO-DIMM SATA ZCR", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
linit.c:        register_ioctl32_conversion(FSACTL_GET_PCI_INFO, NULL);
linit.c:        unregister_ioctl32_conversion(FSACTL_GET_PCI_INFO);
----------

いろいろ出てきましたが、真ん中あたりに気になるものがあります。
------
linit.c:        { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 42 }, /* Legend Catchall */
linit.c:        { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 43 }, /* Adaptec Catch All */
linit.c:        { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 44 }, /* Adaptec Rocket Catch All */
------
このあたりです。
あれ?  0x9005, 0x0285ですね。
これはもしや....ということで、linit.cを覗いてみます。

-----

/*
* Because of the way Linux names scsi devices, the order in this table has
* become important.  Check for on-board Raid first, add-in cards second.
*
* Note: The last field is used to index into aac_drivers below.
*/
static struct pci_device_id aac_pci_tbl[] = {
        { 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si (Iguana/PERC2Si) */
        { 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di (Opal/PERC3Di) */
        { 0x1028, 0x0003, 0x1028, 0x0003, 0, 0, 2 }, /* PERC 3/Si (SlimFast/PERC3Si */
        { 0x1028, 0x0004, 0x1028, 0x00d0, 0, 0, 3 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
        { 0x1028, 0x0002, 0x1028, 0x00d1, 0, 0, 4 }, /* PERC 3/Di (Viper/PERC3DiV) */
        { 0x1028, 0x0002, 0x1028, 0x00d9, 0, 0, 5 }, /* PERC 3/Di (Lexus/PERC3DiL) */
        { 0x1028, 0x000a, 0x1028, 0x0106, 0, 0, 6 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
        { 0x1028, 0x000a, 0x1028, 0x011b, 0, 0, 7 }, /* PERC 3/Di (Dagger/PERC3DiD) */
        { 0x1028, 0x000a, 0x1028, 0x0121, 0, 0, 8 }, /* PERC 3/Di (Boxster/PERC3DiB) */
        { 0x9005, 0x0283, 0x9005, 0x0283, 0, 0, 9 }, /* catapult */
        { 0x9005, 0x0284, 0x9005, 0x0284, 0, 0, 10 }, /* tomcat */
        { 0x9005, 0x0285, 0x9005, 0x0286, 0, 0, 11 }, /* Adaptec 2120S (Crusader) */
        { 0x9005, 0x0285, 0x9005, 0x0285, 0, 0, 12 }, /* Adaptec 2200S (Vulcan)
*/
        { 0x9005, 0x0285, 0x9005, 0x0287, 0, 0, 13 }, /* Adaptec 2200S (Vulcan-2m) */
        { 0x9005, 0x0285, 0x17aa, 0x0286, 0, 0, 14 }, /* Legend S220 (Legend Crusader) */
        { 0x9005, 0x0285, 0x17aa, 0x0287, 0, 0, 15 }, /* Legend S230 (Legend Vulcan) */
-----

どうやら、このデバイスドライバが利用できるカードのIDが含まれているようですね。

ということで、デバイスドライバは、利用できるデバイスの一覧を持っているようです。

試しに、Intel Gigabit Ethernetのe1000のソースも見てみましょう。

すると、drivers/net/e1000/e1000_hw.h に次のようなデバイスIDのリストを持っていました。

-----

/* PCI Device IDs */
#define E1000_DEV_ID_82542               0x1000
#define E1000_DEV_ID_82543GC_FIBER       0x1001
#define E1000_DEV_ID_82543GC_COPPER      0x1004
#define E1000_DEV_ID_82544EI_COPPER      0x1008
#define E1000_DEV_ID_82544EI_FIBER       0x1009
#define E1000_DEV_ID_82544GC_COPPER      0x100C
#define E1000_DEV_ID_82544GC_LOM         0x100D
#define E1000_DEV_ID_82540EM             0x100E
#define E1000_DEV_ID_82540EM_LOM         0x1015
#define E1000_DEV_ID_82540EP_LOM         0x1016
#define E1000_DEV_ID_82540EP             0x1017
#define E1000_DEV_ID_82540EP_LP          0x101E
#define E1000_DEV_ID_82545EM_COPPER      0x100F
#define E1000_DEV_ID_82545EM_FIBER       0x1011
#define E1000_DEV_ID_82545GM_COPPER      0x1026
#define E1000_DEV_ID_82545GM_FIBER       0x1027
#define E1000_DEV_ID_82545GM_SERDES      0x1028
#define E1000_DEV_ID_82546EB_COPPER      0x1010
#define E1000_DEV_ID_82546EB_FIBER       0x1012
#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
#define E1000_DEV_ID_82541EI             0x1013
#define E1000_DEV_ID_82541EI_MOBILE      0x1018
#define E1000_DEV_ID_82541ER             0x1078
#define E1000_DEV_ID_82547GI             0x1075
#define E1000_DEV_ID_82541GI             0x1076
#define E1000_DEV_ID_82541GI_MOBILE      0x1077
#define E1000_DEV_ID_82541GI_LF          0x107C
#define E1000_DEV_ID_82546GB_COPPER      0x1079
#define E1000_DEV_ID_82546GB_FIBER       0x107A
#define E1000_DEV_ID_82546GB_SERDES      0x107B
#define E1000_DEV_ID_82546GB_PCIE        0x108A
#define E1000_DEV_ID_82547EI             0x1019
#define E1000_DEV_ID_82573E              0x108B
#define E1000_DEV_ID_82573E_IAMT         0x108C
-----

ちなみにIntelのベンダIDは、8086 です。

ということで、それぞれのデバイスドライバごとにリストの持ちかたは違いますが、利用できるデバイスのIDを持っているということが分かりました。

みなさんも、あるドライバが自分のマシンで使えるかどうか調べてみたいときには、このようにしてドライバのソースを覗いてみてはいかがでしょう。もちろん実際に問題なく動作するかどうかは保証できませんが、少なくとも動作する可能性については確認できます。

会社情報 採用情報 個人情報保護方針 商標等取り扱い事項 English
Copyright(c)2000-2006 MIRACLE LINUX CORPORATION. All Rights Reserved.