2013年7月30日火曜日

ZFS on Mac (3) ZEVOとHFS+の互換性

前回から長いこと放置してしまったわけですが、そろそろ本格的にZEVOを導入したくなってきたのでちゃんと検証してみようかと。

そんなこんなしてる間にZFS on Linuxもstableになったり長らく休眠してたMacZFSも更新されてたりしますが、ZEVOは相変わらず1.1.1のままなので特に取り巻く状況は前回から変わらず。

本格的に使っていくにあたって、検証しておきたいこととしては
・本家SolarisのZFSv28と比較し各機能(サブコマンド・Snapshot等)はどれだけ実装できているか?
・SolarisやZFS on Linuxとの相互利用はどれだけ可能か?(緊急時のサルベージを考慮して)
・現在使っているオレオレバックアップスクリプトは動くか?
・パフォーマンスは実用レベルか?
・不安定になったり、特定の操作でカーネルパニックになったりしないか?(重要)
・データ消えない?(最重要&しかし完全検証不可)
・リソースフォークや拡張属性、AppleDoubleの動作がどうなっているか
・大文字/小文字の区別やUnicode正規化など、HFS+と同様に扱えるか
といった点が挙げられますが、ZFS独自のメリットを享受する以前にHFS+で動いていたものが動かなくなると大変なので、まずは後ろ2つについて検証してみる。

まずは
・リソースフォークや拡張属性、AppleDoubleの動作がどうなっているか
について。
OS 9時代より、Mac OSではファイルはファイル本体のデータとは別にリソースフォークやFinder情報などのメタデータを保持しています。カスタムアイコンや(拡張子以外)のファイルを開くアプリケーション情報、Finderラベルなどがこれにあたります。
現代のMac OS XではこれらのデータはHFS+の拡張属性に格納されます。HFS+以外の近代的なファイルシステムも拡張属性の仕組みは備えているものの、カスタムアイコンのような巨大なデータを格納するように設計されていないのか(?)、Macでは拡張属性属性を利用することはできません。
そのため、FAT32やexFAT(やSMB)のような非Mac用のファイルシステムにMacから書き込む場合、AppleDoubleという機能によってこれらのデータは「._」から始まる不可視の別ファイルに分割されて格納されます。
別ファイルに分割される以上、誤って削除される、あるいは孤立する事態が起こりうるわけで、USBメモリのようなテンポラリなストレージならともかくデータ置き場にするなら避けたいところ。
ZFSの拡張属性はかなり強力で、Solaris+ZFS+netatalkの環境ならば全てのデータを拡張属性に格納できるようですが、ZEVOではどうなのか検証してみます。

検証のため以下のファイルを用意しました。
none.txtが通常のテキストファイル、app.txtが標準のテキストエディットではなくAppleScriptエディタで開かれるように変更したもの、label.txtがラベルを設定したもの、icon.txtはカスタムアイコンを適用したものです。
実はnone.txtの作成方法は失敗で、テキストエディットで保存した時点でFinder情報が付与されてしまっていました(ターミナルからtouchで作るべきだった)。気にしないことにしよう。

HFS+のボリューム上ではこれらのファイルは(拡張属性を表示する-@オプションを利用)
$ ls -la@ /Volumes/HFS+/
-rw-r--r--@  1 b00t  staff     0  7 29 22:30 app.txt
 com.apple.ResourceFork 1338 
 com.apple.TextEncoding   15 
-rw-r--r--@  1 b00t  staff     0  7 29 22:38 icon.txt
 com.apple.FinderInfo   32 
 com.apple.ResourceFork 642125 
 com.apple.TextEncoding   15 
-rw-r--r--@  1 b00t  staff     0  7 29 22:29 label.txt
 com.apple.FinderInfo   32 
 com.apple.TextEncoding   15 
 com.apple.metadata:kMDLabel_qygkxhrfarhtxanqhi264amkku   50 
-rw-r--r--@  1 b00t  staff     0  7 29 22:29 none.txt
 com.apple.TextEncoding   15
このように表示されます。(無関係なファイルは省略)

