FreeBSD unionfsの改善提案原文

FreeBSD unionfsの改善提案 
Daichi GOTO ([email protected])
作成年月日 Wed Jan 4 17:20:11 2006
更新年月日 Sat Jan 14 23:11:26 2006

[English]
1 概要

FreeBSD 6.0-RELEASEまでに搭載されているunionfsにはいくつかの問題があることが知られている。問題は、大きく分けて2つの領域に分類することができる。unionfsにおける仕様が曖昧な部分に起因する問題と、FreeBSD unionfsのロックの実装に関する問題である。

FreeBSD unionfsの2つの問題:

    * unionfsにおける仕様が曖昧な部分に起因する問題
    * FreeBSD unionfsのロックの実装に関する問題

この結果、CD9660ファイルシステムに対してunionfsをかぶせて使用するような場合、いくつかの問題が起る。そのため、FreeSBIEのようなシステムでは問題が起ることが知られている。本稿では、これら問題を説明すると同時に、これら問題を解決するためのパッチを提供するものである。最終目標は、これらパッチをFreeBSDにマージし、パッチを当てなくても問題が発生しないFreeSBIEが作成できるようにすることにある。
2 unionfsとは

unionfsは、2つのファイルシステムをアタッチしてひとつのファイルシステムとして扱うためのファイルシステムのことである。たとえばCD-ROMに対してメモリファイルシステムをアタッチして、CD-ROM上のファイルに対して書き込みができるかのように見せかけるといった用途に用いられる。

ベースとなるディレクトリ (下層) 以下に対して変更を加えることなく、上にかぶせたディレクトリ(上層)以下に対してのみ変更を与えることになるため、下層のディレクトリはそのままに、変更点だけ保持したいといった場合にも活用できる。

詳細な仕様はMarshall Kirk McKusick、George V. Neville-Neil著 "The Design and Implementation of the FreeBSD Operating System" の P.256 Section 6.7, The Union Filesystemからの2ページ強分などを参照のこと。
3 従来のFreeBSD unionfsが抱える問題

従来のFreeBSD unionfsが抱える問題は次のとおり。

   1. [実装上の問題] 従来のunionfsは、ロック機構として次のような方法を使っている。VOP_* 系の呼び出しに対し、必要に応じて上層/下層をロックしにいくというものである。この場合、unionfsのvnode を含め、1つのvnodeに対して最大で同時に3つのロックを行うことになる。つまり、カーネル側の仕組とは別のタイミングで複数のロック/アンロックを行うため、デッドロックが起りやすい状況にある。事実、従来のunionfsは不安定であり、高負荷状況になるとデッドロックが起りやすい。
   2. [実装上の問題] VOP_*系の呼び出しにおいて、一部はunionfsのvnodeを応答するのに対し、一部は上層/下層のvnodeを直接応答する。特にLOOKUP でこの現象が起きた場合、ユーザからは理解しがたい状況に陥る可能性がある。これまでに確認しているものは、pwdが上層/下層の絶対パスを応答してしまう現象である。
   3. [実装上の問題] readdirの実装が不十分で、上層の一覧のみを応答する。このため、下層にのみ存在するファイルなどをユーザが識別することが出来ない。
   4. [実装上の問題] 上層/下層に同一のファイル/ディレクトリが存在した場合、上層を削除後にホワイトアウトが作成されないため、ユーザからは削除されていないように見える。
   5. [実装上の問題] アクセス権の判定において、下層にのみファイル/ディレクトリがある場合、上層にshadow file/dirを作成後に与えられる権限を応答しない。このため、書き込めるはずのファイルに書き込めないなどの問題が発生する。
   6. [unionfsの仕様の曖昧さに起因する問題] unionfsの仕様には下層のshadow file/dirを作成する場合に、属性の引き継ぎに関する規定がない。このため、従来の実装では「0777をそのときのumaskで修正したもの」という方法のみが提供されてきたが、これが現在のFreeBSD unionfsでは好ましくない結果を生んでしまうことがある。たとえば、実行権限を与えるべきでないファイルへ実行権限が与えられてしまうなど。

これら従来のFreeBSD unionfsが抱える問題による影響はたとえば次のとおり。

    * [実装上の問題] 不安定。unionfsを使って安定したサーバなどの運用を行うことが困難
    * [unionfsの仕様の曖昧さに起因する問題] FreeSBIEなどにおいてOpenOffice.org、Emacs、Vimなどを実行する場合に、あらかじめファイルを作成するといった冗長な作業を行わないとアプリケーションの起動ができなかったり、ファイルの編集ができなかったりする

4 問題への改善提案

