Linux の ISO9660 ファイルシステム固有の問題

Linux の isofs (ISO9660 ファイルシステム) の実装にはひとつ大きな欠陥があり、レコーディングの相互運用性確保の足かせになっています。

ISO9660 のレイアウトの例を右に示します。 isofs の i-node(*) は対応するディレクトリエントリ(黄緑色)へのオフセット値を保持するもので、32bit Linux では 32bit の幅をもちます。 これはメディアの先頭からのバイトオフセット値です。

このため何らかの細工を施さない限り、4GB (=232) の境界を越えた領域にディレクトリ(緑色)を置くことができません。 ただ実際はもう少し良い状況にあります。 なぜなら mkisofs は全てのディレクトリを各セッションの先頭に集約するからです (だから通常は右の図のように緑色の間に青色が存在することはありません)。

このため先頭にあるセッションでは i-node の折返し (32bit を越えた時に起こる問題,例えば 0x100000001 が 0x00000001 になる) は発生しませんが、後ろにあるセッションではこれが発生し得ます。

繰り返しになりますが、ファイルは特定のセッションにおいては 4GB の境界を越えて存在することができますが、ディレクトリは不可能です。

私はディレクトリエントリが常に偶数オフセットで始まることを知って、限界を 8GB まで拡張できる方法を考えました。 しかし相互運用性を考慮すればセッションの開始位置を 4GB (実際は「4GB - ディレクトリ構成に必要な容量」) を超えないようにすべきです。 “ディレクトリ構成に必要な容量”とは、例えば最後のセッションでメディアを満杯にするには、約400MB の余裕が必要になります。

growisofs のバージョン 5.3 からは、 4GB −40MB を超えた領域に新規セッションの作成ができないようになっています(**)。 この 40MB というのはディレクトリカタログ作成のために必要なスペースに多少の余裕をもたせたものです。 ただしこれで i-node の折り返し問題を解消できることを保証するものではありません。 この手の問題に遭遇し、とりあえずデータを回復させなければならない方のために fs/isofs 用のカーネルパッチがあります。
カーネル2.6.8でこの問題に対する恒久対策が施されました(Paul Sericeに感謝)。しかしgrowisofsでは最終書込みにおける4GBの制限を取り除いていません。これはより広い互換性を保つための措置です。

(*) i-nodeとはファイルシステムで特定のファイルを指すユニークな番号のこと
(**) バージョン5.20から2層DVD+Rメディア(DVR+R DL)の書込みをサポートしました。これは -use-the-force-luke=4gms というオプションにより、4GBの制限を取り払うことによります。ただしカーネル2.6.8以上をお使いの開発者のみにお勧めできるものです。

カーネルの “DVD+RWサポート(パッチ)”

DVD+RW にはマルチセッションの概念がありませんが、DVD-ROM との互換性により “CLOSE TRACK/SESSION (5Bh)” という MMC コマンドを発行しなければならないことがあります。 例えばメディアをイジェクトしようとしたら、バックグラウンドフォーマットが行われていたため終了/中断しなければならない場合や、単に読み込みを速くする目的で read-only でマウントし直したりする場合などです。

パッチの第1の目的はこれらを可能とすることです。 つまりメディアへの書込みが行われていることや、ドアがロックされずに “ファイナライズ” 処理が行われていることを知ることです。

第2に、どのようなファイルシステムでも断片化の問題を避けて通れません。 “断片化” とは次のようなことです。

例えば 2KB 単位のデータを扱う場合でもそのデータは物理的に 32KB 単位の塊で処理されるということです。 具体的には、2KB のデータを書き込む場合、まず 32KB の塊が読み込まれ、その内の 2KB に相当する部分が置き換えられ、最後にその変更された 32KB の塊が書き出されます。

“断片化を伴う要求(Fragmented requests)” とは、このように 32KB より小さいか、32KB の塊の間にまたがる要求のことです。 ドライブ内のファームウェアには処理最適化のためのキャッシングアルゴリズムが実装されていますが、これがどんな場合もうまく働くわけではありません。

不幸にもうまく機能しなくなった場合、ドライブは “COMMAND SEQUENCE ERROR (2Ch)” を返し、勝手にI/O処理を止めてしまいます。 この状況に対処するためには “SYNCHRONIZE CACHE (35h)” と呼ばれる MMC コマンドを発行し、ドライブのキャッシュをフラッシュさせて処理を継続しなければなりません。 これを行うようにすることが “DVD+RWサポート(パッチ)” の第2の目的です。

