4Kセクタ問題

先日、SDカード上にスワップ領域を作成した際に、2つ目のパーティション作成時に開始セクタと初期値が異なっていたので気になって調べてみました。

1.0.2 SDカード上にスワップ領域を作成」の以下の部分が該当します。

パーティション番号 (2-4, default 2):
First sector (3880441-15523839, default 3880960):

開始セクタは「3880441」ですが、初期値(default)は「3880960」です。

開始セクタ default
3880441
-15523839
3880960

これは、4Kセクタ問題と呼ばれるもので、久しく新品ディスクのパーティショニングをしていなかったので忘れていました。
※普段は領域は1つですし、テスト機はBigDrive非対応が多いので

4Kセクタ問題

4Kセクタアライメント問題とも呼ばれます。
2009年末に発売されたHDDに端を発する問題です。
当該ディスクはAFT(Advanced Format Technology)・従来のディスクは非AFTなどと表現されます。
現在では、よほど古いものでなければ(ハードウェア・OS・ファイルシステムともに)対応済みです。
ただ、使用方法により性能に影響が出ることがあり、現在でも課題として残っています。

base on WD「Advanced Format」HDD提供開始 - ユーザー領域が7-11%拡大 | マイナビニュース

米Western Digital(WD)が「Advanced Format Technology」を搭載したハードディスクドライブ(HDD)製品の提供を開始した。
従来のHDDよりもユーザーが使用できるディスク領域が7-11%拡大される。

通常HDDには512バイトのセクタが用いられており、セクタごとにSync/DAM(リードイン)とエラー訂正コード(ECC)、セクタギャップが存在する構造になっている。
Advanced Formatは物理上の1セクタを4,096バイトに拡大。
従来Sync/DAMとECCが8つずつ必要だったものが、Sync/DAMとECCひとつずつの構造になる。
これによりユーザーデータを記録する領域が拡大され、またセクタごとにより長いECCが用いられることでデータの整合性も向上し、バーストエラー訂正が50%向上したという。

※文中の"Sync/DAMとECCひとつずつの構造"についてはリンク先(マイナビニュース)の画像が分かりやすいです

アライメントとは

ディスクのアライメントとは、ディスク上のデータ配置形式を指す言葉です。
アライメントの状態は、パーティションが作成される際に同時に作成されます。
つまり、既存のパーティションレイアウトを再利用するには注意が必要、ということです。
※アライメントの不整合によりデータが破壊されることはありません

Windowsの場合

Windowsの場合、"Vistaエディション SP1"以降に4Kセクタ対応になっています。

base on アドバンスド・フォーマット4Kセクター・ハードディスク・ドライブへの移行 | Seagate

オペレーティング・システム・リリース 4Kへの対応 結果
Windows XP 非対応 アライメント 1 の状態でプライマリ・パーティションを作成(非アライン)
Windows Vista—Service Pack 1以前 非対応 大容量セクタ対応ではあるが、不正なパーティションを作成(非アライン)
Windows Vista—Service Pack以降 対応 アライメント 0 の状態でパーティションを作成(アライン)
Windows 7 対応 アライメント 0 の状態でパーティションを作成(アライン)
  • ハードディスク・ドライブのパーティション作成には、Windows Vista(Service Pack 1 以降)またはWindows 7を使用してください。
  • サードパーティのソフトウェアやユーティリティを使用してハードディスク・ドライブのパーティションを作成する場合は、それらが4Kに対応しておりアップデートされているかをベンダーに確認してください。
  • Linuxを使用している場合は、使用中のシステムに4K対応のための変更が加えられているかを、Linuxのベンダーまたは技術組織に確認してください。

Linuxの場合

Linuxでは各ディストリビューションでパーティショニングツールが異なるため、ツール毎のバージョンで管理する必要があります。

base on libblkid, or why you don’t need to worry about 4K disk format