今回提案しているパッチにおける、[実装上の問題]への改善内容は次のとおり。

   1. [実装上の問題への対処] unionfsのvnodeが内部に持つロックオブジェクトを上層のロックオブジェクトへのポインタに差し替えることで、kernelが直接上層の vnodeをロックできるように戦略を変更することで対処。下層へのアクセスが必要な場合は、そのとき必要最小限の範囲でロック。ただし、上層に対応する vnodeが存在しない場合は、下層のロックオブジェクトでunionfsのものを差し替える。VOP_* の呼び出し中に上層にvnodeを作成した場合は、unionfs のものを上層へ差し変えて下層をアンロックする。これらはnullfsの仕組みを応用したもの。この変更が大規模であるため、従来のソースへのパッチではなく、フルスクラッチからつくり直している。
   2. [実装上の問題への対処] http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/84107の修正
   3. [実装上の問題への対処] http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/84498の修正 (MAYBE)
   4. [実装上の問題への対処] http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/89755の修正 (MAYBE)
   5. [実装上の問題への対処] http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/73094の修正 (MAYBE)
   6. [実装上の問題への対処] これ以外で、前述したようにわかっている問題を対処。

[unionfsの仕様の曖昧さに起因する問題]に対する改善については、本来仕様に規定されていないことであるため、規定されていない振る舞いをどうするべきか、という議論を含むことになる。

現状のFreeBSD unionfsにおける実装では、この結果、アクセス権を判定し動作を決定するアプリケーションが、ユーザの期待どおりに動作しないという状況が発生している。

この振る舞いをどうするかであるが、これは場面に応じて要求される事柄であり、また、本来仕様に定められていないことであるために、対応が難しいところだと考えられる。今回はこの振る舞いに対し、オプションによって3つの振る舞いを持たせるということで対処することを提案したい。パッチはこの3つの振る舞いをオプションで切り替える機能を含んでいる。

[unionfsの仕様の曖昧さに起因する問題]に対する改善:3つの動作パターン

    * [traditionalモード] - 互換性のために用意するモード。従来のFreeBSD unionfsの動作と同じ動作をする。標準ではこのモードが有効になるようにしておき、今回のパッチをマージしても動作に影響がでないようにする
    * [transparentモード] - 下層のパーミッションをできるかぎり上層においても保持するモード。前述した問題のほとんどはこの動作によってカバーすることができる。
    * [masqueradeモード] - 任意にパーミッションを指定する方法。任意の指定を行うことで、セキュリティなどに配慮したファイルシステムを用意することができる。

本来仕様が策定されていない部分の振る舞いであるから、複数の振る舞いを用意し選択できるようにすることは、意義のある対応であると考える。たとえば、3-7において説明した[unionfsの仕様の曖昧さに起因する問題]は、[transparentモード]で対処することができる。

この結果、次の問題も[transparentモード]で修正されると考えられる。

    * [unionfsの仕様の曖昧さに起因する問題への対処] http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/86596の修正 (MAYBE)

5 インストール方法

パッチを適用してインストールする方法の作業例をプロンプト5.1に示す。

    # patch < /anywhere/unionfs-p2.diff
    # cp /usr/src/sys/fs/unionfs/union.h /usr/include/fs/unionfs/
    # cd /usr/src/sbin/mount_unionfs/
    # make obj && depend && all && install
    # make clean
    # cd /usr/src
    # make buildkernel
    # make installkernel
    # shutdown -r now

プロンプト5.1 インストール作業の例
6 使用方法

mount_unionfs(8)に追加したオプション

    * [-c <traditional|transparent|masquerade>] - 下層から上層へファイルやディレクトリを複製する方法を指定。指定できるタイプは "traditional", "transparent", "masquerade"の3種類。安全のため、このオプションを指定できるのは root ユーザのみである。
          o traditional - 従来のunionfsの互換モード。
          o transparent - 下層の属性などをそのまま複製。
          o masquerade - 指定の属性で複製。ただし、指定のユーザと下層の所有者が同一ユーザの場合、ユーザに対するアクセス権のみを修正する。これは、ユーザが所有するファイルを無意識に公開するのを防止するためである。
    * [-m permission] - masqueradeが指定されている場合に、ファイルのアクセス権を指定する。
    * [-M permission] - masqueradeが指定されている場合に、ディレクトリのアクセス権を指定する。
    * [-u owner] - masqueradeが指定されている場合に、ユーザ(所有者)を指定する。
    * [-g group] - masqueradeが指定されている場合に、グループを指定する。

mount_unionfs(8)から削除したオプション

    * [-r] - mount_nullfs(8)で事足りるため、mount_unionfs(8)からは[-r]を削除。

7 ダウンロード

パッチは基本的にFreeBSD 7-current向け。パッチセット番号が大きいほど新しいパッチセット。

    * SHA256 (unionfs-p5.diff) = df65da3197dd60d0c37251883a9290f9b03e6b4c1f8e2a5940886aa373ab296c
    * SHA256 (unionfs-p4.diff) = 8a3fed6e835676a1dd27ca8872a042d10ef988c5e5912c9a7823835372255ce5
    * SHA256 (unionfs-p3.diff) = ec7aeb1d55e6d6d86665d319a0404f61cb1066282363d70f8ce1ab41b66297b0
    * SHA256 (unionfs-p2.diff) = beaf51723cfd7017a29a1e24e21c585f884328dcb808e586f4e96391c192d1f3
    * SHA256 (unionfs-p1.diff) = c18b4e19a06875656819738e1de566d2b9faab418af91949e28d72ffacfd2572

