SGLIST(9) | FreeBSD Kernel Developer's Manual | SGLIST(9) |
名称
sglist, sglist_alloc, sglist_append, sglist_append_mbuf, sglist_append_phys, sglist_append_uio, sglist_append_user, sglist_build, sglist_clone, sglist_consume_uio, sglist_count, sglist_free, sglist_hold, sglist_init, sglist_join, sglist_length, sglist_reset, sglist_slice, sglist_split — 物理的なメモリアドレスの分散/集中リストを管理する書式
#include < sys/types.h>#include < sys/sglist.h>
struct sglist *
sglist_alloc( int nsegs, int mflags);
int
sglist_append( struct sglist *sg, void *buf, size_t len);
int
sglist_append_mbuf( struct sglist *sg, struct mbuf *m);
int
sglist_append_phys( struct sglist *sg, vm_paddr_t paddr, size_t len);
int
sglist_append_uio( struct sglist *sg, struct uio *uio);
int
sglist_append_user( struct sglist *sg, void *buf, size_t len, struct thread *td);
struct sglist *
sglist_build( void *buf, size_t len, int mflags);
struct sglist *
sglist_clone( struct sglist *sg, int mflags);
int
sglist_consume_uio( struct sglist *sg, struct uio *uio, size_t resid);
int
sglist_count( void *buf, size_t len);
void
sglist_free( struct sglist *sg);
struct sglist *
sglist_hold( struct sglist *sg);
void
sglist_init( struct sglist *sg, int maxsegs, struct sglist_seg *segs);
int
sglist_join( struct sglist *first, struct sglist *second);
size_t
sglist_length( struct sglist *sg);
void
sglist_reset( struct sglist *sg);
int
sglist_slice( struct sglist *original, struct sglist **slice, size_t offset, size_t length, int mflags);
int
sglist_split( struct sglist *original, struct sglist **head, size_t length, int mflags);
解説
sglist API は、物理アドレス範囲を管理します。各リストは、1 つ以上の要素を含んでいます。各要素は、最初の物理アドレスと長さを含んでいます。分散/集中リストは、それらが共有されている間、読み込み専用です。存在する分散/集中リストを変更したくて、リストの唯一の参照を保持していないなら、既存のリストを変更する代わりに新しいリストを作成するべきです。各分散/集中リストのオブジェクトは、参照カウントを含みます。新しいリストは、単一の参照で作成されます。新しい参照は、 sglist_hold を呼び出すことによって獲得され、 sglist_free を呼び出すことによって解放されます。
リストの割り付けと初期値設定
各 sglist オブジェクトは、ヘッダ構造と分散/集中リスト要素の可変長の配列から成ります。 sglist_alloc 関数は、ヘッダと nsegs 分散/集中リスト要素を含む新しいリストを割り付けます。 M_NOWAIT または M_WAITOK のいずれかのために mflags 引数を設定することができます。sglist_count 関数は、単一のカーネル仮想アドレス範囲によってマップされた物理アドレス範囲について記述するために必要な分散/集中リスト要素の数を返します。カーネル仮想アドレス範囲は、 buf で始まる len バイト長です。
sglist_build 関数は、単一のカーネル仮想アドレス範囲によってマップされた物理アドレス範囲を記述する新しい分散/集中リストオブジェクトを割り付けます。カーネル仮想アドレス範囲は、 buf で始まる len バイト長です。 M_NOWAIT または M_WAITOK のいずれかのために mflags 引数を設定することができます。
sglist_clone 関数は、存在する分散/集中リストオブジェクト sg のコピーを返します。 M_NOWAIT または M_WAITOK のいずれかのために mflags 引数を設定することができます。それを変更する前に分散/集中リストのプライベートなコピーを取得するためにこれを使用することができます。
sglist_init 関数は、分散/集中リストヘッダを初期化します。 sg によって指されたヘッダは、 segs によって指された maxsegs 分散/集中リスト要素の配列を管理するために初期化されます。記憶域が sglist_alloc によって提供されない分散/集中リストヘッダを初期化するためにこれを使用することができます。その場合には、呼び出し側は、それ自体の参照を解放するために sglist_free と呼び出すべきでなく、 sg と segs のための記憶域を解放する前に、リストへの他のすべての参照が落とされることを確実にするために責任があります。
分散/集中リストの構築
sglist API は、1 つ以上のオブジェクトを記述するために分散/集中リストを構築するためのいくつかのルーチンを提供しています。特に、分散/集中リストの終りにオブジェクトによって記述された物理アドレス範囲を追加するのために sglist_append ルーチンファミリを使用することができます。これらのすべてのルーチンは、成功すれば 0 を返し、失敗すればエラーを返します。アドレスの範囲を分散/集中リスト追加する要求が失敗するなら、分散/集中リストは、変更されないままとなります。sglist_append 関数は、分散/集中リスト sg に、単一のカーネル仮想アドレス範囲によって記述された物理アドレス範囲を追加します。カーネル仮想アドレス範囲は、 buf で始まる len バイト長です。
sglist_append_mbuf 関数は、分散/集中リスト sg に全体の mbuf チェーン m によって記述された物理アドレス範囲を追加します。
sglist_append_phys 関数は、分散/集中リスト sg に単一の物理アドレス範囲を追加します。物理アドレス範囲は、 paddr で始まる len バイト長です。
sglist_append_uio 関数は、分散/集中リスト sg に uio(9) オブジェクトによって記述された物理アドレス範囲を追加します。 I/O 要求に裏打ちされたページが、 sg の存続期間のために結びつけられることを保証することは、呼び出し側の責任であることに注意してください。また、このルーチンは、 uio を変更しないことに注意してください。
sglist_append_user 関数は、分散/集中リスト sg に単一ユーザの仮想アドレス範囲によって記述された物理アドレス範囲を追加します。ユーザ仮想アドレス範囲は、スレッド td のアドレス空間に相対的です。それは、 buf で始まる len バイト長です。ユーザバッファを裏打ちするページが、 sg の存続期間のために結びつけられることを保証することは、呼び出し側の責任であることに注意してください。
sglist_consume_uio 関数は、 sglist_append_uio の変異型です。 sglist_append_uio のように、それは分散/集中リスト sg に uio によって記述された物理アドレス範囲を追加します。しかしながら、 sglist_append_uio と異なって、 sglist_consume_uio は、アドレスの範囲が uiomove(9) を呼び出すこと同様に処理されていることを示すために I/O 要求を変更します。このルーチンは、 resid 合計バイトの長さまで記述される範囲だけを追加します。分散/集中リストで利用可能なセグメントが、 resid バイトが処理される前に、使い果たされるなら、 uio 構造は、処理されたバイトの実際の数を反映するために更新され、 sglist_consume_io は、成功したことを示すために 0 を返します。事実上、この関数は、部分的な読み込みまたは書き込みを実行します。呼び出し側は、処理されたバイトの実際の数を決定するために sglist_consume_uio を呼び出す前と後ろで、 uio の uio_resid メンバを比較できます。
分散/集中リストの操作
sglist_join 関数は、 first の上に分散/集中リスト second からの物理アドレス範囲を追加し、次に、 second を空のリストにリセットします。それは、成功すれば 0 を返し、失敗すればエラーを返します。sglist_split 関数は、既存の分散/集中リストを 2 つのリストに分割します。リスト original によって記述された最初の length バイトは、新しいリスト *head に移動されます。 original が length バイトより小さい合計アドレスの範囲を記述するなら、アドレスの範囲のすべては、 *head の新しいリストに移動され、 original は、空のリストになります。呼び出し側は、 *head 中の既存の分散/集中リストを提供します。そうであるなら、リストは、空でなければなりません。そうでなければ、呼び出し側は、 *head を NULL に設定できます、その場合、新しい分散/集中リストが割り付けられます。その場合には、 M_NOWAIT または M_WAITOK のいずれかのために mflags を設定することができます。 original のリストがこの呼び出しによって変更されるので、他の参照がないプライベートなリストでなければならないことに注意してください。 sglist_split 関数は、成功すれば 0 を返し、失敗すればエラーを返します。
sglist_slice 関数は、既存の分散/集中リスト original の部分的な範囲から新しい分散/集中リストを生成します。抽出する部分的な範囲は、 offset と length パラメータによって指定されます。新しい分散/集中リストは、 *slice に格納されます。 sglist_join の head と同様に、呼び出し側は、空の分散/集中リストを提供するか、または *slice を NULL に設定します、その場合、 sglist_slice は、 mflags に従って新しいリストを割り付けます。 sglist_split と異なって、 sglist_slice は、 original を変更しません、そして、プライベートなリストとする必要はありません。 sglist_split 関数は、成功すれば 0 を返し、失敗すればエラーを返します。
その他のルーチン
sglist_reset 関数は、もはや、任意のアドレス範囲をマップできないように、分散/集中リスト sg をクリアします。これによって、複数の要求のために単一の分散/集中リストオブジェクトを再利用することができます。sglist_length 関数は、分散/集中リスト sg によって記述された物理アドレス範囲の合計の長さを返します。
戻り値
sglist_alloc, sglist_build と sglist_clone 関数は、成功すれば新しい分散/集中リストを返し、失敗すれば、 NULL を返します。sglist_append 関数ファミリと sglist_consume_uio, sglist_join, sglist_slice と sglist_split 関数は、成功すれば 0 を返し、失敗すればエラーを返します。
sglist_count 関数は、分散/集中リスト要素のカウントを返します。
sglist_length 関数は、分散/集中リストによって記述されたアドレス空間のバイト単位のカウントを返します。
エラー
sglist_append 関数は、失敗すれば、次のエラーを返します:- [ EINVAL]
- 分散/集中リストに、セグメントがありません。
- [ EFBIG]
- 指定された物理アドレス範囲を追加するための分散/集中リストに十分に利用可能なセグメントがありません。
sglist_consume_uio 関数は、失敗すれば、次のエラーを返します:
- [ EINVAL]
- 分散/集中リストに、セグメントがありません。
sglist_join 関数は、失敗すれば、次のエラーを返します:
- [ EFBIG]
- second からの物理アドレス範囲を追加するために分散/集中リスト first に十分に利用可能なセグメントがありません。
sglist_slice 関数は、失敗すれば、次のエラーを返します:
- [ EINVAL]
- original の分散/集中リストが、要求された部分的な範囲をカバーするための十分なアドレス空間を記述していません。
- [ EINVAL]
- 呼び出し側によって供給にされた *slice の分散/集中リストが空でありません。
- [ ENOMEM]
- mflags の M_NOWAIT 設定がある新しい分散/集中リストを割り付ける試みが、失敗しました。
- [ EFBIG]
- 要求された物理アドレス範囲を記述するために呼び出し側によって供給にされた *slice の分散/集中リストに十分に利用可能なセグメントがありません。
sglist_split 関数は、失敗すれば、次のエラーを返します:
- [ EDOOFUS]
- original の分散/集中リストには 2 つ以上の参照があります。
- [ EINVAL]
- 呼び出し側によって供給にされた *head の分散/集中リストが、空でありません。
- [ ENOMEM]
- mflags の M_NOWAIT 設定がある新しい分散/集中リストを割り付ける試みが、失敗しました。
- [ EFBIG]
- 要求された物理アドレス範囲を記述するために呼び出し側によって供給にされた *head の分散/集中リストに十分に利用可能なセグメントがありません。
歴史
この API は、 FreeBSD 8.0 ではじめて導入されました。May 15, 2009 | FreeBSD |