これがexFATのボリューム上では
$ ls -la@ /Volumes/exFAT/
-rwxrwxrwx  1 b00t  staff    5148  7 30 00:26 ._app.txt
-rwxrwxrwx  1 b00t  staff  645935  7 30 00:26 ._icon.txt
-rwxrwxrwx  1 b00t  staff    4096  7 30 00:26 ._label.txt
-rwxrwxrwx  1 b00t  staff    4096  7 30 00:26 ._none.txt
-rwxrwxrwx@ 1 b00t  staff       0  7 29 22:30 app.txt
 com.apple.ResourceFork   1338 
 com.apple.TextEncoding     15 
-rwxrwxrwx@ 1 b00t  staff       0  7 29 22:38 icon.txt
 com.apple.FinderInfo     32 
 com.apple.ResourceFork 642125 
 com.apple.TextEncoding     15 
-rwxrwxrwx@ 1 b00t  staff       0  7 29 22:29 label.txt
 com.apple.FinderInfo     32 
 com.apple.TextEncoding     15 
 com.apple.metadata:kMDLabel_qygkxhrfarhtxanqhi264amkku     50 
-rwxrwxrwx@ 1 b00t  staff       0  7 29 22:29 none.txt
 com.apple.TextEncoding     15
となります。「._」から始まる4ファイルが生成されているのがわかります。拡張属性は一見保持できていますが、「._」があってはじめて保持できているため、
$ rm /Volumes/exFAT/._*
とした場合
$ ls -la@ /Volumes/exFAT/
-rwxrwxrwx  1 b00t  staff      0  7 29 22:30 app.txt
-rwxrwxrwx  1 b00t  staff      0  7 29 22:38 icon.txt
-rwxrwxrwx  1 b00t  staff      0  7 29 22:29 label.txt
-rwxrwxrwx  1 b00t  staff      0  7 29 22:29 none.txt
このように拡張属性(に含まれる各種情報)が消えてしまいます。

しかし、ZEVOで作成したZFSボリュームでは
$ ls -la@ /Volumes/r1pool/fs/
-rw-r--r--@ 1 b00t  staff     0  7 29 22:30 app.txt
 com.apple.ResourceFork 1338 
 com.apple.TextEncoding   15 
-rw-r--r--@ 1 b00t  staff     0  7 29 22:38 icon.txt
 com.apple.FinderInfo   32 
 com.apple.ResourceFork 642125 
 com.apple.TextEncoding   15 
-rw-r--r--@ 1 b00t  staff     0  7 29 22:29 label.txt
 com.apple.FinderInfo   32 
 com.apple.TextEncoding   15 
 com.apple.metadata:kMDLabel_qygkxhrfarhtxanqhi264amkku   50 
-rw-r--r--@ 1 b00t  staff     0  7 29 22:29 none.txt
 com.apple.TextEncoding   15 
このようにHFS+と同じくAppleDouble無しで拡張属性が保持できています!
また、HFS+←→ZFS間のファイルコピーだけでなく、exFAT→ZFSのようなファイルコピーにおいてもAppleDoubleによって分割されたファイルを結合する仕組みがHFS+と同様に動作します。
どうやら、拡張属性周りについてはさほど心配する必要がなさそう。


次、
・大文字/小文字の区別やUnicode正規化など、HFS+と同様に扱えるか
ですが、大文字/小文字の区別については大きな問題ではありません。HFS+のボリューム作成時に区別するか否かを選択できるように、Mac OS X自体はどちらにも対応できるように設計されています。また、ZFSもファイルシステム作成時にcasesensitivityオプションで選択することができます。
ただ、HFS+のデフォルト設定が「区別しない」(insensitive)であることを考慮すると、ZFSもinsenstiveとする方がトラブルに遭遇しにくくなるかと思います(実際にsensitiveで困ることがあるらしい)。
ZEVOのデフォルトはなぜかsensitiveなので、ファイルシステム作成時に
$ zfs create -o casesentivity=insensitive pool/fs
としてinsensitiveにすることをオススメ。
また、プール作成時に-Oオプションによって
# zpool create -O casesentivity=insensitive pool /dev/disk2
のように指定することでトップレベルのファイルシステムもinsensitiveで作成できます。
ちなみに、ZFSにはファイル共有用ボリューム向けに両方の方式を共存(?)させるcasesentivity=mixedというオプションが存在しますが、ZEVOでは利用できないようです。


