はじめに
Linuxサーバでは、HDD、SATA SSD、SAS Storage、NVMe SSDなど、さまざまなStorage Deviceが利用されています。これらはすべてデータを保存する装置ですが、記録媒体、接続Interface、Commandを処理する仕組みが異なります。
一方、Applicationから見ると、いずれもFilesystem上のファイルとしてread()やwrite()で操作できます。Linux Kernelは、VFS、Filesystem、Page Cache、Block Layer、Device DriverなどのレイヤーによってHardwareの違いを隠し、共通したファイルI/Oを提供しています。
Storageを理解するときに注意したいのは、HDD・SSDという記録装置の分類と、SATA・SAS・PCIeという接続Interface、AHCI・SCSI・NVMeというCommand処理の仕組みを混同しないことです。特に「SSDとNVMeは同じ分類」と考えると、全体像が分かりにくくなります。
Linux I/O連載の最終回となる本記事では、性能の優劣には深入りせず、同じLinux Block I/OでもBlock Layerより下の経路はStorage Deviceによって異なる、という点を中心に整理します。最後に、ApplicationからHDD・SSD・NVMeへI/Oが届くまでの連載全体を一本につなげます。
HDD・SSD・NVMeをどう整理すればよいのか
HDDとSSDは記録媒体・デバイスの違い
HDDとSSDは、データを保存するDeviceと記録媒体の違いを表します。HDDは回転する磁気Diskを利用し、SSDは一般にNAND Flash Memoryを利用します。
HDDにはPlatterやHeadなどの機械部品があり、目的のデータへ到達するまでSeekと回転待ちが発生します。SSDには同様の機械的動作がなく、ControllerがNAND Flash上のデータを電気的に読み書きします。
SATA / SAS / PCIeはHostとStorageをつなぐ仕組み
SATA、SAS、PCIeは、HostとStorageを接続するInterfaceに関係する用語です。HDDはSATAやSASで接続され、SSDはSATA、SAS、PCIeなどで接続されます。
| 分類 | 主な用語 | 表しているもの |
|---|---|---|
| 記録Device・媒体 | HDD、SSD | データをどのような装置・媒体へ保存するか |
| 接続Interface | SATA、SAS、PCIe | HostとStorageをどの経路で接続するか |
| Command処理 | ATA / AHCI、SCSI、NVMe | どの形式でI/O Commandを発行・完了するか |
AHCI / SCSI / NVMeはCommandを扱う仕組み
AHCIは、OSがSATA Host Controllerを操作するためのInterfaceです。SCSIはStorageなどを操作するCommand体系とArchitectureで、SASをはじめ複数のTransportで利用されます。NVMeはPCIe接続の不揮発性Memory向けに設計されたCommand SetとInterfaceです。
LinuxではSATA Deviceもlibataを通じてSCSI Subsystemへ統合され、/dev/sdaなどとして見えることがあります。そのため、Linux上のDevice名だけから物理Interfaceや内部経路を断定することはできません。
「SSD = NVMe」ではない
SSDは、主にNAND Flashを利用するStorage Deviceです。NVMeは、そのような不揮発性MemoryをPCIe上で効率よく利用するために設計されたStorage Interface / Command Setです。
したがって、SSDにはSATA SSD、SAS SSD、NVMe SSDなどがあります。すべてのSSDがNVMeではなく、NVMeという名称だけで記録媒体の種類を完全に表しているわけでもありません。
HDDの仕組み
HDDの仕組みをまとめると以下の通りです。

Platter / Head
HDDの内部には、磁性体を塗布した円盤であるPlatterがあります。PlatterはSpindle Motorによって回転し、Actuatorに取り付けられたHeadが表面のデータを読み書きします。
目的のTrackへHeadを移動する時間をSeek Time、目的のSectorがHeadの下へ来るまでの待ち時間をRotational Latencyと呼びます。離れた位置へのRandom I/Oでは、これらの機械的な待ち時間が繰り返し発生します。
Sector
Platter表面は同心円状のTrackとして整理され、TrackはSectorへ分割されます。SectorはHDDがデータを記録・管理する基本的な単位です。
Hostへ公開されるLogical Sector Sizeと、Device内部のPhysical Sector Sizeが異なる場合があります。例えば512eでは、Hostへ512Byte Sectorとして見せながら、内部では4KiB単位で処理します。PartitionやFilesystemのAlignmentが不適切だと、余分なRead-Modify-Writeが発生する可能性があります。
LBA(Logical Block Addressing)
LBAはLogical Block Addressingの略で、Storage上の領域を連続した番号で指定する方法です。LinuxやStorage Controllerは、Platter、Head、Trackを直接指定せず、「LBAの何番から何Blockを読む」といった形でI/Oを要求します。
HDD内部のControllerがLBAを実際の記録位置へ対応付けます。障害Sectorを予備領域へ置き換えるReallocationが行われると、Hostから見えるLBAを変えずに内部の物理位置だけが変化することもあります。
LinuxからはBlock Deviceとして扱う
LinuxはHDDをBlock Deviceとして扱います。Block Layerは論理Sectorを指定したRead / Write RequestをDevice Driverへ渡し、Driverが接続Interfaceに応じたCommandを発行します。
Applicationは通常、HDDの物理構造を意識しません。Filesystem上のファイルをread()やwrite()で操作し、FilesystemとBlock Layerがファイル内の位置をBlock Device上の領域へ変換します。
SSDの仕組み
SSDの仕組みをまとめると以下の通りです。

