4096 バイトセクタの HDD と Linux

先日 1TB クラスのハードディスクを買いに秋葉原へいってきました。ずいぶん安くなったものだなぁと感激しながら物色してたんですが、なぜかキャッシュ 64MB のほうが 32MB のものより安かったのでこりゃお得だろうと思いそちらを考えなしに買いました。

帰ってきて調べてみたら、買ったやつは 4096 バイトセクタのものでした。なんか Windows XP だとそのまま使うとパフォーマンスがでないとか聞いていた気はしていたんですが、まさかそれを買ってしまうとは。どうりでバッファ容量が大きいほう(つまり 4K セクタ)がどの店でも安いわけだ。

たしか Linux の場合だと大丈夫だよねと思いながら検索してみると、Linux でもパフォーマンスが落ちるという話が。うわーどうしようと思い、4096 バイトセクタ HDD と Linux についていろいろ調べてみました。

ただ、机上の調査であり実地検証はおこなっていないですし、ATA 仕様や Linux のブロックデバイスドライバまわりも明るくないので間違いも多々あるかもしれませんが、ツッコミ歓迎ということで。

結論から書くと、Linux で使う場合、(現状では)fdisk のエキスパートモードを使ってパーティション境界を 8 の倍数(セクタ)に指定してあげるとパフォーマンスはきちんと出ます。新規インストールするならあらかじめ別の(ブータブル Linux などの)OS などでパーティションを切っておく。ハードウェア RAID の場合どうすればいいかはわかんない。

  • 従来の HDD はセクタサイズが 512 バイトである
  • いまどきの OS は複数セクタをまとめたブロック単位で扱っている(たいてい 4096 バイト単位*1
  • 最近物理セクタサイズを 4096 バイト(4K)とした HDD が出荷されるようになってきた
  • 最終的には(業界全体の意向としては)外部インタフェースも含めて 4096 バイトセクタ(など 512 バイト以上)にしたい
    • だがそのためには、(ホスト側の)HDD コントローラ、BIOSブートローダ、OS の HDD コントローラデバイスドライバ、等々ハードウェア・ソフトウェア両面のアップデートが必要となる
  • 既存のハードウェア・ソフトウェアとの互換性維持のため、現在出荷されている(物理)4K セクタ HDD は、外部インタフェース向けとしては(論理)512 バイトセクタであるかのように振る舞う(エミュレーション)
  • エミュレーションによる 4K セクタ HDD は、論理セクタ*2(512 バイト)を1つ書き込む際、一度物理セクタ(4096 バイト)を HDD 内部のバッファに読み込み、該当する部分だけ*3を変更して物理セクタ全体を書き込む(read-modify write; RMW)
  • このままだと書き込みパフォーマンスが大幅に低下してしまう(単純計算で8倍)ので、同一物理セクタ内の論理セクタに連続して書き込む場合、HDD 内部のバッファにそれらを書き込んでからまとめて物理セクタに書き出している、複数セクタを書き込む場合、物理セクタサイズ境界で分割して一度に書き込む、と思われる(推測)
    • ATA の規格書(ATA/ATAPI-5 世代だけど)を読みました。WRITE DMA や WRITE SECTOR(S) コマンドでは複数セクタ(ATA-5 時代で最大256セクタ)を同時に(ホスト側から)書き込むことができます。ですので上記「同一物理セクタ内の論理セクタに連続して書き込む場合〜」というのは厳密には想定が間違っていました。
  • 前述したように、いまどきの OS ではブロックサイズ単位(現在はデフォルトでたいてい 4K)でディスクとやりとりするので、書き込み時のスループット低下はほぼおきなくてハッピー(のはず)
  • ところが
  • 「ハッピー」の前提は、HDD の物理セクタの境界と OS のブロック境界が一致していた場合の話
  • もし境界がずれている場合、1ブロックの書き込みに対して、物理セクタ1つの読み書きが2つ分発生する(ブロックサイズ 4K の場合)→スループットが1/2に低下
  • 古典的な DOS パーティションテーブルでは、通常、パーティションの境界はシリンダ単位としている
    • 実際にはパーティション境界はセクタ単位で指定できる(しブートも可能)が、歴史的経緯からシリンダ単位で切り上げするのが定番となっている
  • 歴史的経緯により現在(仮想的な)シリンダは 63 セクタから構成されているとみなされる
  • 63 は 8 の倍数ではないので、シリンダ境界はたいてい*4物理セクタの境界と一致しない
  • ブロックサイズ自体は 4K なので、パーティション内の各ブロックの境界はすべて物理セクタの境界と一致しない
  • オワタ\(^o^)/
  • さて
  • Western DigitalWindows XP では HDD をそのまま使うと性能がでないが、Linux ではそのまま使ってよいとしている*5
  • 実際、理論上、(DOSパーティションテーブルのパーティション境界を 8 セクタ単位にすれば、書き込み性能の劣化はみられないはずである
  • しかしながら、現在のたいていの Linux ディストリビューション付属のパーティショニングユーティリティは、デフォルトでシリンダ単位(つまり 63 セクタ単位)でパーティションをわりふる
    • anaconda などのインストーラ組み込みのパーティショニングツールも含む
  • このため、何も考えずに 4K セクタ HDD を Linux を使うと、書き込み性能が大幅に劣化する
    • シーケンシャル書き込みで 40%、ランダム書き込みで 30% に書き込み速度が低下
  • というわけで
  • 現在、Linux で 4K セクタ HDD を使う場合
    • あとから追加する HDD なら、fdisk のエキスパートモード(x コマンド)においてパーティションの開始セクタを(b コマンドなどで)8 の倍数に設定する
    • インストール時に使用する HDD であれば、KNOPPIXUbuntu Live mode や SystemRescueCd などをあらかじめ立ち上げて上述する方法でパーティションを切っておき、そのパーティションにインストールすればよい
      • たしかめていないけど、Windows XP でもインストール後に WD Align utility を利用しなくても、インストール前に上記のように CD ブート Linux などでパーティションを切っておけばうまくいくと思う
  • 今後の Linux ディストリビューションでは、物理セクタサイズに対応したパーティションテーブルを作成できるようになるはず
    • ただしたとえば Fedora 13 とか Ubuntu 10.10 とか?の話であって、RHEL 5 などにバックポートはされないと思う(推測)

参考文献

*1:ちなみに x86 アーキテクチャのページサイズも 4096 バイトである(自信なし)ので、この倍数にしておくといろいろ都合がよい。

*2:OS 側の論理セクタという意味ではなく、あくまで HDD 側のエミュレーションレイヤにおける論理的セクタ

*3:実際には物理セクタ全体の ECC を計算して書き込む必要がある。

*4:もちろん、第2パーティション以降でたまたまシリンダ境界が物理セクタ境界と一致することもありえる。

*5:実際にはそのような記述は見当たらなかった。HDD に添付された注意書きでは、「All other OS」というくくりになっているし、Advanced Format に関するページには Mac OS の表記はあるものの Linux の表記はない。