さて、問題なのはUnicode正規化です。
Unicode正規化についてそれなりに説明すると、記事一本書けてしまうくらい重いものなので以降はある程度Unicode正規化について知っている人向けの内容です。
しかし、そうは言っても自分自身がUnicodeの専門家ではないので、多くの事実誤認が含まれている可能性があります。その場合は是非指摘していただきたい。

Mac←→Windowsのファイル交換でたまに問題になるのですが、Macではファイル名の仕様としてNFDのようなものが使われています。一方Windowsでは特に正規化を行いません。
「NFDのようなもの」が何かというと、「が」のような合成文字はNFD(か+゛)として正規化しつつ、「神」のような互換漢字は正規化を行わない(「神」にしない)ものです。
見た目上同じ「が」と「か+゛」がWindowsのように共存できてしまうことが無い一方、見た目が違う「神」と「神」を別物として扱うのは実用に即しているように思えますが、その独特の正規化基準(UTF-8-MACと言ったりするらしい)はZEVO(というかHFS+以外のファイルシステム)との相互運用性においてかなりの不安要素になります。

ここでややこしいのは「ファイルシステム上のファイル名」と「lsやFinderから取得できるファイル名」が同一でない可能性があるということです。つまり、ファイル名が渡されるときにOSなりFinderなりで正規化が行われるということです。この点も踏まえながら色々と検証していきます。

まず、ZFSのnormalizationプロパティについて説明します。
ZFSではnone・formC・formD・formKC・formKDの5つのプロパティを設定でき、noneは「何もしない」、それ以降はNFC・NFD・NFKC・NFKDに対応します。NFKC/NFKDは「㎡」が「m+2」に正規化されたり、全角英数が半角に正規化されるようなファイル名向きとは言い難いものなので除外して考えます。
ここで設定できるプロパティはあくまで「ファイル名の比較方法」であって、「ファイル名の格納方法」ではないことに注意が必要です。formDと設定したからといって「$ mkdir が」で生成されるのが「か+゛」になるわけではなく、「が」フォルダが存在する場所で「か+゛」を生成しようとした際に「が」同名ファイルである(から生成できない)との比較結果を返すようになるだけに過ぎません。
(素人考えだが、格納するファイル名に関与せずどちらに寄せて比較するかというだけなので、noneとその他で違いはあってもformCとformDで違いが出るケースが思い浮かばない。単なるファイル生成ではなく、ファイル呼び出しで問題が起こるという可能性もあるものの、formCで作ったボリュームにNFCな動画を配置してもQTXで再生できた)

結論から言ってしまうと、(ZEVOのデフォルトがそうであるように)作成するファイルシステムのnormalization=formDとしておくのが正解だとは思いますが、何もかもHFS+と同じ挙動となることは期待できません。
(また、normalization=noneはかなり問題のある挙動を示すために推奨できません)
以下に書き連ねるのも特に結論に辿り着けない検証結果でしかなかったりします。

そしてMac側の挙動についてですが、かなり不可解です。調べた限りでは、「mkdir/touchによるNFCなファイル生成」「mvによるNFDなファイル名からNFCなファイル名への変更」「Finder上でNFCな文字列をペーストすることによるファイル作成」のそれぞれで違う挙動を示します。

まず、以下の4つのボリュームを用意しました。
・HFS+
・exFAT
・ZFS(normalization=none)
・ZFS(normalization=formD)(formCは結果が変わらなかったため割愛)
これらのボリュームに対し、
・FinderからNFCの「が」フォルダを作成
・ターミナルからmkdirによりNFCの「が」フォルダを作成
します。NFCの「が」はペーストによって貼り付けしますが、ことえり・ATOKなどのIMEで入力されるカナは基本的にNFCなので実際は手入力でフォルダを作成するのと変わりません。
フォルダ作成後、
・lsから取得できるファイル名
・Finderから取得できるファイル名
を比較します。なお、Macのターミナルはデータ的には正規化前の文字を保持するものの、表示上は全てNFCに正規化されてしまう(2014/3/29追記:勘違いかもしれません。)ためlsの結果をファイルに書き出してから取得しています。