NAND Flash
一般的なSSDは、電源を失ってもデータを保持できるNAND Flash Memoryを利用します。Memory Cellの電荷状態によって情報を記録し、一つのCellへ保持するBit数に応じてSLC、MLC、TLC、QLCなどに分類されます。
NAND Flashには書き換え回数の制約があり、既存データをその場で自由に上書きできません。そのため、SSD Controllerが書き込み位置とデータ移動を管理します。
Page / Block
NAND Flashは、一般にPage単位でReadとProgramを行い、複数PageをまとめたBlock単位でEraseします。Linux MemoryのPage、FilesystemのBlock、NAND FlashのPage / Blockは、それぞれ別レイヤーの単位です。
使用済みPageのデータを更新する場合、Controllerは別の空きPageへ新しいデータを書き、古いPageを無効として扱います。無効Pageが増えると、有効Dataを別の場所へ移動し、Block全体をEraseして再利用するGarbage Collectionを行います。
SSD Controller
SSD Controllerは、HostからのCommandを受け取り、NAND FlashへのRead / Program / Eraseを制御します。複数のNAND Channelを並列に使用し、Error Correction、Bad Block管理、Garbage Collection、Wear Levelingなども行います。
- Host Commandの処理
- NAND Flash上の保存位置の管理
- Garbage Collection
- Wear Leveling
- Error CorrectionとBad Block管理
FTL(Flash Translation Layer)
FTLはFlash Translation Layerの略で、Hostから見えるLogical Block Addressと、NAND Flash上の物理的な保存位置を対応付けます。HostはHDDと同じようにLBAを指定できますが、SSD内部ではFTLがNAND Channel、Chip、Block、Pageなどへ変換します。
Logical BlockとFlash上の物理位置の関係
同じLBAへ繰り返しwriteしても、毎回同じ物理Pageへ書き込まれるとは限りません。FTLは新しいPageへデータを書き、Mappingを切り替えます。これにより、NANDの上書き制約を隠し、書き換えを複数領域へ分散できます。
Filesystemが不要になったBlockをDiscard / TRIMで通知すると、SSDは対応するLBAのデータが不要であることを把握できます。これにより、将来のGarbage Collectionを効率化できる場合があります。
SATA SSDの仕組み
SATAとは
SATAはSerial ATAの略で、HostとStorage Deviceを接続するInterfaceです。HDDとSSDの両方で利用され、ATA CommandをSerial Link上で転送します。
SATA SSDは記録媒体としてNAND Flashを利用しますが、Host側からはSATA Deviceとして操作されます。したがって、「SSD」は内部の記録Device、「SATA」はHostとの接続方式を表しています。
AHCIとは
AHCIはAdvanced Host Controller Interfaceの略で、OSがSATA Host Controllerを操作するための標準的なInterfaceです。Native Command QueuingやHot Plugなどの機能を利用できます。
AHCIはHDDを含む従来のStorageを前提に設計された面があり、NVMeと比べるとQueue数や並列性が限定的です。ただし、SATA SSDの実際の性能はController、NAND、Firmware、Workloadなどにも左右されます。
SAS Storageの仕組み
SASとは
SASはSerial Attached SCSIの略で、SCSI CommandをSerial接続でやり取りするStorage Interfaceです。ServerやStorage Arrayで使用され、SAS HDDとSAS SSDの両方が存在します。
SASでは、HBA、Expander、Dual Portなどを利用したEnterprise向けの接続構成を取ることができます。冗長Pathを利用する場合、LinuxではDevice Mapper Multipathによって複数Pathを一つのDeviceへ統合することがあります。
SCSIとの関係
SCSIはStorageを操作するCommand体系とArchitectureであり、SASはそのSCSI CommandをSerial Linkで運ぶTransportです。SAS DeviceはREAD、WRITE、INQUIRYなどのSCSI Commandを処理します。
LinuxのSCSI Subsystemとの関係
Linuxでは、SAS HBA固有のDriverがSCSI Mid-Layerへ接続し、Disk型のDeviceはSCSI Disk DriverであるsdによってBlock Deviceとして登録されます。その結果、一般に/dev/sdaなどの名前で認識されます。
SATA DeviceもlibataによってSCSI Subsystemへ統合されるため、SATAとSASの両方が/dev/sdXとして見える場合があります。/dev/sdXという名前だけでは接続Interfaceを判断せず、lspci、lsscsi、udevadm、sysfsなどで経路を確認します。
SATAとSASの違い

