ブロック デバイス ドライバーの API は Linux の登場以来何度か変更されていますが、現在では基本的に次のようになっています。
初期化関数は を呼び出しblk_init_queue
、リクエスト コールバックとそのキューのオプションのロックを渡します。
struct request_queue *q;
q = blk_init_queue(my_request_cb, &my_dev->lock);
my_request_cb
そのブロックデバイスのすべての I/O を処理するコールバックです。I/O 要求はこのキューにプッシュされmy_request_cb
、カーネル ブロック ドライバー レイヤーが決定したときに、それらを次々に処理するために呼び出されます。次に、このキューがディスクに追加されます。
struct gendisk *disk;
disk->queue = q;
次に、ディスクがシステムに追加されます。
add_disk(disk);
にはdisk
、メジャー番号、最初のマイナー番号、およびその他のファイル操作などの他の情報があります ( open
、release
、ioctl
およびその他ですが、キャラクター デバイスにはread
ありません)。write
現在、my_request_cb
いつでも呼び出すことができ、ブロック デバイスで読み取り/書き込みを開始したプロセスのコンテキストから必ずしも呼び出されるとは限りません。この呼び出しはカーネルによって非同期です。
この関数は次のように宣言されます。
static void my_request_cb(struct request_queue *q);
キューq
には、このブロック デバイスへの要求の順序付きリストが含まれます。次に、関数は次のリクエストを確認します ( blk_fetch_request(q)
)。リクエストを完了としてマークするために、呼び出しますblk_end_request_all
(状況に応じて、他のバリエーションが存在します)。
そして、これが私があなたの質問に答える場所です.カーネルは、ドライバーがblk_end_request_all
この要求に対してまたは同様の関数を呼び出したときに、特定のブロックデバイス要求が行われたことを認識しています. ドライバーは、 内で要求を終了する必要はありませんmy_request_cb
。たとえば、DMA 転送を開始し、要求を再キューイングし、他を無視し、完了した DMA 転送の割り込みがアサートされた場合にのみ、それを終了し、効果的にカーネルにそのことを伝えます。この特定の読み取り/書き込み操作が完了します。
LDD3/chapter 16が役に立ちますが、2.6 から変更されたものもあります。