1

カーネルがハード ドライブからブロックを読み取ろうとすると、デバイス ドライバーによって処理されるソフトウェア割り込みが送信されます。デバイス ドライバーが要求を処理する作業をワーク キューを介して上半分と下半分に分割する場合、下半分が完了するまでデータが使用できないことをカーネルはどのように認識しますか?

言い換えれば、ドライバーが必要なブロックをフェッチして、提供されたバッファーにまだコピーしていないことを、カーネルはどのようにして知るのでしょうか?

明らかに、上位半分が実行を終了して戻ったときにデータがすぐに利用できるとカーネルが期待している場合、カーネルは不要なデータを読み取る可能性があります。

4

1 に答える 1

3

ブロック デバイス ドライバーの 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、メジャー番号、最初のマイナー番号、およびその他のファイル操作などの他の情報があります ( openreleaseioctlおよびその他ですが、キャラクター デバイスには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 から変更されたものもあります。

于 2013-09-11T15:40:24.533 に答える