ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
デバイスドライバの記述 Oracle Solaris 11.1 Information Library (日本語) |
パート I Oracle Solaris プラットフォーム用デバイスドライバの設計
2. Oracle Solaris カーネルとデバイスツリー
22. ドライバのコンパイル、ロード、パッケージ化、およびテスト
23. デバイスドライバのデバッグ、テスト、およびチューニング
SPARC プラットフォームでの代替カーネルを使用した kmdb のブート
x86 プラットフォームでの代替カーネルを使用した kmdb のブート
Oracle Solaris Ethernet ドライバのカーネル統計
データ損失などの問題を避けるため、新しいデバイスドライバをテストするときには、特に注意を払うようにしてください。このセクションでは、さまざまなテスト方針について説明します。たとえば、シリアル接続経由で制御可能な別個のシステムを設定するのが、新しいドライバをテストする場合にもっとも安全な方法です。さまざまなカーネル変数設定を含むテストモジュールをロードし、さまざまなカーネル条件の下でパフォーマンスをテストできます。システムがクラッシュした場合に備え、バックアップデータの復元、任意のクラッシュダンプの解析、およびデバイスディレクトリの再構築を行う準備を整えておくべきです。
システムがハードハング状態に陥ると、デバッガを起動できなくなります。デッドマン機能を有効にすると、システムはいつまでもハングする代わりにパニック状態になります。その後、kmdb(1) カーネルデバッガを使用して問題の解析を行えます。
デッドマン機能は 1秒に一度、システムクロックが更新されているかどうかをチェックします。システムクロックが更新されていない場合、システムが無期限のハングに陥っていることになります。システムクロックが 50 秒間更新されないと、デッドマン機能によってパニックが引き起こされ、デバッガが起動されます。
デッドマン機能を有効化するには、次の手順に従います。
クラッシュイメージの取得中であることを dumpadm(1M) で確認します。
/etc/system ファイル内で snooping 変数を設定します。/etc/system ファイルについては、system(4) のマニュアルページを参照してください。
set snooping=1
/etc/system ファイルが再度読み取られて snooping 設定が有効になるように、システムをリブートします。
システム上のすべてのゾーンもデッドマン設定を継承します。
デッドマン機能が有効な状態でシステムがハングすると、次の例のような出力がコンソール上に表示されるはずです。
panic[cpu1]/thread=30018dd6cc0: deadman: timed out after 9 seconds of clock inactivity panic: entering debugger (continue to save dump)
デバッガの内部から ::cpuinfo コマンドを使用することで、クロック割り込みの発行に失敗してシステム時間を進めることができなかった原因を調査します。
ドライバをテストするときには、シリアル接続を使用することをお勧めします。ホストシステムとテストシステムの間でシリアル接続を確立するには、tip(1) コマンドを使用します。このアプローチでは、ホストコンソールの tip ウィンドウがテストマシンのコンソールとして使用されます。詳細については、tip(1) のマニュアルページを参照してください。
tip ウィンドウには次のような利点があります。
テストシステムやカーネルデバッグとの対話内容を監視できます。たとえば、ドライバが原因でテストシステムがクラッシュした場合、このウィンドウは使用中のセッションのログを記録できます。
tip ホストマシンにログインし、tip(1) を使用してテストマシンに接続することにより、テストマシンにリモートアクセスできます。
注 - Oracle Solaris デバイスドライバのデバッグに tip 接続や 2 台目のマシンの使用が必須というわけではありませんが、それでもこの手法をお勧めします。
この接続を行う際にはヌルモデムケーブルを使用する必要があります。
この端末エントリは、使用するシリアルポートに一致している必要があります。シリアルポート B については、オペレーティングシステムに適切なエントリが含まれていますが、シリアルポート A については端末エントリを追加する必要があります。
debug:\ :dv=/dev/term/a:br#9600:el=^C^S^Q^U^D:ie=%$:oe=^D:
注 - ボーレートは 9600 に設定する必要があります。
% tip debug connected
これによって、そのシェルウィンドウがテストマシンのコンソールへの接続を含む tip ウィンドウになります。
注意 - テストマシンを停止するとき、ホストマシンが SPARC マシンの場合は STOP-A キーを、x86 アーキテクチャーマシンの場合は F1-A キーを、それぞれホストマシン上で使用しないでください。この操作を行うと、実際にはホストマシンが停止されます。テストマシンに BREAK 信号を送信するには、tip ウィンドウで ~# と入力します。~# などのコマンドが認識されるのは、それらの文字が行の先頭にある場合のみです。このコマンドで効果がない場合は、Return キーまたは Control-U キーを押してください。 |
SPARC プラットフォームのテストマシンを設定する簡単な方法は、マシンの電源を入れる前にキーボードを取り外すことです。これによって、マシンのシリアルポート A が自動的にコンソールとして使用されます。
テストマシンを設定するもう 1 つの方法は、ブート PROM コマンドを使用してシリアルポート A をコンソールにすることです。テストマシンのブート PROM の ok プロンプトで、コンソール入出力をシリアル回線に転送します。テストマシンの起動時に必ずシリアルポート A がコンソールとして使用されるようにするには、環境変数 input-device と output-device を設定します。
例 23-1 ブート PROM コマンドによる input-device と output-device の設定
ok setenv input-device ttya ok setenv output-device ttya
eeprom コマンドを使用すると、シリアルポート A をコンソールにすることもできます。スーパーユーザーとして次のコマンドを実行し、input-device および output-device パラメータがシリアルポート A を指すようにします。次の例はその eeprom コマンドを示したものです。
例 23-2 eeprom コマンドによる input-device と output-device の設定
# eeprom input-device=ttya # eeprom output-device=ttya
この eeprom コマンドにより、その後システムがブートされるたびにコンソールがシリアルポート A にリダイレクトされます。
x86 プラットフォームでは、eeprom コマンドを使用してシリアルポート A をコンソールにします。その手順は、SPARC プラットフォームの手順と同じです。「SPARC プラットフォームのターゲットシステムの設定」を参照してください。この eeprom コマンドにより、リブート中にコンソールがシリアルポート A (COM1) に切り替わります。
注 - x86 マシンでは、BIOS がシリアルポートへのコンソールリダイレクションをサポートしていないかぎり、ブート処理のある初期段階に達するまでコンソールの制御が tip 接続に移りません。SPARC マシンではブート処理の全体を通じて、tip 接続がコンソールの制御を維持します。
/etc ディレクトリ内の system(4) ファイルを使用すると、ブート時にカーネル変数の値を設定できます。カーネル変数を使用すると、ドライバの複数の動作を切り替えたり、カーネルが提供するデバッグ機能を活用したりできます。デバッグ時に非常に役立つ可能性のあるカーネル変数 moddebug と kmem_flags については、このセクションで後述します。「ハードハングを避けるためのデッドマン機能の有効化」も参照してください。
ブート後のカーネル変数の変更は、信頼できません。/etc/system はカーネルのブート時に一度だけ読み取られるからです。このファイルを変更したあと、その変更を有効にするには、システムをリブートする必要があります。ファイルの変更後にシステムが機能しなくなった場合は、ask (-a) オプションを指定してブートします。その後、/dev/null をシステムファイルとして指定します。
注 - 将来のリリースでもカーネル変数が存在すると仮定することはできません。
set コマンドは、モジュール変数またはカーネル変数の値を変更します。モジュール変数を設定するには、次のようにモジュール名と変数を指定します。
set module_name:variable=value
たとえば、myTest という名前のドライバの変数 test_debug を設定するには、set を次のように使用します。
% set myTest:test_debug=1
カーネル自体によってエクスポートされた変数を設定する場合は、モジュール名を省略します。
値の設定には、ビット単位の論理和演算を使用することもできます。次に例を示します。
% set moddebug | 0x80000000
コマンド modload(1M)、modunload(1M)、および modinfo(1M) を使用するとテストモジュールを追加できます。これは、ドライバのデバッグや負荷テストを行うための便利な手法です。一般に、これらのコマンドは通常運用時には必要ありません。必要なモジュールのロードや未使用モジュールのアンロードは、カーネルが自動的に行うからです。情報の提供と制御の設定を行うため、moddebug カーネル変数はこれらのコマンドと連携して動作します。
あるモジュールを強制的にメモリー内にロードするには、modload(1M) を使用します。modload コマンドは、ドライバのロード時にそのドライバに未解決の参照が含まれていないことを確認します。ドライバのロードは必ずしも、そのドライバが接続可能であることを意味するわけではありません。ドライバのロードが成功すると、ドライバの _info(9E) エントリポイントが呼び出されます。attach() エントリポイントは、必ずしも呼び出されるわけではありません。
ドライバがロードされたことを確認するには、modinfo(1M) を使用します。
例 23-3 modinfo によるロード済みドライバの確認
$ modinfo Id Loadaddr Size Info Rev Module Name 6 101b6000 732 - 1 obpsym (OBP symbol callbacks) 7 101b65bd 1acd0 226 1 rpcmod (RPC syscall) 7 101b65bd 1acd0 226 1 rpcmod (32-bit RPC syscall) 7 101b65bd 1acd0 1 1 rpcmod (rpc interface str mod) 8 101ce8dd 74600 0 1 ip (IP STREAMS module) 8 101ce8dd 74600 3 1 ip (IP STREAMS device) ... $ modinfo | grep mydriver 169 781a8d78 13fb 0 1 mydriver (Test Driver 1.5)
info フィールドの番号は、そのドライバ用に選択されたメジャー番号です。モジュール ID を利用できる場合は、modunload(1M) コマンドを使用してモジュールをアンロードできます。モジュール ID は、modinfo 出力の左側の列に表示されます。
modunload の発行後に予期したとおりにドライバがアンロードされない場合がありますが、これはドライバがビジー状態であると判定されたためです。この状況が発生するのは、ドライバが実際にビジー状態であるか、または detach エントリポイントの実装が間違っているために、ドライバの detach(9E) が失敗した場合です。
現時点で使用されていないすべてのモジュールをメモリーから削除するには、モジュール ID に 0 を指定して modunload(1M) を実行します。
# modunload -i 0
moddebug カーネル変数は、モジュールのロード処理を制御します。moddebug の使用可能な値は次のとおりです。
モジュールのロードまたはアンロード時にコンソールにメッセージを出力します。
より詳しいエラーメッセージを提供します。
ロードまたはアンロード時に、アドレスやサイズを含めるなど、より詳しい情報を出力します。
ドライバの自動アンロードを行いません。システムリソースが少なくなっても、システムがデバイスドライバのアンロードを試みません。
ストリームの自動アンロードを行いません。システムリソースが少なくなっても、システムが STREAMS モジュールのアンロードを試みません。
すべてのタイプのカーネルモジュールの自動アンロードを行いません。
kmdb を使用して実行する場合、各モジュールの _init() ルーチンが呼び出される前に、moddebug によってブレークポイントが実行され、kmdb への復帰がただちに発生します。また、この設定ではモジュールの _info() および _fini() ルーチンの実行時に追加のデバッグメッセージが生成されます。
kmem_flags カーネル変数は、カーネルのメモリーアロケータのデバッグ機能を有効化します。アロケータのデバッグ機能を有効化するには、kmem_flags を 0xf に設定します。これらの機能には、次のコード条件を検出するための実行時チェックが含まれます。
バッファー解放後のバッファーへの書き込み
メモリー初期化前のメモリーの使用
バッファーの限度を超える書き込み
カーネルメモリーアロケータを使用してそのような問題を解析する方法については、『Oracle Solaris Modular Debugger Guide 』を参照してください。
注 - kmem_flags を 0xf に設定した状態でテストや開発を行うと、潜在的なメモリー破壊バグの検出が容易になる可能性があります。kmem_flags を 0xf に設定するとカーネルメモリーアロケータの内部動作が変化するため、kmem_flags を使用しない状態でも完全なテストを実施するべきです。
ドライバのバグにより、システムがブートできなくなる場合があります。このセクションで説明するように、予防策を実施しておくことで、このようなイベントが発生した場合でもシステムの再インストールを回避できます。
多数のドライバ関連システムファイルを再構築することは、不可能でないにしても非常に困難です。ドライバのインストール中にドライバが原因でシステムがクラッシュすると、/etc/name_to_major、/etc/driver_aliases、/etc/driver_classes、/etc/minor_perm などのファイルが破壊される可能性があります。add_drv(1M) のマニュアルページを参照してください。
テストマシンが適切な構成になったら、安全のために、beadm(1M) コマンドを使ってルートファイルシステムのバックアップコピーを取っておきます。/etc/system ファイルの変更を予定している場合には、変更を実施する前にこのファイルのバックアップコピーを作成します。
詳細は、『Oracle Solaris 11.1 ブート環境の作成と管理』の第 4 章「ブート環境の管理」および『Oracle Solaris の管理: 一般的なタスク』の「ZFS ブート環境からのブート (作業マップ)」を参照してください。
システムがネットワークに接続されている場合、テストマシンをサーバーのクライアントとして追加できます。問題が発生した場合には、ネットワークからシステムをブートできます。その後、ローカルディスクをマウントして任意の修正を行えます。Oracle Solaris システムの CD-ROM から直接システムをブートすることもできます。
障害から復旧するためのもう 1 つの方法は、別のブート可能なルートファイルシステムを用意することです。format(1M) を使用して、元のパーティションとまったく同じサイズのパーティションを作成します。次に、dd(1M) を使用して、そのブート可能なルートファイルシステムをコピーします。コピーの完了後、新しいファイルシステムに対して fsck(1M) を実行し、その整合性を確認します。
その後、元のルートパーティションからシステムをブートできなくなったら、バックアップパーティションをブートします。dd(1M) を使用してバックアップパーティションを元のパーティションにコピーします。ルートファイルシステムが破損していないにもかかわらず、システムをブートできないような状況が発生する可能性もあります。たとえば、破損箇所がブートブロックやブートプログラムに限定されていることがあります。そのような場合は、ask (-a) オプションを使用してバックアップパーティションからブートできます。その後、元のファイルシステムをルートファイルシステムとして指定できます。
システムがパニック状態になると、システムはカーネルメモリーのイメージをダンプデバイスに書き込みます。デフォルトでは、もっとも適したスワップデバイスがダンプデバイスになります。このダンプはシステムのクラッシュダンプであり、アプリケーションによって生成されるコアダンプに似ています。パニックが発生したあとのリブート時に、savecore(1M) はダンプデバイス内でクラッシュダンプの存在の有無をチェックします。ダンプが見つかった場合、savecore は、unix.n という名前のカーネルシンボルテーブルのコピーを作成します。次に savecore ユーティリティーは、vmcore.n という名前のコアファイルをコアイメージディレクトリ内にダンプします。デフォルトでは、コアイメージディレクトリは /var/crash/machine_name になります。/var/crash の容量不足によりコアダンプを格納できない場合には、システムによって必要な容量が表示されるものの、実際のダンプの保存が行われません。その後、コアダンプや保存済みカーネルに対して mdb(1) デバッガを使用できます。
Oracle Solaris オペレーティングシステムでは、クラッシュダンプはデフォルトで有効になっています。dumpadm(1M) コマンドは、システムクラッシュダンプを構成するために使用されます。dumpadm コマンドを使用すると、クラッシュダンプが有効になっていることを確認したり、保存されたコアファイルの場所を特定したりできます。
注 - savecore ユーティリティーがファイルシステムをいっぱいにしてしまうのを防ぐことができます。minfree という名前のファイルを、ダンプの保存先となるディレクトリに追加します。savecore の実行後に空き領域として残すキロバイト数を、このファイル内に指定します。十分な容量を確保できない場合、コアファイルは保存されません。
attach(9E) の実行中にドライバがクラッシュすると、/devices および /dev ディレクトリが破損する可能性があります。いずれかのディレクトリが破損した場合にそのディレクトリを再構築するには、システムをブートし、fsck(1M) を実行して破損したルートファイルシステムを修復します。これによって、ルートファイルシステムをマウントできるようになります。/devices および /dev ディレクトリを作成し直すには、devfsadm(1M) を実行し、マウントされたディスク上で /devices ディレクトリを指定します。
次の例は、SPARC システム上の破損したルートファイルシステムを修復する方法を示しています。この例で、破損したディスクは /dev/dsk/c0t3d0s0、代替ブートディスクは /dev/dsk/c0t1d0s0 になっています。
例 23-4 破損したデバイスディレクトリの復旧
ok boot disk1 ... Rebooting with command: boot kernel.test/sparcv9/unix Boot device: /sbus@1f,0/espdma@e,8400000/esp@e,8800000/sd@31,0:a File and \ args: kernel.test/sparcv9/unix ... # fsck /dev/dsk/c0t3d0s0** /dev/dsk/c0t3d0s0 ** Last Mounted on / ** Phase 1 - Check Blocks and Sizes ** Phase 2 - Check Pathnames ** Phase 3 - Check Connectivity ** Phase 4 - Check Reference Counts ** Phase 5 - Check Cyl groups 1478 files, 9922 used, 29261 free (141 frags, 3640 blocks, 0.4% fragmentation) # mount /dev/dsk/c0t3d0s0 /mnt # devfsadm -r /mnt
注 - /devices および /dev ディレクトリを修正すると、システムのほかの部分が壊れたままでも、システムをブートできる可能性があります。そのような修復は、システムを再インストールする前にシステムクラッシュダンプなどの情報を保存するための一時的な修正にすぎません。