残念ながら上の段落の内容は第1世代のドライブ・・・すなわち Ricoh MP5120A およびその派生機には当てはまらないようです:-( 。 “SYNCHRONIZE CACHE (35h)” は効かないらしく、 “COMMAND SEQUENCE ERROR (2Ch)” を吐き続けて無限ループに陥るようです。 これでは任意のファイルシステムに対応させることはできません。とりあえずメディアがアンマウントされるまで I/O 処理を停止するようにしていますが、何か良い考えがあれば教えてください。

第2世代のドライブでもごくまれに、特殊な状況下で似たような[しかし異なる]動作をするものがあることが報告されています。 少なくとも私はそれを再現することができませんでした。 その問題はファームウェアのアップグレードで解消されたと報告されています。

ほとんどのベンダでは、[ほとんど?]のポスト第2世代のドライブについて、どうも DVD+RW の仕様、例えば “2KB のグラニュラリティ (粒状性=データの塊の単位) での真のランダムライト” のような部分への準拠を怠っているようです。

ベンダ側は、DVD-RW の Restricted Overwrite と似た方法を使ってホスト側で処理することを期待しているようです。 具体的には、ホスト側で複数の 2KB の書込み要求を DVD ECC ブロックサイズである 32KB にまとめ、書き込むようにすることです。 本来はそんなことを要求されるのは筋違いです。が、これが業界の実情なのです。

私はこの手の問題に随分悩まされています。 あるドライブはベンダ固有のポジショニングエラーコードである 03h/15h/82h などを吐いて止まってしまうことがありました。 特にメディアが新しくフォーマッティングされた場合に見られるようです。

理由はいくつか考えられます。 そのひとつは、ブロックバッファキャッシュのリオーダーリクエストにより、キャッシュの内容の連続性が失われた状況です。 これは “FLASH CACHE” により起こると考えられます。

もう一つは、“アンダーラン” の状態でバックグラウンドフォーマッティングが始まり、これを明示的に停止させなければならない状況です。 “アンダーラン” を強調したのは、ドライブ側でデータの流れが止まった状況に対処すべきだからです。

もしこの状況に陥ったら(多分陥ることになると思いますが)、growisofs のコマンドラインの最初に -poor-man オプションを付加してみてください。 このオプションはリオーダーリクエストを抑止すると共に、“アンダーラン” 状態が発生する可能性を低くします (VMサブシステムへの過負荷防止機能を外すことで)。

最初は DVD+RW サポートを drivers/cdrom/cdrom.c に組み込むつもりでした。 しかし残念ながら SCSI レイヤは WRITE コマンドの発行可否を制御するための独自の “書込み可” フラグを持っており、これがCD-ROM 共通ドライバ (sr_mod.c) から見えないため、諦めざるを得ませんでした。

IDE ドライブしかないのになぜ SCSI ドライバを? と思うかもしれませんが、同じドライブを使ってcdrecord でCD-R['W'] を焼く場合、ide-scsi エミュレーションレイヤを経由するからです。 だから DVD+RW 用なのにSCSI CD-ROM ドライバに注目せざるを得ないわけです。

残念ながら必要なもの全てを sr_mod.o に組み込むのは不可能でした :-( 。 メディアに書込許可可能かどうかが判断される前にメディアをセンスしなければならないため、 drivers/cdrom/cdrom.c の小変更が必要なのです。 DVD+RW ドライブはマウントされるメディアによってその特性を変えるため、新しいメディアが挿入されたことを真っ先に検出する必要があるのです。

“what a dirty hack!!!” というコメントについて

驚いたことに cdrom_generic_command で渡されたはずのタイムアウト値は無視され、常に30秒という固定値になってしまいます。 この値はフォーマッティングをするには短すぎるため、何らかの対策が必要でした。

本来なら、sr_do_ioctl 関数に引数を追加してタイムアウト値を渡せるようにし、その関数をコールしている個所をしらみつぶしに探して変更していくべきなのですが。 結局 私は既存の “quiet” 引数の未使用の 31bit を流用することにしました (コールしている個所を全部変更するなんて大変です)。 これが “what a dirty hack !!!” の由縁です。

ただし (CDROM_SEND_PACKET か SG_IO ioctl のいずれかにより) タイムアウト値がカーネルに届く方法を思いついたとしても、どのような値を渡したら良いのかはっきりしません。

(私も含め :-) 常識のあるプログラマなら誰でもプラットフォームに依存しない形で実装しようと思いますよね。 タイムアウト値ですからミリ秒が妥当でしょうか。 しかし CDROM_SEND_PACKET についてのドキュメントがなく不明です。

SG_IO のドキュメントは存在し、ミリ秒であると書かれていますがこれは正しくありません。 カーネルはこの値を “jiffies” という単位で扱います。 これはタイマ割込みの間隔に相当し、まさにプラットフォームに依存するものです。

では百歩譲って “jiffies” にしてしまえば良いのでしょうか? [本稿執筆時点では]それもまずいことになりそうです。 問題は['IA-32']カーネル開発者たちは “jiffy” のように短くした方がクールかどうかということばかりに執着しており、その絶対値がいくらか,伝統的な(タイムスライス)値である 10ms に対してどの程度の割合かなどについて気にしようとしないことです。

dvd+rw-format を作っていた時に問題となったカーネルの別の“欠陥”があります。 ドライブはバックグラウンドフォーマッティングの経過カウンターに相当するステータスを提供しますが、残念なことにそれを取得できないのです。

経過カウンターは SCSI の [“TEST UNIT READY”コマンドへの応答として] “NO SENSE/LOGICAL UNIT NOT READY/FORMAT IN PROGRESS” センスバイトとして返され、その場合の応答ステータスは “GOOD” です。問題は SCSI レイヤでは応答ステータス “GOOD” のセンスデータは捨てられてしまうことです。 Acard 社製 SCSI to IDE ブリッジ経由で動作する DVD+RW ドライブでこのことを知りました。

DVD+RW/+R の “プラス” の由来は?

もともとこの段落は次のように始まっていました。

DVD+RW/+R メディアの特徴は高い[空間]周波数を使ってアドレス情報で変調されながらウォブリングされた[プリ]グルーブである。 これにより中断された[または故意に中断した]書込み処理は非常に高い精度で再開でき、結果として DVD['-ROM'] プレーヤでの再生に全く支障をきたすことはありません。
一方、DVD-RW/-R ではバッファアンダーランからの回復処理における精度は平均的なプレーヤが許容できる程度のレベルです。 これは一見問題ないよう見えますが、この精度が書込みと読み出しの両方で影響するとすれば、書込み時にバッファーアンダーランを起こした DVD-RW/-R がどんなドライブでも読めるという保証はありません。

実は DVD-R['W'] について認識不足があり、訂正しなければなりません。 DVD-R['W'] のグルーブもバッファーアンダーランからの回復を行うのに十分な精度をもつということです。 DVD+RW ほど高精度ではないものの、理論的にはどのような DVD-ROM/-Video ドライブでも再生できるようにするだけの十分な精度をもちます。

しかしながら実際 DVD-R['W'] への記録を行う場合は次の点に注意すべきでしょう。

  • バッファーアンダーラン防止機能を有効にし
  • DVD-ROM/-Video完全互換にする

後者は単に Disc-at-once モードを選び、最後まで記録が中断されなかった場合に限り満たされます。 くどいようですが、ほとんどのベンダが DAO モード(*) におけるロスレスリンクを実装していますが、DVD-ROM/-Video 完全互換とするためにはバッファーアンダーランが発生しないことが重要です。

バッファーアンダーランが起こったセクタには一定のリンキングチャンクが見られ、これがユーザデータにおける数バイトの欠損として表れます。 ただしこれは ECC 処理(**)で訂正できる範囲と考えられます。

これに対し DVD+ の場合の継続部分は僅か数ビット分である上、ユーザデータではなく同期パターンとみなされます。 ですから例え DVD+ の記録でバッファーアンダーランが起こったとしても、DVD-ROM ドライブでは検出されません。 このような理由から一般に DVD+RW/+R の方が不意のバッファーアンダーランに強くDVD-ROM/-Video との互換性が高いと言われるわけです。

既に触れましたが、DVD+ のグルーブは “アドレス情報で変調されて” います。 これは ADIP (ADress In Pre-groove) と呼ばれます。

これにより DVD+RW への記録は完全に任意の順序で行うことができます。 未使用ディスクでもほとんど即座にです (およそ40秒の初期フォーマットが必要なだけです)。 さらに DVD+RW では 2KB という小さな単位(***)で書き込めるという便利さがあります。

これに対し DVD-RW では上書きの場合にのみ任意の順序で記録を行うことができます。つまりディスク全面を任意の順序で書込み可能とするためには、最初に完全なフォーマッティングを行う必要があります (1倍速メディアで約1時間かかります)。 そうでなければ最初からシーケンシャルに書き込んでいくしかありません。

そしてもう一つ注意しなければならないのは、[互換]Disc-at-once モードや追記モードで記録されたメディアではブロックオーバーライトはできないということです。これを可能とするには全面ブランキングを行うしかありません。

DVD-R['W'] と違い、DVD+R['W'] の記録は任意のタイミングで中断することができます。 またその副作用もありません。次の状況を考えてみてください。

一つのファイルを書き込むデータが 2KB という小さな単位で次々と、ただし比較的低いレートでやってきます。 そうなると直前に記録されたデータが頻繁に読み出されることになり、記録は中断されてしまいます。

特に DVD-R [およびDVD-RWのシーケンシャル記録] の場合は、この中断により記録されるファイルに“穴”が開いてしまいます。この“穴”とはリンキングエリアと呼ばれる 32KB の大きさのギャップのことです。このため、ファイルの記録が完了するまで待つか、穴の開いたファイルの扱い方を考える必要があります。

それに対し、DVD+R では同様のケースでも、中断されたポイントから記録を再開させることができます。 これは ADIP のおかげです。 DVD-R の場合でも Restricted Overwrite モードの場合はギャップは作られません。 しかしメディアが最小限のフォーマッティングしか行われていない場合は、記録の中断/再開の処理が必要となり、これに約40秒かかることになります。 DVD+R ではメディアの状態に関わらず、記録の中断/再開処理は一瞬で行われます。

結局何が言いたいか? (賢明な読者はお気付きだと思いますが)つまり DVD+R を任意のファイルシステムで利用できるようにすることは実に簡単なことなのです。 対象となるファイルシステムのドライバに手を加える必要は無いのです。リアルタイムVBR (Variable Bit Rate: 可変ビットレート)記録だって子供のゲームほど簡単です。

時々 DVD+RW/+R の記録方式はパケット記録方式であるかのように言われることがありますが、私はそう呼ぶ (または TAO/SAO/DAO などと呼ぶ) ことに抵抗があります。

DVD-R['W'] では(パケット/エクステントに限り)ロスレスリンキングが可能ですが、パケット/エクステントを Disc-at-once などと区別するためのリンキング情報が必要になります。

DVD+RW/+R メディア、正確にはそのデータゾーンには、そのようなリンキング情報は存在せず、Disc-at-once で焼かれた DVD-R['W'] や通常の DVD-ROM と論理的に等価になります。 これは DVD+ の記録がグルーブからの信号によって制御されるからです。 この仕組みがホコリやキズへの耐性を高めているわけです。

(*) Mt.Fuji のドラフトによれば、DVD-R DAO においてはバッファアンダーラン防止機構について何も記述されておらず、DVD-RW のインクリメンタルシーケンシャルモードの記述の中でのみ定義されています。 このドラフトでは DVD+RW についても検討されています。 しかし彼らが参照しているのは、DVD+RW/+R の実装について十分な議論が行われなかった中途半端なバージョンであることに注意してください。
(**) ECCの冗長性はかなり高いため、リンキングチャンク程度は問題にならなりません。ですから実際はそれがメディア再生に影響するとは考えられません。
(***) DVDの本来のブロックサイズは32KBであり、2KB単位での記録は問題ないように思えますが、実際2KBを書き込むのには、まず32KBを読み、その中の2KB分を置き換えた上で32KBを書き戻すというような複雑な処理が必要です(読み出しは単純です)。

訳者注
Mt. Fuji (group)
PCとドライブ間のコマンドセットの標準化を策定する企業グループ。
[プリ]グルーブ: pre-groove
トラックの案内溝。最初から形成されているものをプリ・グルーブという。
ウォブリング: wobbling
グルーブの溝をメディアの半径方向にわざと波打たせること。これをプレーヤで検出することで録再生における同期クロックを生成する。
高い[空間]周波数を使ってアドレス情報で変調・・・
ウォブリングを一定周波数で行うのではなく、位相変調をさせて位置アドレス情報をもたせる(ADIP)。「高い空間周波数」とは、DVD+のウォブリング周波数、つまり変調のベースとなるキャリア周波数がDVD-の140.6KHzに対し、817.4KHzと高いということである。