copy_file_rangeを使用したコピーアクセラレーション

Copy acceleration with copy_file_range


質問 written by Some Name @2019-01-22 06:14:50Z

: 0 : 1 : 42

Linuxの2つのファイル記述子間でのカーネル内データ転送について学んでいますが、理解できないことがありました。 copy_file_rangeのマンページからの引用です

copy_file_range()は、reflinks(つまり、同じコピーオンライトディスクブロックへのポインターを共有する2つ以上のiノード)やサーバーサイドコピーなどの「コピーアクセラレーション」技術を実装する機会をファイルシステムに与えます

インデックスノードは、 stat / statx syscallによって返されるものと考えていました。 st_ino型はここtypedef ています

typedef unsigned long   __kernel_ulong_t;

では、「同じコピーオンライトディスクブロックへのポインターを共有する2つ以上のiノード」とはどういう意味ですか?

回答 1 written by SergGr @2019-01-23 23:59:37Z
2

私の理解によると、 copy_file_rangeはユーザーモードを介してデータを渡す必要がないという事実は、カーネルがディスクからデータをロードする必要がないことを意味します(まだそうする必要はありませんが)操作をファイルシステムスタックにプッシュすることにより、さらに最適化できます。 これは、NFSを介したサーバー側コピーの場合を対象としています。

他の最適化に関する実際の答えは、ファイルの保存方法のイントロから始まります。すでにわかっている場合は、スキップしてもかまいません。

典型的なLinux FSでのファイルの保存方法には3つの層があります。

  1. あるディレクトリ内のファイルエントリ(それ自体は、そのようなエントリのリストを含むファイルです)。 このようなエントリは、基本的にファイル名を何らかのiノードにマップします。 これは、inode番号(別名st_inoを格納することで実行されます。これは、事実上、あるテーブルのinodeへのポインタです。

  2. 共有(詳細を参照)メタデータ( statによって返されるメタデータ)および実際のファイルコンテンツを格納するデータブロックへのポインターを含むiノード

  3. 実際のデータブロック

たとえば、ハードリンクは、「オリジナル」ファイルと同じiノードを指す(およびiノード内の「リンクカウンター」をインクリメントする)ディレクトリ内のレコードです。 つまり、ファイル名(および場合によってはディレクトリ)のみが異なり、残りのデータとメタデータはすべてハードリンク間で共有されます。 ハードリンクの作成は、ファイルをコピーする非常に高速な方法であることに注意してください。 唯一の欠点は、両方のファイルがコンテンツを永久に共有するようにバインドされているため、これが真のコピーではないことです。 しかし、 コピーオンライト方式を使用して「書き込み」部分を修正した場合、非常にうまく機能します。 これは、一部のFS( Btrfsなど)がreflinksを介してサポートするものです。

このcopy-on-wroteトリックのアイデアは、新しい適切なメタデータを使用して新しいiノードを作成しながら、同じデータブロックを共有できるということです。 また、iノードメタデータの「非表示」部分の2つのiノード間に相互参照を追加して、データブロックを共有していることを認識します。 明らかに、この操作は実際のコピーと比較して非常に高速です。 また、ファイルが読み取られるだけである限り、すべてが完全に機能します。 ただし、ハードリンクとは異なり、書き込みを独立したものとして扱うこともできます。 書き込みが実行されると、FSはファイル(またはinode)が実際にデータブロックの唯一の所有者であるかどうかを確認し、そうでない場合は書き込み前にデータをコピーします。 FSの実装に応じて、最初の書き込みでファイル全体をコピーするか、より詳細なメタデータを保存して、変更する必要があるブロックのみをコピーし、残りをファイル間で共有できます。 後者の場合、書き込みサイズがブロックを超える場合、ブロックをコピーする必要はまったくありません。

したがって、 copy_file_range()ができる最も簡単なトリックは、ファイル全体が実際にコピーされているかどうかをチェックし、そうであれば、上記のreflinkトリックを実行することです(FSがサポートしている場合)。

FSがデータブロックのより詳細なメタデータをサポートしている場合、いくつかのより高度な最適化も可能です。 ファイルの先頭から最初のNバイトを新しいファイルにコピーするとします。 その後、FSは開始ブロックのみを共有でき、おそらく完全にコピーされていない最後のブロックのみをコピーする必要があります。