ZFS, Transactional NTFS, Rollback

ZFS がやってくる

@IT に,Leopard で使用可能になるといわれる ZFS の記事が出ています.

システム開発者や管理者であれば、あるディレクトリに関連ファイルを展開して作業するというのは、よくあることだ。アーカイブを展開し、makeファイルを編集し、パッチを当てるといった作業はよく発生する。パッチ当てでは、その作業順序が異なると、うまくいかなかったりするため、どうしても試行錯誤が必要となるが、そんなときにうれしいのが、スナップショットのロールバック機能だ。

「ここから先は」と不安に感じたら、すぐに「zfs snapshot pool/home/ken/project1@point-a」としてスナップショットを取り、もし作業をやり直したいと思ったら「zfs rollback pool/home/ken/project1@point-a」とするだけでいい。ファイル群をまるまる複製する単純なスナップショットと異なり、こうした作業においてはディスク消費量は極めて少なく、生成も一瞬。

もっとスゴイのは、スナップショットのクローン機能だ。生成されたスナップショットはリードオンリーだが、スナップショットから「zfs clone pool/home/ken/project1@point-a pool/home/ken/project1/test」とクローンを作成することで、ファイルの編集が可能になる。さらに、「昇進させる」という意味のpromoteコマンドを使えば、スナップショットの元になったディスク上のデータに対する差分という存在から、ディスク上にフルに書き出された正規のファイルに変換することもできる。

Transactional NTFS (TxF) と FeedbackID 155945

ZFS は確かにエキサイティングな機能です.が,上の記事を読んでいるとちょうど一年前に書いた Transactional-NTFS (TxF) の記事を思い出します.

河端さんが書かれているように,あるコマンドプロンプトでこのトランザクションを実行しているとき,最後の transaction /commit が実行されるまでは,別のコマンドプロンプトから 1.txt や 2.txt の変更は見えません.セッション外部からは,文字通りトランザクションがコミットされるタイミングでまとめてファイルシステム上の変更が行われるように見えるのです.より詳しく見てみると,読み書き可能なスナップショットが作成されるわけではなく,トランザクションを破壊するようなファイル操作は外部からできなくなっていることがわかります.例えば,トランザクション中で変更されたファイルは,トランザクションが終了するまで外部からは書き込めません.

トランザクション中のコマンドプロンプトから起動されたプロセスは,このトランザクション中の状態が見えるようです.これを利用すると,例えば一時的にデータを書き換えて処理プログラムを実行し,後でオリジナル状態に戻すといった作業で,いちいちオリジナルデータのバックアップをとる必要が無くなります.

例えばこういう場合ですね.

これで,オリジナルのソースコードは一切変更されません.ただ上にも書きましたが,このビルド処理と並行してオリジナルのソースに対しても別のビルド処理を実行できるかというと,それは難しいでしょう.技術的には揮発性スナップショットを作るのも不可能ではなさそうですが,どうなんでしょうね?

実は,この記事を書いている裏で,Windows Vista のベータサイトに,あるフィードバックを上げていました.セキュリティ絡みということで公の場で言及はしなかったのですが,RTM 以前の修正でそもそも前提ごと消滅したので,もう公開しても大丈夫でしょう.

Transactional NTFSは、トランザクションに参加していないプロセスからはファイルの存在を隠す手段に使用できうる。

コマンドプロンプトからtransactionコマンドを使用し、トランザクション中にリネーム・作成されたexeファイルを使用すると、タスクマネージャの機能であるプロセスから「ファイルの場所を開く」や「プロパティ」が事実上無効化される。

Transactional NTFSがマルウェア等によって偽装手段に使われないよう、タスクマネージャ以外にも仕様のレビューが必要かと思われる。

つまり,TxF を利用してあるトランザクション中に隔離された実行ファイルを使用することで,外部のプロセスから「実行ファイルへのアクセスが拒絶されてしまう」プロセスを作成できたというものです.トランザクション自体に依存する新たなプロセスを実行できるメリットより,このような状態を許してしまう仕組みによって不必要な複雑さを OS に持ち込むデメリットの方が大きいのではと思い,フィードバックを書いた次第です.

ZFSロールバックファイルシステムのアンマウントが必要

当時の Vista の transaction コマンドに比べれば,@IT の記事にあるような ZFS の使い方は,現実的な取り組みだと思います.しかし,@IT の記事ではロールバックされるファイル群を使用中のプロセスがどう扱われるべきかなど,自明でない問題に関して一切ふれられていません.ちょっと気になって調べてみました.
以下は 『Solaris ZFS 管理ガイド』のもので,Leopard に搭載されるものが同じ制約を受けるかどうかは分かりませんが,割と納得の内容です.

注– ロールバックするファイルシステムが現在マウントされている場合は、そのマウントを解除してから再度マウントする必要があります。ファイルシステムのマウントを解除できない場合は、ロールバックに失敗します。必要に応じて-f オプションを指定する と、ファイルシステムのマウントが強制的に解除されます。

なるほど,ロールバック時にはファイルシステムを丸ごとアンマウントするので,例えばファイルをオープン中のプロセスとか,そういった問題とは無縁のようですね.

lost feature

ファイルシステムのアンマウントといった荒療治なしにロールバックを可能にする TxF は,必然的に多くの複雑さを抱えていました.
上のフィードバックを書いた頃のベータ版 Windows Vista には,CreateFile や CopyFile といった従来の Win32 API を使用してファイル操作を行う従来のアプリケーションを,修正なしに TxF のトランザクションに参加させる仕組みがありました.これこそが消えた transaction コマンドの正体でもあります.

トランザクション コマンド ラインの変更点

Windows Vista の初期のベータ版をテストしたことがある皆さんは、コマンド ラインからトランザクション コマンドを呼び出すことができた記憶があるでしょう。管理者は、この機能を使用して、コマンド ラインからトランザクションを開始し、アプリケーションを実行して、それ以降にアプリケーション内で実行するファイル操作を、暗黙的にすべてトランザクション ファイル操作として実行できました。

しかし、Windows Vista でのアプリケーションの互換性をテストした段階で、この暗黙的なモデルでは、COM+ 開発者やマネージ開発者が安全に使用することは難しいことがわかりました。そのため、この混乱を回避するために、選択的かつ明示的なモデルに変更しました。この変更の欠点は、アプリケーション内で TxF を使用する必要がある場合、コードを変更して新しい API を呼び出す必要があるということです。

Kernel Transaction によって,TxF Contextを子プロセスのスレッドに暗黙的に引き継がせる仕組みがどのようなものであったかは,以下の記事にその片鱗をみることができます.

しかし,この仕組みは消えました.また,CreateProcess や LoadLibrary のトランザクション版が存在しないことから,プロセス起動用のファイルが隠されるということもありません.

参考資料

現在の Vista に搭載されている TxF で何ができるかを知るには,MSDN Library の以下のページに一通り目を通すのが良いでしょう.

ファイルのメモリマップにも当然対応しています.また,ファイルの移動や名前変更は,TxF が最も活躍する場面になるでしょう.