| 項目 | SATA | SAS |
|---|---|---|
| 主なCommand | ATA | SCSI |
| 主な用途 | 一般PC、Server、単体Storage | Enterprise Server、Storage Array |
| 接続構成 | 比較的単純 | ExpanderやDual Portなどに対応 |
| Device | SATA HDD / SSD | SAS HDD / SSD |
SAS ControllerがSATA Deviceを扱える構成もありますが、SATA ControllerへSAS Deviceを接続できるわけではありません。Connectorの形だけでなく、ControllerとProtocolの対応を確認する必要があります。
NVMeとは

NVMe(Non-Volatile Memory Express)
NVMeはNon-Volatile Memory Expressの略で、不揮発性Memoryを効率よく利用するために設計されたStorage Interface / Command Setです。Flash Storageの低いLatencyと高い並列性を活かせるCommandとQueueの構造を持ちます。
PCIe上で利用されるStorage Protocol
一般的なLocal NVMe SSDはPCI Express Busへ接続されます。NVMe DriverはMemory-Mapped I/Oを通じてControllerのRegisterへアクセスし、Host Memory上にSubmission QueueとCompletion Queueを用意します。
利用可能な帯域はPCIeの世代、Lane数、CPUとのTopologyなどにも左右されます。また、NVMe over FabricsではNetwork Fabric上でNVMe Protocolを利用しますが、本記事では主にPCIe接続のLocal NVMe SSDを扱います。
SATA / AHCIを経由しない
NVMe SSDはSATA LinkやAHCI Controllerを経由しません。LinuxのNVMe DriverがPCIe上のNVMe Controllerを直接操作します。したがって、SATA SSDを高速化しただけの仕組みではなく、CommandとQueueを含むI/O経路そのものが異なります。
NVMe DriverとNVMe Controller
LinuxのNVMe DriverはControllerを初期化し、Admin QueueとI/O Queueを構成します。Controllerは一つ以上のNamespaceを公開し、各NamespaceがLogical Blockの集合として扱われます。
Linuxでは、Controller 0のNamespace 1が/dev/nvme0n1のように見えます。SSD内部ではNVMe ControllerがLBAとFTLを通じ、実際のNAND FlashへのI/Oを処理します。
NVMeのQueueの仕組み
Submission Queue
Submission Queueは、HostがNVMe Controllerへ実行してほしいCommandを登録するRing形式のQueueです。DriverはREAD、WRITE、FLUSHなどのCommand Entryを追加し、Doorbell Registerを更新してControllerへ通知します。
Completion Queue
Completion Queueは、NVMe Controllerが処理を終えたCommandの結果を返すQueueです。完了したCommandの識別情報とStatusが登録され、DriverはInterruptまたはPollingによって結果を確認します。
NVMe Command
NVMe Commandには、対象Namespace、開始LBA、Block数、Data Bufferを示す情報などが含まれます。Controller管理用のAdmin Commandと、Dataを読み書きするI/O Commandがあります。

複数Queueを利用する仕組み
NVMeは複数のI/O Queueを利用できます。QueueをCPUへ分散すれば、複数CPUが一つの共有QueueとLockへ集中することを抑え、複数のI/Oを並列に発行できます。
実際に作成されるQueue数は、ControllerのCapability、CPU数、MSI-X Vector数、Driver設定などによって決まります。常にCPU Coreと同数のQueueが使われるわけではありません。
blk-mqとの関係
Linuxのblk-mqは、複数CPUから発生するBlock I/OをSoftware Queueで受け付け、Hardware Dispatch QueueからDevice Driverへ渡します。NVMe Driverは、blk-mqのHardware QueueをNVMeのI/O Queueへ対応付けます。
blk-mqのHardware QueueとNVMe Controller内のQueueは別レイヤーの概念ですが、Driverによって密接にMappingされます。これにより、Linux Block LayerからNVMe Hardwareまで並列性を維持したI/O経路を構成できます。