To solve this problem, libblkid provides topology information for block devices. This includes physical and logical block sizes. As of spring 2010, support for libblkid is available in all the standard tools:

fdisk, since util-linux >= 2.15. You should start with ‘-c -u’ to disable DOS compatibility and use sectors instead of cylinders.
parted, since parted >= 2.1. Parted defaults to 1 MiB alignment for unknown disks, which should align to just about any sector size. This includes gparted and other graphical tools such as the partitioner used in the Ubuntu desktop installer.
mdadm, since util-linux >= 2.15. It is no longer necessary to manually specify stride and stripe-width. All MD superblocks are positioned either at the end of the array (0.9 and 1.0) or in multiples of 4K from the beginning (1.1, 1.2).
lvm2, since util-linux >= 2.15.
mkfs.{ext,xfs,gfs2,ocfs2} all support libblkid directly.
If you’re uncertain, verify that your tool depends on util-linux or libblkid.

この問題を解決するために、libblkidはブロックデバイスのトポロジ情報(始点から終点までの接続状態)を提供します。これには、物理​​ブロックサイズと論理ブロックサイズが含まれます。2010年春、libblkidのサポートはすべての標準ツールで利用できます:

  • fdisk (util-linux >= 2.15)
    DOSの互換性を無効にし、シリンダーの代わりにセクターを使用するには、 '-c -u'で始める必要があります。
  • parted (parted >= 2.1)
    分割されたデフォルトは、不明なディスクの場合は1 MiBアライメントに設定されます。これはほぼセクタサイズに合わせる必要があります。これには、Ubuntuデスクトップインストーラで使用されるパーティショナなど、gpartedやその他のグラフィカルツールが含まれます。
  • mdadm (util-linux >= 2.15)
    ストライドとストライプ幅を手動で指定する必要はなくなりました。すべてのMDスーパーブロックは、配列の終わり(0.9と1.0)か、先頭から4Kの倍数(1.1,1.2)のいずれかに配置されます。
  • lvm2 (util-linux >= 2.15)
  • mkfs.{ext, xfs, gfs2, ocfs2}はすべてlibblkidを直接サポートします。

不確実な場合は、ツールがutil-linuxまたはlibblkidに依存していることを確認してください。

なお、OSやツールが対応していても、その上で動く仮想化技術(KVMなど)のツールまで対応しているとは限りませんので注意が必要です。
※関連する全てのレイヤでアライメントの妥当性が確認される必要があります

非AFTとは

30年近く続いてきた「セクタ=512byte」を前提に設計されたディスクです。
併せて「シリンダ=63セクタ」が慣例となっています。
平たく言うと、常に512byte単位(512byteの倍数)でデータの読み書きを行うディスクを指します。

base on http://www.atmarkit.co.jp/flinux/rensai/watch2010/watch03a.html

もうかれこれ20年以上も「1セクタ=512bytes」でやってきてしまったので、ありとあらゆるレイヤに512bytesを仮定している処理があり、簡単に変更できる状態ではありません。
そこでHDD業界は、物理セクタ長は4Kに変更するが、ソフトウェアから見える論理セクタ長は512bytesに据え置き、HDDのファームウェアでエミュレーションするという対策を取ることにしました。

AFTとは

かいつまんで説明すると、セクタ毎に用意する必要のある「Sync/DAM(リードイン)とECC(エラー訂正コード)、Sector Gap(セクタギャップ)」が8個 → 1個に減るので、面積あたりの記憶容量が増えるというメリットがあります。

例)セクタ長を 512byte → 4Kbyte(4096byte)に変更すると

種類 セクタ Sync/DAM +
Sector Gap
ECC 合計サイズ 効率
非AFT 512 40 40 592 86.49%
AFT 4096 100 40 4236 96.69%