FreeBSD 6.x向けパッチセット:

    * SHA256 (unionfs6-p5.diff) = 7e0c876c7428693367533b9a6bad44023851e43c0a4795a4939accc72ee9fdc7
    * SHA256 (unionfs6-p4.diff) = aa5faf32dd06645cdce1a90219083707a79a25a7c0882aed8a11b19b62db0b0a
    * SHA256 (unionfs6-p3.diff) = 49a80103631267d824dfa6775e572e16098aa789994bf58bb0259a8e10ead0d7
    * SHA256 (unionfs6-p2.diff) = c6deb8be2cc0b3251a5a3ed04d9945f7756bb915b5a5bf77482546d34cec862c
    * SHA256 (unionfs6-p1.diff) = afa06531d1525e4a96fb6f315f48a8119c79094d97994c155944bbeb0d4f64c5

7.1 unionfs-p5.diffにおける変更点

    * "can't fifo/vnode bypass -1" panic が発生する問題を修正
    * ソースコードへ動作説明のコメントを追加
    * style(9)に準拠したソースコードスタイルへ編集

7.2 unionfs-p4.diffにおける変更点

    * 64bit arch で正常動作しない問題を修正
    * __FreeBSD_versionによる6-stable/7-currentの切り分けを追加

7.3 unionfs-p3.diffにおける変更点

    * shadow dirの属性を正しく設定しない問題を修正
    * 不要なアンロックを行い、アンロックしなければいけない vnode をロックしたまま関数を抜けていた問題を修正(p2の修正では不十分だった)
    * 一部のcomponentnameが正しく初期化されていない問題を修正

7.4 unionfs-p2.diffにおける変更点

    * 不要なアンロックを行い、アンロックしなければいけない vnode をロックしたまま関数を抜けていた問題を修正。VOP_RENAMEのfdvpをロックせずにホワイトアウトを作成していたため、下層に対応するファイルがある場合にrenameを実行するとパニックが発生していた。
    * unionfs-p1.diffでは3つの動作モードとして[-c <old|fullcopy|useful>]を使っていたが、名前が不適切という指摘に従い、より直感的でわかりやすい名前として[-c <traditional|transparent|masquerade>]へ変更

7.5 unionfs-p1.diffにおける変更点

    * 従来のunionfsにおけるロックの実装を改良することに限界を感じたため、ロックの戦略を変更し、フルスクラッチからunionfsを構築。
    * 従来のunionfsが抱えていた様々な問題をわかっている範囲でより正しく実装。ただし、readdirの実装は一考の余地あり。

8 既知の問題

    * 下層にのみ存在するディレクトリをrenameすると、ディレクトリ以下に存在しているファイルなどにアクセスできなくなる。これは、上層に shadow dirを作成しこれをリネームした後、ホワイトアウトを作成しているためである。下層のディレクトリ内を維持したままrenameするには、上層に完全なコピーを作成してからrenameすること。これは、バグではなく仕様。
    * nullfsとの併用ができない。これは、ロック/アンロックの仕組みをnullfsと同様にしたために発生。nullfsを多層化できないのと同じ理由で実現できていない。また、現在これを阻止する実装を入れていないため、誤って併用するとpanicする。

9 Appendix
9.1 FAQ

Q: 従来のunionfsの修正という形ではなく、フルスクラッチから作り替える必要はあったのか?

A: 従来の実装は本質的にロックの実装でデッドロックが発生しやすいものになっていた。これを修正するのは難しく、ほとんどが作り替えになる。このため、従来のソースに対する修正という形ではなく、フルスクラッチから作成することにした。

Q: 互換性はどうなっているのか?

A: 現在のパッチでは、従来の使い方をする限り従来の動作と互換性がある。しかもhttp://www.freebsd.org/cgi/query-pr.cgi?pr=kern/84107(そしてたぶんhttp://www.freebsd.org/cgi/query-pr.cgi?pr=kern/84498、 http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/89755、 http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/86596、 http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/73094)の問題も修正されている。

将来的には、-c transparentの動作をデフォルトにするべきだと考える。従来の動作で問題となる動作のほとんどは、-c transparentにすることで修正されると考えるからである。

Q: パッチの実装はunionfsの本来の動作に沿っているのか

A: 沿っていると考える。unionfsの仕様についてはMarshall Kirk McKusick、George V. Neville-Neil著 "The Design and Implementation of the FreeBSD Operating System" の P.256 Section 6.7, The Union Filesystemからの2ページ強分にまとまっているので、そちらを参照のこと。

Q: 読み込みを行っただけで shadow file が生成されるのはなぜか?

A: 下層のファイルに対してアクセス日時を更新することは出来ないため、shadow fileを作成して日時を更新するからである。この動作をやめるには、-o noatime オプションを指定すればよい。詳細はmount(8)を参照のこと。
9.2 連絡先 & お願い

だれかこのページを英語に翻訳してぷり〜ず :) 翻訳したテキストは[email protected][email protected]へ。日本語テキストだとSPAMフィルタで弾かれる可能性があるので、[email protected]の方がいいかも。バグ報告も同アドレスへ。