| ナビゲーションリンクをスキップ | |
| 印刷ビューの終了 | |
|
デバイスドライバの記述 Oracle Solaris 11.1 Information Library (日本語) |
パート I Oracle Solaris プラットフォーム用デバイスドライバの設計
2. Oracle Solaris カーネルとデバイスツリー
dump() エントリポイントと print() エントリポイント
22. ドライバのコンパイル、ロード、パッケージ化、およびテスト
23. デバイスドライバのデバッグ、テスト、およびチューニング
このセクションでは、ブロックデバイスドライバ内の open() 関数と close() 関数のエントリポイントについて説明します。open(9E) と close(9E) の詳細については、第 15 章文字デバイスのドライバを参照してください。
open(9E) エントリポイントは、指定されたデバイスへのアクセスを取得するために使用されます。ブロックドライバの open(9E) ルーチンは、ユーザースレッドがマイナーデバイスに関連付けられたブロック型特殊ファイルに対して open(2) または mount(2) システムコールを発行したとき、または階層化ドライバが open(9E) を呼び出したときに呼び出されます。詳細については、「ファイル入出力」を参照してください。
open() エントリポイントは、次の条件を確認します。
デバイスを開くことができる。つまり、デバイスがオンラインで、準備ができている。
要求どおりにデバイスを開くことができる。デバイスがこの操作をサポートしている。デバイスの現在の状態が要求と競合していない。
呼び出し元がデバイスを開くためのアクセス権を持っている。
次の例は、ブロックドライバの open(9E) エントリポイントを示しています。
例 16-2 ブロックドライバの open(9E) ルーチン
static int
xxopen(dev_t *devp, int flags, int otyp, cred_t *credp)
{
minor_t instance;
struct xxstate *xsp;
instance = getminor(*devp);
xsp = ddi_get_soft_state(statep, instance);
if (xsp == NULL)
return (ENXIO);
mutex_enter(&xsp->mu);
/*
* only honor FEXCL. If a regular open or a layered open
* is still outstanding on the device, the exclusive open
* must fail.
*/
if ((flags & FEXCL) && (xsp->open || xsp->nlayered)) {
mutex_exit(&xsp->mu);
return (EAGAIN);
}
switch (otyp) {
case OTYP_LYR:
xsp->nlayered++;
break;
case OTYP_BLK:
xsp->open = 1;
break;
default:
mutex_exit(&xsp->mu);
return (EINVAL);
}
mutex_exit(&xsp->mu);
return (0);
}
otyp 引数は、デバイスに対するオープンのタイプを指定するために使用されます。OTYP_BLK は、ブロックデバイスの標準的なオープンのタイプです。otyp が OTYP_BLK に設定されている場合は、デバイスを複数回開くことができます。close(9E) は、デバイスに対するタイプ OTYP_BLK の最後のクローズが実行されるときに 1 回だけ呼び出されます。デバイスが階層化デバイスとして使用されている場合、otyp は OTYP_LYR に設定されます。階層化ドライバは、タイプ OTYP_LYR のすべてのオープンに対してタイプ OTYP_LYR の対応するクローズを発行します。この例ではオープンの各タイプを常時監視しているため、ドライバはデバイスがいつ close(9E) で使用されていないかを判定できます。
close(9E) エントリポイントは、1 つの例外を除いて open(9E) と同じ引数を使用します。dev はデバイス番号であり、デバイス番号へのポインタではありません。
close() ルーチンは、open(9E) エントリポイントについての説明と同じ方法で otyp を確認します。次の例では、close() は、実際にデバイスをいつ閉じることができるかを判定する必要があります。閉じる操作は、ブロックのオープンと階層化されたオープンの数によって影響を受けます。
例 16-3 ブロックデバイスの close(9E) ルーチン
static int
xxclose(dev_t dev, int flag, int otyp, cred_t *credp)
{
minor_t instance;
struct xxstate *xsp;
instance = getminor(dev);
xsp = ddi_get_soft_state(statep, instance);
if (xsp == NULL)
return (ENXIO);
mutex_enter(&xsp->mu);
switch (otyp) {
case OTYP_LYR:
xsp->nlayered--;
break;
case OTYP_BLK:
xsp->open = 0;
break;
default:
mutex_exit(&xsp->mu);
return (EINVAL);
}
if (xsp->open || xsp->nlayered) {
/* not done yet */
mutex_exit(&xsp->mu);
return (0);
}
/* cleanup (rewind tape, free memory, etc.) */
/* wait for I/O to drain */
mutex_exit(&xsp->mu);
return (0);
}
strategy(9E) エントリポイントは、ブロックデバイスとの間でのデータバッファーの読み取りと書き込みのために使用されます。strategy という名前は、このエントリポイントによって、デバイスへの要求を順序付けるための何らかの最適な方針が実装される可能性がある点を指しています。
strategy(9E) は、一度に 1 つの要求を処理する、つまり、同期転送を行うように記述できます。strategy() はまた、非同期転送のように、デバイスへの複数の要求をキューに入れるように記述することもできます。これらの方法を選択する場合は、デバイスの機能や制限事項を考慮に入れるべきです。
strategy(9E) ルーチンには、buf(9S) 構造体へのポインタが渡されます。この構造体には転送要求を記述しますが、復帰したときにはステータス情報が含まれています。buf(9S) と strategy(9E) が、ブロックデバイス操作の焦点です。
ブロックドライバには、次の buf 構造体メンバーが重要です。
int b_flags; /* Buffer status */
struct buf *av_forw; /* Driver work list link */
struct buf *av_back; /* Driver work list link */
size_t b_bcount; /* # of bytes to transfer */
union {
caddr_t b_addr; /* Buffer's virtual address */
} b_un;
daddr_t b_blkno; /* Block number on device */
diskaddr_t b_lblkno; /* Expanded block number on device */
size_t b_resid; /* # of bytes not transferred after error */
int b_error; /* Expanded error field */
void *b_private; /* "opaque" driver private area */
dev_t b_edev; /* expanded dev field */
各表記の意味は次のとおりです。
ドライバでバッファーのリストを管理するためにドライバが使用できるポインタ。av_forw ポインタと av_back ポインタの説明については、「非同期データ転送 (ブロックドライバ)」を参照してください。
デバイスによって転送されるバイト数を指定します。
データバッファーのカーネル仮想アドレス。bp_mapin(9F) の呼び出しのあとでのみ有効です。
512 バイトの DEV_BSIZE の単位で表された、データ転送用にデバイス上に存在する、先頭の 32 ビット論理ブロック番号。ドライバは、b_blkno と b_lblkno の両方ではなく、このどちらかを使用します。
512 バイトの DEV_BSIZE の単位で表された、データ転送用にデバイス上に存在する、先頭の 64 ビット論理ブロック番号。ドライバは、b_blkno と b_lblkno の両方ではなく、このどちらかを使用します。
エラーのために転送されなかったバイト数を示すためにドライバによって設定されます。b_resid の設定の例については、例 16-7 を参照してください。b_resid メンバーはオーバーロードされます。b_resid はまた、disksort(9F) によっても使用されます。
転送エラーが発生した場合、ドライバによってエラー番号が設定されます。b_error は、b_flags の B_ERROR ビットとともに設定されます。エラー値の詳細については、Intro(9E) のマニュアルページを参照してください。ドライバは、b_error を直接設定するのではなく、bioerror(9F) を使用します。
buf 構造体のステータスと転送の属性を含むフラグ。B_READ が設定されている場合、buf 構造体は、デバイスからメモリーへの転送を示します。それ以外の場合、この構造体はメモリーからデバイスへの転送を示します。データ転送中にドライバでエラーが発生した場合、ドライバは、b_flags メンバーの B_ERROR フィールドを設定します。さらに、ドライバは、b_error でより具体的なエラー値を提供します。ドライバは、B_ERROR を設定するのではなく、bioerror(9F) を使用します。
![]() | 注意 - ドライバが b_flags をクリアしないようにしてください。 |
ドライバの非公開データを格納するために、ドライバによって排他的に使用されます。
転送で使用されたデバイスのデバイス番号が含まれています。
デバイスドライバの strategy(9E) ルーチンには、buf 構造体ポインタを渡すことができます。ただし、b_un.b_addr によって参照されるデータバッファーは、必ずしもカーネルのアドレス空間内にマッピングされるわけではありません。そのため、ドライバはデータに直接アクセスできません。ほとんどのブロック指向のデバイスは DMA 機能を備えているため、データバッファーに直接アクセスする必要はありません。代わりに、これらのデバイスは DMA マッピングルーチンを使用して、そのデバイスの DMA エンジンがデータ転送を実行できるようにします。DMA の使用の詳細については、第 9 章ダイレクトメモリーアクセス (DMA)を参照してください。
ドライバがデータバッファーに直接アクセスする必要がある場合、そのドライバはまず、bp_mapin(9F) を使用してそのバッファーをカーネルのアドレス空間内にマッピングする必要があります。ドライバがそのデータに直接アクセスする必要がなくなった場合は、bp_mapout(9F) を使用するべきです。
![]() | 注意 - bp_mapout(9F) は、そのデバイスドライバによって割り当てられ、かつ所有されているバッファーに対してのみ呼び出すべきです。ファイルシステムなどの、strategy(9E) エントリポイントを介してドライバに渡されたバッファーに対しては bp_mapout() を呼び出してはいけません。bp_mapin(9F) は参照カウントを保持しません。bp_mapout(9F) は、デバイスドライバ上のレイヤーが依存している可能性のあるカーネルマッピングをすべて削除します。 |