web-dev-qa-db-ja.com

open(2)のO_SYNCフラグとO_DIRECTフラグはどう違うのですか?

O_SYNCおよびO_DIRECTフラグの使用と効果は非常に紛らわしく、プラットフォームによって多少異なるようです。 Linuxのマニュアルページ(例 here を参照)から、O_DIRECTは同期I/Oを提供し、キャッシュ効果を最小限に抑え、ブロックサイズの調整を自分で処理する必要があります。 O_SYNCは、同期I/Oを保証するだけです。どちらもデータがハードディスクのキャッシュに書き込まれることを保証しますが、直接I/O操作はページキャッシュをバイパスするため、プレーンな同期I/Oよりも高速であると考えられます(ただし、FreeBSDのopen(2)のmanページではO_SYNCを使用すると、キャッシュはバイパスされます。 here を参照してください。

O_DIRECTフラグとO_SYNCフラグの違いは何ですか?一部の実装では、O_SYNCの使用を推奨しています| O_DIRECT。どうして?

47
user625070

O_DIRECTのみでは、カーネルがユーザー空間からカーネル空間へのデータのコピーを回避することのみを約束し、代わりにDMA(直接メモリアクセス。可能な場合)。データはキャッシュに入れられません。 。すべてのデータが転送された後にのみ関数が戻るという厳密な保証はありません。

O_SYNCは、すべてのデータがディスクに転送される前に(OSが認識できる限り)呼び出し戻らないを保証します。これは、データがハードディスクの書き込みキャッシュのどこかにないことを保証するものではありませんが、OSが保証できる範囲内です。

O_DIRECT | O_SYNCはこれらの組み合わせ、つまり「DMA +保証」です。

84
Damon

O_DIRECTおよびO_SYNCの役割とデータ整合性への影響についての明確な説明については、このlwnの記事を参照してください。

https://lwn.net/Articles/457667/

8
jmoyer

実際のLinux 2.6では、o_directは同期的です。manページを参照してください。

openのマンページ、それについて2つのセクションがあります。

2.4では保証されません

O_DIRECT(Linux 2.4.10以降)このファイルとの間のI/Oのキャッシュ効果を最小限に抑えます。通常、これはパフォーマンスを低下させますが、アプリケーションが独自のキャッシングを行う場合など、特別な状況で役立ちます。ファイルI/Oは、ユーザースペースバッファーとの間で直接行われます。 O_DIRECTフラグ自体は、データを同期的に転送しようとしますが、データと必要なメタデータが転送されるというO_SYNCフラグの保証はありません。同期I/Oを保証するには、O_DIRECTに加えてO_SYNCを使用する必要があります。詳細については、以下の注を参照してください。

ブロックデバイス用のセマンティック上類似した(非推奨の)インターフェースはraw(8)で説明されています。

しかし2.6では保証されています、をご覧ください

O_DIRECT

O_DIRECTフラグは、ユーザースペースバッファーの長さとアドレス、およびI/Oのファイルオフセットにアライメント制限を課す場合があります。 Linuxでは、アライメントの制限はファイルシステムとカーネルのバージョンによって異なり、まったく存在しない場合があります。ただし、現在のところ、特定のファイルまたはファイルシステムのこれらの制限を発見するための、アプリケーション用のファイルシステムに依存しないインターフェイスはありません。 xfsctl(3)のXFS_IOC_DIOINFO操作など、一部のファイルシステムは、そのための独自のインターフェイスを提供します。

Linux 2.4では、転送サイズ、およびユーザーバッファーとファイルオフセットのアライメントは、すべてファイルシステムの論理ブロックサイズの倍数でなければなりません。 Linux 2.6では、512バイトの境界に合わせれば十分です。

O_DIRECT I/Oは、メモリバッファがプライベートマッピング(つまり、mmap(2)MAP_PRIVATEフラグで作成されたマッピング。これには、ヒープに静的に割り当てられたメモリが含まれる場合、fork(2)割り当てられたバッファ)。そのようなI/Oは、非同期I/Oインターフェース経由で送信された場合でも、プロセス内の別のスレッドから送信された場合でも、fork(2)が呼び出される前に完了する必要があります。そうしないと、親プロセスと子プロセスでデータが破損し、未定義の動作が発生する可能性があります。 O_DIRECT I/OのメモリバッファがMAP_SHAREDフラグを指定したshmat(2)またはmmap(2)を使用して作成された場合、この制限は適用されません。また、メモリバッファがmadvise(2)でMADV_DONTFORKとしてアドバイスされている場合、この制限は適用されず、fork(2)の後に子が使用できないようにします。

O_DIRECTフラグはSGI IRIXで導入されたもので、Linux 2.4と同様のアライメント制限があります。 IRIXには、適切な配置とサイズを照会するためのfcntl(2)呼び出しもあります。 FreeBSD 4.xは同名のフラグを導入しましたが、アライメントの制限はありません。

O_DIRECTサポートは、カーネルバージョン2.4.10のLinuxで追加されました。古いLinuxカーネルは、このフラグを単に無視します。一部のファイルシステムはフラグを実装しない場合があり、open()を使用すると、EINVALで失敗します。

アプリケーションは、O_DIRECTと通常のI/Oを同じファイルに、特に同じファイル内の重複するバイト領域に混在させないでください。この状況でファイルシステムがコヒーレンシの問題を正しく処理した場合でも、全体的なI/Oスループットは、いずれかのモードを単独で使用するよりも遅くなる可能性があります。同様に、アプリケーションは、ファイルのmmap(2)と同じファイルへの直接I/Oを混在させないでください。

NFSでのO_DIRECTの動作は、ローカルファイルシステムとは異なります。古いカーネル、または特定の方法で構成されたカーネルは、この組み合わせをサポートしていない場合があります。 NFSプロトコルはサーバーへのフラグの受け渡しをサポートしていないため、O_DIRECT I/Oはクライアント上のページキャッシュのみをバイパスします。サーバーは引き続きI/Oをキャッシュできます。クライアントは、O_DIRECTの同期セマンティクスを保持するために、サーバーにI/Oの同期を要求します。これらの状況では、特にI/Oサイズが小さい場合、一部のサーバーのパフォーマンスが低下します。一部のサーバーは、I/Oが安定したストレージに到達したことをクライアントに知らせるように構成されている場合があります。これにより、サーバーの電源障害が発生した場合に、データの整合性を損なう可能性があるパフォーマンスの低下を回避できます。 Linux NFSクライアントは、O_DIRECT I/Oにアライメントの制限を設けません。

要約すると、O_DIRECTは潜在的に強力なツールであり、注意して使用する必要があります。アプリケーションは、O_DIRECTの使用を、デフォルトで無効になっているパフォーマンスオプションとして扱うことをお勧めします。

「O_DIRECTについていつも私を悩ませてきたのは、インターフェイス全体がただ愚かであり、おそらく、いくつかの深刻な心を制御する物質に関する混乱した猿によって設計されたということです。」--- Linus

8
HardySimpson

知る限り、O_DIRECTはページキャッシュをバイパスします。 O_SYNCはページキャッシュを使用しますが、すぐに同期します。ページキャッシュはプロセス間で共有されるため、O_DIRECTフラグなしで同じファイルを処理している別のプロセスがある場合、正しいデータを読み取ることができます。

1