以下は、Linux カーネル文書、Documentation/filesystems/overlayfs.txt の kanda.motohiro@gmail.com による訳です。原文と同じ、GPL v2 で公開します。
Neil Brown <neilb@suse.de> 著
オーバーレイファイルシステム
=================
この文書は、Linux で、オーバーレイファイルシステム(ユニオンファイルシステムとも呼ばれます。)機能を提供するための新しいアプローチのプロトタイプを説明します。オーバーレイファイルシステムは、1つのファイルシステムをもうひとつのものの上にオーバーレイした結果を提供しようとするものです。
結果は、必然的に、多くの技術的理由から、通常のファイルシステムのようには見えないこともあります。しかし、多くのユースケースにおいて、その違いが無視できることが期待されます。
このアプローチは「ハイブリッド」です。なぜならば、ファイルシステムに現れるオブジェクトは、そのファイルシステムに属するようには全く見えないからです。多くの状況でユニオンでアクセスされるオブジェクトは、それに対応するオブジェクトを元のファイルシステムでアクセスするのと区別がつきません。これは、stat(2) が返す 'st_dev' フィールドにおいて最も明らかです。
ディレクトリはオーバーレイファイルシステムに由来する st_dev を報告しますが、すべてのディレクトリ以外のオブジェクトは、そのオブジェクトを提供している上あるいは下のファイルシステムに由来する st_dev を報告します。同様に、 st_ino は st_dev と組み合わせた時だけユニークであり、この両方が、ディレクトリ以外のオブジェクトの一生の間に変わることがあります。多くのアプリケーションとツールはこれらの値を無視するので、影響を受けることはありません。
上と下
-------
オーバーレイファイルシステムは、2つのファイルシステムを結合します。「上」のファイルシステムと、「下」のファイルシステムです。両方のファイルシステムに名前が存在するとき、「上」のファイルシステムのオブジェクトが見え、「下」のファイルシステムのオブジェクトは、隠されるか、あるいはディレクトリの場合は、「上」のオブジェクトとマージされます。
「ファイルシステム」というよりは、上と下の「ディレクトリツリー」と呼ぶほうが正確でしょう。なぜならば、両方のディレクトリツリーが同じファイルシステムに存在することも十分ありえますし、上にも下にも、ファイルシステムのルートがなくていはいけないという要求は無いからです。
下のファイルシステムは、 Linux がサポートするファイルシステムなら何でもよく、書き込み可能である必要はありません。下のファイルシステムが別の overlayfs であってもよいです。上のファイルシステムは普通は書き込み可能で、そうである時は、trusted.* 拡張属性の作成をサポートしなくてはいけません。さらに、 readdir 結果に、有効な d_type が必要です。このため、NFS は不可です。
2つのリードオンリーファイルシステムのリードオンリーなオーバーレイは、どのようなファイルシステムタイプを使ってもよいです。
ディレクトリ
------------
オーバーレイは、主に、ディレクトリに関係します。もしある名前が上と下の両方のファイルシステムに存在し、どちらもディレクトリでないものを参照する場合、下のオブジェクトは、隠されます。名前は、上のオブジェクトだけを参照します。
上と下のオブジェクトの両方がディレクトリの場合、マージされたディレクトリが作られます。
マウント時に、マウントオプション "lowerdir" と "upperdir" で指定された2つのディレクトリはマージされたディレクトリに結合されます。
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper,\
workdir=/work /merged
"workdir" は、upperdir と同じファイルシステムにある空のディレクトリでなくてはいけません。
そして、そのマージされたディレクトリに対して、検索が要求された時には、検索はそれぞれの実際のディレクトリに対して行われ、結合された結果が、オーバーレイファイルシステムに属する dentry にキャッシュされます。両方の実際の検索がディレクトリを見つけたら、両方が記録され、マージされたディレクトリが作成されます。そうでない場合、片方だけが記録されます。上にあれば、上のが、そうでなければ下のが。
ディレクトリの名前のリストだけがマージされます。メタデータや拡張属性などの内容は、上のディレクトリのものだけが報告されます。下のディレクトリのこれらの属性は隠されます。
whiteouts と不透明ディレクトリ
-----------------------------------
下のファイルシステムを変更せずに rm と rmdir をサポートするため、オーバーレイファイルシステムでは、ファイルが削除されたことを上のファイルシステムに記録する必要があります。これは、whiteouts と不透明ディレクトリを使って行われます。(ディレクトリでないものは、常に不透明です。)
whiteout は、 0/0 デバイス番号を持つキャラクタデバイスとして作られます。マージされたディレクトリの上のレベルに whiteout が見つかると、下のレベルのすべてのマッチする名前は無視され、whiteout 自身も隠されます。
ディレクトリは、xattr "trusted.overlay.opaque" を、"y" にすることで不透明となります。上のファイルシステムが不透明ディレクトリを持つとき、下のファイルシステムの同じ名前のすべてのディレクトリは無視されます。
readdir
-------
'readdir' 要求がマージされたディレクトリに行われると、上と下のディレクトリがそれぞれ読まれて、名前のリストが自明な方法でマージされます。(先に上が読まれ、次に下です。すでにある要素は再度追加はされません。)このマージされた名前のリストが、'struct file' にキャッシュされ、そのファイルがオープンされている間、とどまります。ディレクトリが同時に2つのプロセスによってオープン、リードされると、それぞれ別のキャッシュができます。ディレクトリ最初への seekdir (オフセット0)に続いて readdir がされると、キャッシュは捨てられ、再作成されます。
これはつまり、マージされたディレクトリへの変更は、ディレクトリが読まれている間は見えないということです。多くのプログラムはこれには気が付きません。
シークオフセットは、ディレクトリが読まれる間、シーケンシャルにアサインされます。このため、もし、
- ディレクトリの一部を読む
- オフセットを覚えて、ディレクトリをクローズする
- しばらく後で、ディレクトリを再度オープンする
- 以前のオフセットにシークする
ならば、ファイル名のリスト中の、古い方と新しい方の位置はほとんど無関係となります。特に、ディレクトリで何かが変更された場合はそうです。
マージされていないディレクトリへの readdir は単純に元となるディレクトリによって処理されます。(上か下)
ディレクトリ以外
----------------
ディレクトリでないオブジェクト(ファイル、シンボリックリンク、デバイススペシャルファイルなど)は、上あるいは下のファイルシステムから適切に提示されます。下のファイルシステムのファイルが、ライトアクセスを指定してオープンされるとかメタデータをいくらか変更するなど、ライトアクセスが必要な方法でアクセスされた場合、ファイルは最初に下のファイルシステムから上のファイルシステムにコピーされます(copy_up)。ハードリンクを作るのも copy_up が必要なことに注意下さい。もちろん、シンボリックリンクの作成では不要です。
copy_up は不要とわかることもあります。例えば、ファイルが読み書き指定でオープンされたけど、データが変更されなかった時などです。
copy_up 処理は、まず、上のファイルシステムにそれを含むディレクトリがあることを確認します。なければ、親も含めて、作成します。次に、同じメタデータ(所有者、モード、変更時刻、シンボリックリンクターゲットなど)でオブジェクトを作ります。次に、オブジェクトがファイルなら、データは下から上のファイルシステムにコピーされます。最後に、拡張属性があれば、下から上にコピーされます。
copy_up が終わったら、オーバレイファイルシステムは、単純に、上のファイルシステムに新しく作られたファイルへの直接アクセスをさせます。そのファイルへの以降の操作は、オーバレイファイルシステムには、全く通知されません。(なお、ファイル名への操作、つまり、リネームやアンリンクは通知、処理されます。)
標準的でない振る舞い
---------------------
copy_up 操作は、要するに、新しい、同じファイルを作成して、元の名前のところに移動します。新しいファイルは異なるファイルシステムにあるかもしれないので、ファイルの st_dev と st_ino の両方が変わることがあります。
この inode を参照するオープンファイルは、古いデータとメタデータをアクセスします。同様に、 copy_up の前に確保されたファイルロックはコピーアップされたファイルには適用されません。
O_RDONLY を指定してオープンされたファイルへの fchmod(2), fchown(2), futimesat(2) そして fsetxattr(2) は、 EROFS で失敗します。
複数のハードリンクを持つファイルがコピーアップされると、リンクは、「こわれます」。同じ inode を参照する別の名前には変更は伝搬されません。
/proc/PID/ と /proc/PID/fd のシンボリックリンクのうち、 overlayfs のディレクトリ以外のオブジェクトを指すものは、有効な絶対パスを持ちません。ファイルシステムのルートまでの相対パスを持つだけです。これは将来、修正されます。
操作にはアトミックでないものがあります。例えば、 copy_up やリネームの途中でのクラッシュは、ファイルシステムを矛盾した状態にします。これは将来、考慮されます。
下のファイルシステムへの変更
------------------------------
オーバレイがマウントされていない時のオフライン変更は、上と下のツリーに対して可能です。
マウントされたオーバレイファイルシステムの一部となっている時の元となるファイルシステムへの変更は許されません。元となるファイルシステムが変更された場合、オーバレイの振る舞いは未定義です。ただ、クラッシュあるいはデッドロックにはならないでしょう。
以上