結果としては
・Finderから生成したフォルダ→どの条件でもNFD
となりました。つまり、Finderは内部的にNFD(のようなもの)に正規化してからファイル名を設定しているようです。IMEから入力したNFC文字列がNFDとなって格納されるのはFinderが寄与していると。
では、ターミナルから生成した「が」についてはどうなのかというと
・lsの結果→HFS+・exFATはNFD、ZFSはどちらもNFC
となってしまいました。一方で
・Finderから取得したファイル名→HFS+のみNFD、それ以外はNFC
となっています。「それ以外」とは言いましたが、実はnormalization=noneではFinder上で表示すらされませんでした(正確には一瞬見えて消えたりする)
さて、mkdirで生成した「が」についてまとめると

このようになります。 なんとも言い難い結果です。とりあえず言えることはnormalization=noneを避けようということだけです。
Mac OS X自体がNFDでの処理を基本としていることを考えると、HFS+以外では内部的にNFCでファイルが格納されていることが推測できます。HFS+は(確か)仕様上NFDでファイルを格納しているので、Finderではなく(特に正規化機能を持たないであろう)mkdirでファイルを生成した場合でもファイルシステムレベルで正規化を行っているのでしょう。
一方ZFSでは特段の処理がなされていないのでしょうが、謎なのがexFATです。
元々Windows向けのファイルシステムである性格上、WindowsからNFCなファイルが書き込まれることを想定してlsコマンドにexFAT向け正規化機能でも含まれているのでしょうか?だとしたらFinderではNFCなファイル名が返ってくるのは不可解なのでやっぱりわかりません。
ちなみに、normalization=noneではFinderで表示できないのは、
・Finderがファイル一覧を取得(NFCのファイル名が返る)
・取得したファイルを表示するためにアイコンなどを取得しようとする
・FinderがファイルシステムにNFDで正規化したファイル要求を出す
・ファイルシステムが(正規化して比較しないので)そんなファイルは無いと返す
ことにより起こる問題なのではないかな?と勝手に思っています。

そして、更に不可解なのが、「が.txt」のようなNFDなファイルを配置して、mvによってファイル名を変更した場合の挙動です。

なんとこのようになります。ZFS(formD)での挙動が変わる。
最初はQTXの再生テスト用に「どうが.mp4」のようなファイルを作っていて気付いたのですが、テキストでも変わらず、また拡張属性に左右されるのかと思いtouchで作った拡張属性無しの空ファイルでも試しましたが結果は同じでした。
相変わらず内部的にはNFCで格納されているはずなのですが、lsがNFDなファイル名を返すように。
正直、lsの挙動についてはさっぱりです。ここに書いた以外にも色々試し、条件を統一して検証しているはずなのですが同じ条件で繰り返すと違う結果のようなときもあったりして気持ちが折れてしまった。
「Finderで作業する分には困らない」ということで逃げたい。

最後に、どうしてもHFS+と同様にならない問題について。HFS+がNFD(のようなもの)を採用している以上、本来のNFDとはどうしても齟齬が生じます。
つまり、HFS+では「神」と「神」が共存できますがnormalization=none以外のZFSでは同一とみなされ共存できません(比較の際の問題なので互換漢字の「神」が使えないわけではない)。正規化による比較をしないnormalization=noneなら共存できますが、それ以外の問題が大きすぎるので到底おすすめできません。
テキストファイルの中身ならともかく、ファイル名で互換漢字が問題になるケースは考えにくいということで割り切るしかないところです。


なんとも釈然としない終わり方ですが、まったくHFS+と同じようにはいかないまでも「そういうものだと知っておく」ことである程度なんとかなる程度の差異なのではないかなと思います。

0 件のコメント:

コメントを投稿