LinuxからHDD・SSD・NVMeはどう見えるのか
/dev/sda
/dev/sdaは、LinuxのSCSI Disk Subsystemを通じて公開された最初のDiskに使われる代表的な名前です。SAS Diskだけでなく、libataを経由するSATA HDDやSATA SSD、USB Storage、Hardware RAIDのLogical Diskなども/dev/sdXとして見える場合があります。
そのため、/dev/sdaという名前だけではHDDかSSDか、SATAかSASかを確定できません。Device属性、Transport、Driver、回転Device Flagなどを別途確認します。
/dev/nvme0n1
/dev/nvme0n1は、NVMe Controller 0のNamespace 1を表すBlock Deviceです。nvme0がController、n1がNamespaceを示します。一つのControllerが複数Namespaceを公開する場合もあります。
Partitionとの関係
| Disk | Partition 1 |
|---|---|
| /dev/sda | /dev/sda1 |
| /dev/nvme0n1 | /dev/nvme0n1p1 |
NVMeのDevice名は数字で終わるため、Partition番号の前にpが入ります。PartitionはDiskのLBA範囲を分割したLogical Block Deviceであり、その上にFilesystemやLVM、暗号化Layerなどを構成できます。
Block Deviceとして共通して扱える理由
LinuxのBlock LayerとDevice DriverがHardwareの違いを抽象化するため、HDD、SATA SSD、SAS SSD、NVMe SSDはいずれもBlock Deviceとして扱えます。
Filesystemは共通のBlock I/O Interfaceを利用し、その下でSCSI・ATA系DriverやNVMe Driverが各Deviceに適したCommandへ変換します。上位のApplicationはDevice固有のCommandを意識せず、同じread()やwrite()を利用できます。
HDD・SATA SSD・NVMe SSDのI/O経路を比較する

HDD / SATA SSD
HDDとSATA SSDは記録媒体が異なりますが、どちらもSATA Deviceであれば、LinuxからのI/Oはlibata、SCSI Subsystem、AHCI Driverなどを経由してATA Commandとして届きます。
Commandを受け取った後、HDDではControllerがLBAを磁気Disk上の位置へ対応付け、HeadとPlatterを使って処理します。SATA SSDではSSD ControllerがFTLを通じてNAND Flash上の位置へ対応付けます。
SAS HDD / SSD
SAS HDDやSAS SSDでは、Block LayerからSCSI Subsystemを経由してSAS HBA固有のDriverへI/O Requestが渡されます。HBAはSCSI CommandをSAS Link上でDeviceへ送り、DeviceがRead / Writeを処理します。
NVMe SSD
NVMe SSDではSATA、AHCI、SCSI Disk Driverを経由せず、Block LayerからNVMe DriverへI/O Requestが渡されます。NVMe DriverはCommandをSubmission Queueへ登録し、PCIe経由でControllerへ通知します。
NVMe ControllerはDMAによってDataを転送し、内部のFTLを通じてNAND Flashへアクセスします。処理結果はCompletion Queueへ登録され、InterruptまたはPollingによってDriverが完了を検出します。
つまり、FilesystemとBlock Layerまでは共通でも、その下で利用するDriver、Command、Controller、接続Interfaceが異なります。この違いが本記事で最も重要なポイントです。
まとめ
HDDとSSDはStorage Deviceと記録媒体の違い、SATA・SAS・PCIeは接続Interface、AHCI・SCSI・NVMeはCommandを扱う仕組みに関係する用語です。SSDにはSATA SSD、SAS SSD、NVMe SSDがあるため、「SSD = NVMe」ではありません。
HDDは磁気PlatterとHeadを使い、LBAを実際の記録位置へ対応付けます。SSDはNAND Flashを利用し、FTLがHostのLBAをNAND上のPageへ対応付けます。同じLogical Block I/Oでも、Device内部の処理は大きく異なります。
Linuxでは、HDDやSATA SSD、SAS Storageは一般に/dev/sdX、NVMe Namespaceは/dev/nvmeXnYとして見えます。名前は異なりますが、Block LayerとDevice Driverによる抽象化によって、Filesystemからは共通のBlock Deviceとして利用できます。
一方、Block Layerより下では、SCSI・ATA系DriverとAHCI / SATAを通る経路、SAS HBAとSCSIを通る経路、NVMe DriverとPCIeを通る経路に分かれます。つまり、同じLinux Block I/Oでも、Block Layerより下の経路はStorage Deviceによって異なります。
本連載では、Applicationのread() / write()から、VFS、Filesystem、Page Cache、Block Layer、Device Driver、そしてStorageまでを順番に解説してきました。各レイヤーの役割と境界を理解することで、LinuxでI/Oが遅い場合やDeviceが認識されない場合にも、問題がどの層で発生しているのかを体系的に切り分けられるようになります。


コメント