web-dev-qa-db-ja.com

Linuxはブロックデバイスをどのように処理しますか?

今日、私はFreeBSDがブロックデバイスのサポートを完全に削除したことを知りました。決定の彼らの論理的根拠を読んでいる間、私はこれに出くわしました:

ブロックデバイスは、カーネルがキャッシュを提供するディスクデバイスです。このキャッシュにより、ブロックデバイスはほとんど使用できなくなるか、少なくとも危険なほど信頼性が低くなります。キャッシュにより、書き込み操作のシーケンスが並べ替えられ、アプリケーションはいつでも正確なディスクの内容を知ることができなくなります。これにより、ディスク上のデータ構造(ファイルシステム、データベースなど)の予測可能で信頼性の高いクラッシュリカバリが不可能になります。書き込みが遅れる可能性があるため、特定の書き込み操作で書き込みエラーが発生したことをカーネルがアプリケーションに報告する方法はありません。これにより、整合性の問題がさらに悪化します。

https://www.freebsd.org/doc/en_US.ISO8859-1/books/Arch-handbook/driverbasics-block.html から)

ただし、Linuxはほぼ排他的にブロックデバイスを使用していることを私は知っています(ただし、1つはrawデバイスを要求できます)。

では、Linuxはこの引用で言及されている問題をどのように回避するのでしょうか。または、ほとんどのドライバーは代わりにrawデバイスを要求するだけですか?

5
Zigsaz

BSDの人々は本当に筋金入りで、しばしば驚くべきことをします:-)私の意見では、ブロックデバイスレイヤーの削除は問題ではありません(たとえば、nfsには基盤となるブロックデバイスさえありません)が、この理由はブロックに反していませんデバイス、ただし書き込みキャッシュに対して。そして、書き込みキャッシュを削除することは、私の意見では悪いことです。プロセスがディスクに何かを書き込んだ場合、成功しなくなるまでコントロールを取り戻すことはできませんか?

しかし、私は彼らが彼らが何をしているのか知らなかったとは思いません。うまくいけば、誰かが別の答えで彼らの理由を説明するでしょう。

これを明確に説明するために、ファイルシステムがどのように機能するかを説明する必要があります。ファイルシステムドライバは、基本的に、ファイルシステム操作(ディレクトリのオープン、ファイルの作成、読み取り/書き込み、削除など)間およびブロック操作(たとえば、「ページ0xfce2ea31をディスクブロック0xc0deebedに書き出す」)間の変換レイヤーです。

しかし、ブロック操作はその場でハードディスクに到達しません。まず、ブロックキャッシュに移動します。つまり、ファイルシステムがメモリページをディスクに書き込みたい場合は、最初に予約済みのメモリ領域に書き込みます。カーネルのメモリ管理は、最適であると判断した場合、このデータをハードディスクに書き込みます。これにより、さまざまな速度の向上が可能になります。たとえば、ディスクの最初と最後に多くの書き込み操作が発生する場合、カーネルはそれらをそのような方法で組み合わせることができるため、ディスクヘッドの位置をできるだけ変更する必要はほとんどありません。

もう1つの改善点があります。プログラムがファイルに書き込む場合、RAMディスクのように非常に高速な操作が実行されます。もちろん、システムのRAMがいっぱいになるまでは可能です。その後、書き込みキャッシュが空になるのを待つ必要があります。ただし、多くの場合にのみ発生します。一度に書き込み操作(たとえば、大きなファイルをコピーしている場合)。

ファイルシステムの場合、ディスク上で実行されているファイルシステム(つまりブロックデバイス)とそうでないファイルシステム(つまりnfs)の間には大きな違いがあります。 2番目の場合、ブロックがないため、ブロックキャッシュの可能性はありません。彼らの場合、いわゆる「バッファキャッシュ」があります。これは、基本的にはまだキャッシュ(読み取りと書き込みの両方)を意味しますが、メモリブロックではなく、任意のサイズのI/Oフラグメントで構成されます。

はい、Linuxには、ブロックキャッシュメカニズムなしでディスクデバイスの使用を可能にする「生の」ブロックデバイスがあります。しかし、この問題は彼らによって解決されていません。

その代わりに、いわゆる「ジャーナリングファイルシステム」があります。ジャーナリングファイルシステムの場合、ファイルシステムはカーネルに指示する機会があり、どのページを他のページよりも先に書き出す必要があります。ファイルシステムにジャーナリングメカニズムがない場合は、ブロックをディスク(より正確にはブロックキャッシュ)に書き込むだけであり、カーネルは、最適であると判断した場合、実際に実際の書き込み操作を実行します。

ジャーナリングファイルシステムは、すべての書き込み操作が2回発生するかのように想像できます。最初はディスク上の予約領域である「ジャーナル」に、その後は実際の場所に移動します。システムクラッシュまたはディスクエラーが発生した場合、ディスクの最後の損傷していない状態のコンテンツは、ジャーナル上で非常に高速かつ簡単に再構築できます。

ただし、すべての書き込みを2回実行する必要があるため、これにより書き込みパフォーマンスが大幅に低下します。これが、実際にはジャーナリングファイルシステムがはるかに複雑な方法で機能する理由です。ジャーナリングファイルシステムは、さまざまな複雑なデータ構造操作を使用して、このオーバーヘッドをほとんど目に見えないレベルに減らしています。しかし、これは難しいことです。たとえば、ext2に対するext3の主な改善点は、コードサイズを増やしたジャーナリングの追加でした。

Linuxでは、ブロックレイヤーAPIには「バリア」メカニズムがあります。ファイルシステムは、書き込み操作の間に「バリア」を設定できます。バリアとは、データバリアがディスクにのみ書き込まれることを意味しますすべてのデータバリアはすでに書き出されています。ジャーナリングファイルシステムは、バリアメカニズムを使用して、実際の書き込み操作に必要な順序についてブロックレイヤーに指示しています。私が知っているように、彼らは生のデバイスマッピングを使用していません。

FreeBSDがこの事件について何をしているのかわかりません。おそらく、ブロックデバイスを排除するということは、すべてがバッファキャッシュを使用し、ブロックキャッシュを使用しないことを意味します。または、ここに書かれていない何かがあります。ファイルシステムの内部では、* BSDとLinuxの世界の間には非常に大きな違いがあります。