※セクタ長を4096byteに増やした場合のECC長を100byteで計算しています(512byteセクタの40byteECCと同等のエラー訂正能力があると仮定
※効率は小数点以下2位を四捨五入しています

また、ディスク上の効率がUPするので、面積あたりの容量が増えます。

AFT利用における障壁

ディスク上の物理セクタサイズを4Kに変更したAFTは、従来のハードウェアでも利用できるようにエミュレーションさせることで対応しました。
(OS・コントローラからは、セクタサイズが 512byte のディスクに見える)。

ただ、従来 512byte を前提にコンピュータは設計されていたので、色々な課題が生まれました。

base on https://ja.wikipedia.org/wiki/容量の壁#2TiB(約2.2TB)の壁

LBAにより参照される論理ブロック (Logical Block) と物理セクタ(1セクタ512バイト)は伝統的に同一視されてきた。
即ち、「物理セクタサイズ=512バイト」はMS-DOS時代から変わutil-linux >= 2.15っておらず、既存のHDDコントローラー、ホストバスアダプタ、デバイスドライバー、BIOSやOS、さらにパーティションを直接操作するソフトウェアなどがこの前提で設計されている為、物理セクタサイズの変更はあらゆるコンポーネントとの非互換性が問題になる。

そこで、LBAの論理ブロックサイズ(論理セクタサイズ)は従来の512バイトから変更せずに、物理セクタサイズだけを4KiBに拡張する方法が取られた。
すなわち、OSやコントローラー側とは従来通りLBAによる512バイト単位でデータのやり取りを行い、物理メディアとのやり取りは物理セクタサイズの4KiB単位で行う。
これがAFT ("Advanced Format Technology") である。

Advanced Format Technology、AFT (en) は、HDD側の物理セクタサイズが4KiBであっても、OS、コントローラーからはセクタサイズ512バイトのHDDとしてアクセスできるようにエミュレーションを行う。

デバイスの物理セクタサイズよりも小さい単位での書き込みの場合、ドライブ側でリード・モディファイ・ライトが行われる。
そのため、特にパーティションの開始位置が4KiB単位の物理セクタ境界からずれた場合に大きな性能低下を引き起こす。
この性能低下は(殆どの製品が4KiB物理セクタである)NANDフラッシュ製品でも起こる

共通の仕様

PC/AT互換機では最初のパーティションは最初のシリンダから配置されるので、多くの場合は63セクタ目となります。

規格

規格名称 別名称 論理セクタ
サイズ(byte)
物理セクタ
サイズ(byte)
従来のHDD 非AFT / 512 Native 512 512
AFT Advanced Format Technology / 512E 512 4096
4K Native 4kn 4096 4096

まとめ

Lubuntu 16.04.3 の parted のバージョンは 3.2 です。

$ parted -v
parted (GNU parted) 3.2

バージョン2.1以上なので対応しており、8セクタの倍数に自動的に揃えられたことが分かります。

注意点

注意したほうが良い点としては、以下のサイトでは「util-linux >= 2.15」と紹介されていますが、以下のIBMのサイトでは「util-linux >= 2.18」となっています。
サイトごとに記載が異なるので、各ディストリビューションの情報を信頼するか、あるいは実際にアライメントを確認するのが一番確実だと感じました。

base on 4 KB セクター・ディスクで Linux を使用する: 実用的なアドバイス | IBM

4 KB セクタ・ディスクで Linux を使用する: 実用的なアドバイス
ディスクは通常 512 バイト単位のセクタに分割され、読み取り処理や書き込み処理はこのセクタ・サイズの倍数単位で行われることはご存知のはずです。
さらに詳しく見てみると、ハード・ディスクは、セクタとセクタの間にも追加のデータを記録するようになっており、これらの追加のバイトを使用して各セクタ内でのエラーを検出して訂正します。

Advanced Format ディスクは、4,096 バイトの物理セクタを 8 つの 512 バイトの論理セクタに分割します。
そのため、ファームウェアや、オペレーティング・システム、そしてすべてのディスク・ユーティリティーにとっては、物理セクタのサイズが 4,096 バイトであっても、ディスクのセクタ・サイズは 512 バイトであるように映ります。
その一方で、ファームウェアで見掛けのセクタ・サイズを変更すると、パフォーマンスが低下する恐れがあります。
その理由を理解するには、ファイルシステムのデータ構造と、ハード・ディスクでのパーティションの配置について理解する必要があります。

ファイルシステムのデータ構造がパフォーマンスに影響する理由
最近のファイルシステムのほとんどは、4,096 バイトまたはそれより大きいサイズのデータ構造を使用しています。
そのため、大部分のディスク I/O 処理はこの値の倍数単位で行われます。
ここで、Linux がこれらのデータ構造の 1 つに対する読み書きを、セクタ・サイズが 4,096 バイトの新しいディスク上で行うとしたらどうなるか考えてみてください。
ファイルシステムのデータ構造が、偶然にも、物理セクタの位置とぴったり合うように配置されているとしたら、4,096 バイトのデータ構造の読み書きは、単一セクタの読み書きとなるため、ハード・ディスクのファームウェアが特別な処理を行う必要はありません。
一方、ファイルシステムのデータ構造が、物理セクタの位置とぴったり合うようには配置されていない場合、読み書きの処理では 2 つの物理セクタにアクセスしなければならないことになります。

理論上、読み取り処理は、書き込み処理ほどには位置合わせされていないことによる影響を受けません。
ディスクからデータを読み取る場合、読み取り先の 4 KiB (キビバイト) のデータ構造は、ディスクの連続する 2 つのセクタにまたがっている可能性が高く、ファームウェアが 4 KiB のデータ構造を返すタスクは比較的単純です。
それとは対照的に、位置合わせされていないデータ構造を書き込む場合は、ディスクのファームウェアは 2 つのセクタを読み取り、両方のセクタの必要な部分を変更してから 2 つのセクタに書き込まなければなりません。
この処理には、その 4,096 バイトが 1 つのセクタだけを占有している場合よりも時間がかかります。
そのため、パフォーマンスが低下するというわけです。
実際には、位置合わせされていないことによる悪影響を、読み取り処理が書き込み処理と同じぐらい受ける場合もあります。

データ構造が適切に配置されているかどうかを判断するにはどうすればよいのでしょう?ほとんどのファイルシステムは、データ構造を、そのデータ構造を含めるパーティションの先頭に揃えます。
つまり、パーティションの先頭が 4,096 バイト (8 セクタ) の境界上にあれば、データ構造は適切に配置されていることになります。
しかし 2010年になるぐらいまでは、Linux パーティショニング・ツールが作成するパーティションは 4096 バイトの境界に位置合わせされていませんでした。
今でも落とし穴は残っているため、パーティションを作成するときには注意が必要です (一般的な Linux パーティショニング・ソフトウェアでパーティションを位置合わせする方法については、この後の「パーティションの位置合わせ」のセクションで説明します)。

パーティションの位置合わせ
ほとんどのディストリビューションで util-linux または util-linux-ng パッケージに含まれている fdisk ファミリーでは、かなり直接的に MBR データ構造を編集することができます。
しかしその一方で、ファイルシステムを作成または変更することはできません。
util-linux バージョン 2.17 までの fdiskは、8 セクタ単位でのパーティション位置合わせを直接サポートしていません。
つまり、位置合わせはシリンダ・ベースのままです。
これはバージョン 2.18 で変更され、このバージョンからは、fdisk はデフォルトでセクタ 2,048 に最初のパーティションの開始点を設定するようになりました。
fdisk で、1MiB (またはそれ以上) の倍数のパーティション・サイズを使用してすべてのパーティションを作成する場合、fdisk は 1MiB の倍数でパーティションの位置合わせを維持します。
これは、8 セクタの倍数でのパーティションの位置合わせになります。