Oracle® Solaris 11.2 デバイスドライバの記述

印刷ビューの終了

更新: 2014 年 9 月
 
 

ベクトル化された入出力

文字ドライバでは、転送は uio (9S) 構造体で記述されます。uio (9S) 構造体には、転送の方向とサイズに関する情報に加え、転送の一方の端のためのバッファーの配列が含まれています。もう一方の端はデバイスです。

uio(9S) 構造体には、次のメンバーが含まれています。

iovec_t       *uio_iov;       /* base address of the iovec */
                              /* buffer description array */
int           uio_iovcnt;     /* the number of iovec structures */
off_t         uio_offset;     /* 32-bit offset into file where */
                              /* data is transferred from or to */
offset_t      uio_loffset;    /* 64-bit offset into file where */
                              /* data is transferred from or to */
uio_seg_t     uio_segflg;     /* identifies the type of I/O transfer */
                              /* UIO_SYSSPACE:  kernel <-> kernel */
                              /* UIO_USERSPACE: kernel <-> user */
short         uio_fmode;      /* file mode flags (not driver setTable) */
daddr_t       uio_limit;      /* 32-bit ulimit for file (maximum */
                              /* block offset). not driver settable. */
diskaddr_t    uio_llimit;     /* 64-bit ulimit for file (maximum block */
                              /* block offset). not driver settable. */
int           uio_resid;      /* amount (in bytes) not */
                              /* transferred on completion */

uio (9S) 構造体は、ドライバの read(9E) エントリポイントと write (9E) エントリポイントに渡されます。この構造体は、いわゆる gather 書き込みおよびscatter 読み取りをサポートするために一般化されています。デバイスに書き込む場合、書き込まれるデータバッファーがアプリケーションメモリー内で隣接している必要はありません。同様に、デバイスからメモリーに転送されるデータは隣接ストリームで受信されますが、アプリケーションメモリーの不連続領域に格納できます。scatter/gather 入出力の詳細については、readv (2)writev (2)pread (2)、および pwrite (2) のマニュアルページを参照してください。

各バッファーは、iovec (9S) 構造体で記述されます。この構造体には、データ領域へのポインタと転送されるバイト数が含まれています。

caddr_t    iov_base;    /* address of buffer */
int        iov_len;     /* amount to transfer */

uio 構造体には、 iovec(9S) 構造体の配列へのポインタが含まれています。この配列の基底アドレスは uio_iov 内に保持されており、要素の数は uio_iovcnt 内に格納されています。

uio_offset フィールドには、アプリケーションが転送を開始する必要がある位置として、デバイスへの 32 ビットオフセットが含まれています。uio_loffset は、64 ビットのファイルオフセットのために使用されます。デバイスがオフセットの概念をサポートしていない場合は、これらのフィールドを安全に無視できます。ドライバは、uio_offset と uio_loffset の両方ではなく、このどちらかを解釈する必要があります。ドライバが cb_ops(9S) 構造体内の D_64BIT フラグを設定した場合、そのドライバは uio_loffset を使用します。

uio_resid フィールドは、開始時は転送されるバイト数、つまり、uio_iov 内のすべての iov_len フィールドの合計に設定されます。このフィールドは、戻る前にドライバによって、転送されなかったバイト数に設定される必要があります read(2) システムコールと write (2) システムコールは、 read(9E) エントリポイントと write (9E) エントリポイントからの戻り値を使用して、転送の失敗を判定します。失敗が発生した場合、これらのルーチンは -1 を返します。戻り値が成功を示している場合、システムコールは、要求されたバイト数から uio_resid を引いた値を返します。uio_resid がドライバによって変更されない場合、 read(2)write (2) の呼び出しは 0 を返します。すべてのデータが転送されたにもかかわらず、0 の戻り値によってファイルの終わりが示されます。

サポートルーチン uiomove(9F)physio (9F)、および aphysio (9F) は、uio (9S) 構造体を直接更新します。これらのサポートルーチンは、データ転送を考慮してデバイスオフセットを更新します。ドライバが、位置の概念を使用するシーク可能なデバイスで使用されている場合は、uio_offset フィールドと uio_loffset フィールドのどちらも調整する必要はありません。この方法でデバイスに対して実行される入出力は、uio_offset または uio_loffset の取り得る最大値によって制約されます。このような使用法の例として、ディスク上の raw 入出力があります。

デバイスに位置の概念がない場合、ドライバは次の手順を実行できます。

  1. uio_offset または uio_loffset を保存します。

  2. 入出力操作を実行します。

  3. uio_offset または uio_loffset をフィールドの初期値に復元します。

この方法でデバイスに対して実行される入出力は、uio_offset または uio_loffset の取り得る最大値によって制約されません。このような使用法の例として、シリアル回線上の入出力があります。

次の例は、read(9E) 関数で uio_loffset を保持するための 1 つの方法を示しています。

static int
xxread(dev_t dev, struct uio *uio_p, cred_t *cred_p)
{
    offset_t off;
    /* ... */
    off = uio_p->uio_loffset;  /* save the offset */
    /* do the transfer */
    uio_p->uio_loffset = off;  /* restore it */
}