BUF(9) FreeBSD カーネル開発者マニュアル BUF(9)
名称
buf − FreeBSD の VM システムで使用されたカーネルバッファ入出力機構 |
解説
カーネルは、(主にファイルシステムの) デバイスおよびデバイス入出力によって 使用されるための、まったくバラバラかもしれない仮想メモリページを連続した KVM にマップすることを可能にする、バッファキャッシュの KVM の抽象概念を実 装します。この抽象概念は、DEV_BSIZE (通常 512) から数ページ以上のまでのブ ロックサイズをサポートします。また、NFS によって使用されるための現在は ハードコーディングされている、相対的に基本的なバイト粒度の正当な範囲およ びダーティな範囲も、サポートします。 VM バッファの抽象概念を実装している コードは、大部分は /usr/src/sys/kern/vfs_bio.c に集約されています。 バッファポインタ (struct buf) を取り扱うときに憶えておくべき最も重要なこ との 1 つは、下層のページがバッファキャッシュから直接的にマップされるとい うことです。もっとも UFS のような幾つかのファイルシステムがファイルのフラ グメントを取り扱うときには少しコピーをしなければならないのですが、厳密な 意味でのこの機構では、データのコピーは発生しません。憶えておくべき最も重 要なことの 2 番目は、下層のページマッピングのため、buf の中の b_data ベー スポインタは常に *ブロック* で整列されるのではなく、*ページ* で整列される ということです。ある b_offset および b_size を表現する VM バッファを持つ もきには、そのバッファの実際の開始は (b_data + (b_offset & PAGE_MASK)) で、ちょうど b_data ではありません。最後に、VM システムの中核のバッファ キャッシュは、DEV_BSIZE の塊の中のページのための、正当およびダーティビッ ト (m->valid, m->dirty) をサポートします。従って、4096 バイトのページサイ ズのハードウェアを持つプラットホームは、8 個の正当ビットおよび 8 個のダー ティビットを持ちます。これらのビットは一般的に、ページを裏打ちするそのデ バイスのデバイスブロックサイズに基づいたグループ単位で、セットおよびクリ アされます。完全なページの価値は、しばしば VM_PAGE_BITS_ALL ビットマスク (すなわち、ハードウェアのページサイズが 4096 であれば 0xFF) を使用するこ とに当たります。 VM バッファはバイト粒度のダーティな範囲および正当な範囲の追跡も維持しま す。この機能は通常 NFS サブシステムによってのみ使用されます。 VM バッファ の内部に DEV_BSIZE の正当/ダーティの粒度を持っているので、本当に、一体ど うして使用されているのか自信を持って言えません。バッファをダーティにする 操作が ’穴’ を生成する場合には、ダーティな範囲がその穴を覆うように広がり ます。バッファを正当化する操作が ’穴’ を生成する場合には、バイト粒度の正 当な範囲がそのまま残され、新しい拡張の評価は行なわれません。従って、バイ ト粒度の抽象概念全体は悪いハックだと考えられます。それを徹底的に除去でき るのであれば、快適なことでしょう。 VM バッファは、カーネルが直接的に (vnode,b_offset,b_size) に関連付けられ たデータを操作することを可能にするために、下層の VM キャッシュページを KVM にマップすることが可能です。カーネルは一般的には、バッファがもはや必 要でなくなった時に、VM バッファをアンマップしますが、すでに KVM からアン マップされているにもかかわらず、しばしば実体化された ’struct buf’ 構造体 を、および実体化された bp->b_pages の配列をも保持します。 VM バッファに仕 立てられたページが今にも入出力を受けようとしている場合には、システムは一 般的には、それを KVM からアンマップし、b_pages[] 配列の中のページを bogus_page (偽のページ) と呼ばれる位置目印に置き換えます。その場所の目印 は、関連付けられたページを再捜索するために、全てのカーネルのサブシステム が関連付けられた struct buf を参照することを、強制します。位置目印のハッ クは、ファイルシステムデバイスのようなきわめて複雑なデバイスが、例えば、 ファイルのフラグメントをファイルブロックに再マップするために、下層のペー ジを再マップすることを、可能にするために使用されると確信しています。 VM バッファはカーネル内部の入出力操作を追跡するために使用されます。運の悪 いことに、入出力の実装もハックの対象です。なぜならば、カーネルは物理的な 入出力が実際に始まったときではなく、VFS デバイスに入出力をキューに入れた ときに、下層のページ上のダーティビットをクリアしたいからです。これは、遅 延書き込みを使用するファイルシステムデバイスの内部に混乱を生み出すことが ありえます。なぜならば、実際には未だダーティであるがページを正当であると 目印をつけて終了するからです。注意深く取り扱わない場合には、これらのペー ジは破棄されてしまうことがありえます。それどころか、このハックに関連した かなりの深刻なバグが、2.2.8/3.0 リリースまで修正されませんでした。カーネ ルはこの特殊状態にあるページに位置目印をつけるため、実体化された VM バッ ファ (すなわち struct buf) を使用します。バッファは通常 B_DELWRI フラグが 付けられます。もはやバッファが必要でなくなったときに、通常 B_RELBUF とし てフラグを付けます。下層のページが正当であると目印を付けられている結 果、B_DELWRI|B_RELBUF の組み合わせは、そのバッファは実際には未だダーティ であり、それが実際に解放されることがありうる前に、後援の記憶装置に書込ま れなければならないということを意味すると、解釈されなければなりません。こ の場合で、B_DELWRI が設定されない場合、下層のダーティなページは未だ適切に ダーティであると目印を付けられ、そのバッファは正当/ダーティの状態情報を失 うことなく、完全に解放されることが可能です。 (XXX この状況に配慮して、そ の他のフラグをチェックしなければならないのでしょうか ???) カーネルは VM バッファのデータマップを保持するために、その KVM 空間の一部 を予約します。これは仮想空間 (バッファはバッファキャッシュからマップされ るため) であるにもかかわらず、それを任意に大きく出来ません。なぜならば、 実体化された VM バッファ (struct buf) がバッファキャッシュの中の下層の ページが解放されることを妨げるからです。これはページングシステムの生存を 脅かし得ることです。 |
歴史
buf のマニュアルページは元々 Matthew Dillon が書いて、1998 年 12 月に FreeBSD 3.1 ではじめて登場しました。 FreeBSD 10.0 December 22, 1998 FreeBSD 10.0 |