Go to main content
Oracle® Solaris 11.3 デバイスドライバの記述

印刷ビューの終了

更新: 2016 年 11 月
 
 

デバイスアクセスの制御

このセクションでは、ブロック型デバイスドライバ内の open() 関数と close() 関数のエントリポイントについて説明します。open(9E)close(9E) の詳細については、文字デバイスのドライバを参照してください。

open() エントリポイント (ブロックドライバ)

open(9E) エントリポイントは、指定されたデバイスへのアクセスを取得するために使用されます。ブロックドライバの open(9E) ルーチンは、ユーザースレッドがマイナーデバイスに関連付けられたブロック型特殊ファイルに対して open(2) または mount(2) システムコールを発行したとき、または階層化ドライバが open(9E) を呼び出したときに呼び出されます。詳細については、ファイル入出力を参照してください。

open() エントリポイントは、次の条件を確認します。

  • デバイスを開くことができる。つまり、デバイスがオンラインで、準備ができている。

  • 要求どおりにデバイスを開くことができる。デバイスがこの操作をサポートしている。デバイスの現在の状態が要求と競合していない。

  • 呼び出し元がデバイスを開くためのアクセス権を持っている。

次の例は、ブロックドライバの open(9E) エントリポイントを示しています。

使用例 86  ブロックドライバの 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 は、ブロックデバイスの標準的なオープンのタイプです。otypOTYP_BLK に設定されている場合は、デバイスを複数回開くことができます。close(9E) は、デバイスに対するタイプ OTYP_BLK の最後のクローズが実行されるときに 1 回だけ呼び出されます。デバイスが階層化デバイスとして使用されている場合、otypOTYP_LYR に設定されます。階層化ドライバは、タイプ OTYP_LYR のすべてのオープンに対してタイプ OTYP_LYR の対応するクローズを発行します。この例ではオープンの各タイプを常時監視しているため、ドライバはデバイスがいつ使用されていないかを close(9E) で判定できます。

close() エントリポイント (ブロックドライバ)

close(9E) エントリポイントは、1 つの例外を除いて open(9E) と同じ引数を使用します。dev はデバイス番号であり、デバイス番号へのポインタではありません。

close() ルーチンは、open(9E) エントリポイントについての説明と同じ方法で otyp を確認します。次の例では、close() は、実際にデバイスをいつ閉じることができるかを判定する必要があります。閉じる操作は、ブロックのオープンと階層化されたオープンの数によって影響を受けます。

使用例 87  ブロック型デバイスの 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() エントリポイント

strategy(9E) エントリポイントは、ブロック型デバイスとの間でデータバッファーの読み取りと書き込みのために使用されます。strategy という名前は、このエントリポイントによって、デバイスへの要求を順序付けるための何らかの最適な方針が実装される可能性がある点を指しています。

strategy(9E) は、一度に 1 つの要求を処理する、つまり、同期転送を行うように記述できます。strategy() はまた、非同期転送のように、デバイスへの複数の要求をキューに入れるように記述することもできます。これらの方法を選択する場合は、デバイスの機能や制限事項を考慮に入れるべきです。

strategy(9E) ルーチンには、buf(9S) 構造体へのポインタが渡されます。この構造体には転送要求を記述しますが、復帰したときにはステータス情報が含まれています。buf(9S)strategy(9E) が、ブロック型デバイス操作の焦点です。

buf 構造体

ブロックドライバには、次の 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

ドライバでバッファーのリストを管理するためにドライバが使用できるポインタ。av_forw ポインタと av_back ポインタの説明については、非同期データ転送 (ブロックドライバ)を参照してください。

b_bcount

デバイスによって転送されるバイト数を指定します。

b_un.b_addr

データバッファーのカーネル仮想アドレス。bp_mapin(9F) の呼び出しのあとでのみ有効です。

b_blkno

512 バイトの DEV_BSIZE の単位で表された、データ転送用にデバイス上に存在する、先頭の 32 ビット論理ブロック番号。ドライバは、b_blkno と b_lblkno の両方ではなく、このどちらかを使用します。

b_lblkno

512 バイトの DEV_BSIZE の単位で表された、データ転送用にデバイス上に存在する、先頭の 64 ビット論理ブロック番号。ドライバは、b_blkno と b_lblkno の両方ではなく、このどちらかを使用します。

b_resid

エラーのために転送されなかったバイト数を示すためにドライバによって設定されます。b_resid の設定の例については、使用例 91 を参照してください。b_resid メンバーはオーバーロードされます。b_resid はまた、disksort(9F) によっても使用されます。

b_error

転送エラーが発生した場合、ドライバによってエラー番号が設定されます。b_error は、b_flags の B_ERROR ビットとともに設定されます。エラー値の詳細については、Intro(9E) のマニュアルページを参照してください。ドライバは、b_error を直接設定するのではなく、bioerror(9F) を使用します。

b_flags

buf 構造体のステータスと転送の属性を含むフラグ。B_READ が設定されている場合、buf 構造体は、デバイスからメモリーへの転送を示します。それ以外の場合、この構造体はメモリーからデバイスへの転送を示します。データ転送中にドライバでエラーが発生した場合、ドライバは、b_flags メンバーの B_ERROR フィールドを設定します。さらに、ドライバは、b_error でより具体的なエラー値を提供します。ドライバは、B_ERROR を設定するのではなく、bioerror(9F) を使用します。


Caution

注意  - ドライバが b_flags をクリアしないようにしてください。


b_private

ドライバの非公開データを格納するために、ドライバによって排他的に使用されます。

b_edev

転送で使用されたデバイスのデバイス番号が含まれています。

bp_mapin 構造体

デバイスドライバの strategy(9E) ルーチンには、buf 構造体ポインタを渡すことができます。ただし、b_un.b_addr によって参照されるデータバッファーは、必ずしもカーネルのアドレス空間内にマッピングされるわけではありません。そのため、ドライバはデータに直接アクセスできません。ほとんどのブロック指向のデバイスは DMA 機能を備えているため、データバッファーに直接アクセスする必要はありません。代わりに、これらのデバイスは DMA マッピングルーチンを使用して、そのデバイスの DMA エンジンがデータ転送を実行できるようにします。DMA の使用の詳細については、ダイレクトメモリーアクセス (DMA)を参照してください。

ドライバがデータバッファーに直接アクセスする必要がある場合、そのドライバはまず、bp_mapin(9F) を使用してそのバッファーをカーネルのアドレス空間内にマッピングする必要があります。ドライバがそのデータに直接アクセスする必要がなくなった場合は、bp_mapout(9F) を使用するべきです。


Caution

注意  - bp_mapout(9F) は、そのデバイスドライバによって割り当てられ、かつ所有されているバッファーに対してのみ呼び出すべきです。ファイルシステムなどの、strategy(9E) エントリポイントを介してドライバに渡されたバッファーに対しては bp_mapout() を呼び出してはいけません。bp_mapin(9F) は参照カウントを保持しません。bp_mapout(9F) は、デバイスドライバ上のレイヤーが依存している可能性のあるカーネルマッピングをすべて削除します。