NVMeにはNamespace(名前空間)という機能がある。NVMeデバイスの記憶領域を論理的に分割し、それぞれを独立したNVMeストレージのように扱う機能である。
馴染みあるところだとパーティションのようなものだが、ファームウェアレイヤーでの分割となり、名前空間同士には明確な前後関係はなく、OSからは別のデバイスとして見えるのが大きな違い。ハードウェアRAIDの仮想ドライブ、ZFSのデータセットに近い。
名前空間を使うと以下の効能が見込めるとされる。
名前空間はオプション機能なので、大半のNVMe SSD製品、特にコンシューマ向けは最大1つの名前空間しかサポートしてなかったりして残念ではあるが、使えれば色々遊べそうな機能だ。個人的には仮想と物理を行き来するような構成でディスク管理の簡単化への期待が高まる(弊宅ではPromoxVEと一部VMのRDM用パーティションが同じSSD上にあり、だいぶ面倒な運用となっている。名前空間でデバイスを割ることができれば、非常にシンプルになるハズ。)
FreeBSDerのわたくしといたしましては、FreeBSDのnvmecontrol
コマンドで試したかったのだけれども、バグで名前空間が作れないという致命的な問題があったので、やむなくLinux環境で試すこととなった。なお、バグは13.2-RELEASEで修正される模様。
まずは現在のNVMe SSDの状態を確認する。
デバイスの認識状況:
$ sudo nvme list Node SN Model Namespace Usage Format FW Rev --------------------- ------- ---------------------------------------- --------- -------------------------- ---------------- -------- /dev/nvme0n1 Serial SAMSUNG MZ1L21T9HCLS-00A07 1 0.00 B / 1.92 TB 512 B + 0 B GDC7302Q
使用可能なLBAフォーマット:
$ sudo nvme id-ns -H /dev/nvme0n1 | grep ^LBA LBA Format 0 : Metadata Size: 0 bytes - Data Size: 512 bytes - Relative Performance: 0 Best (in use) LBA Format 1 : Metadata Size: 0 bytes - Data Size: 4096 bytes - Relative Performance: 0 Best
既存の名前空間から使用可能なLBA形式を取得しておく。
というのも、後ほど名前空間作成時に使うのだけれども、名前空間がない状態でこのリストを取得する術が無さそうなのだ。いざとなれば、てきとーなLBA形式で名前空間作成後、希望の形式で再フォーマットしてやれば済む話だが、二度手間は避けたいので。
NVMeコントローラの一覧:
$ sudo nvme list-ctrl /dev/nvme0 num of ctrls present: 1 [ 0]:0x6
NVMeデバイスでは複数のコントローラを持つことができ、名前空間はコントローラに割り当てる形となっている。この値も後ほど使うのでメモっておく。
NVMeコントローラの詳細:
$ sudo nvme id-ctrl /dev/nvme0 | grep -E 'nn|nvmcap' tnvmcap : 1920383410176 unvmcap : 0 nn : 32
tnvmcap
はTotal NVM Capacity、unvmcap
はUnallocated NVM Capacityのことで、それぞれNVMeデバイスの合計容量と未確保容量をバイト単位であらわす。
nn
はNumber of Namespacesで、本記事の肝であり、デバイスがサポートする名前空間の数である。これが1だと話にならない。
上記の実行結果からは、本SSDは最大32個の名前空間が使えるものの、現在の空き容量が0なのでこれ以上の名前空間の追加は不可ということになる。
nvme delete-ns
で既存の名前空間を削除する。
言うまでもないが、削除された名前空間にあったデータは全て消失する。確認プロンプトも出ず、デバイスレベルでの管理情報が消えることとなり、データの復元は個人レベルでは恐らく不可能なので要注意。
$ sudo nvme delete-ns /dev/nvme0 -n 1 delete-ns: Success, deleted nsid:1
unvmcapが増えていることが分かる。
$ sudo nvme id-ctrl /dev/nvme0 | grep nvmcap tnvmcap : 1920383410176 unvmcap : 1920383410176
いよいよ名前空間を追加する。
$ sudo nvme create-ns /dev/nvme0 -f 0 -s 209715200 -c 209715200 create-ns: Success, created nsid:1
引数オプションの意味は下表のとおり。
オプション | 意味 |
---|---|
-f , –flbas | LBA形式の指定。nvme id-ns で得られた値を指定する。ここでは512バイトセクタとしている。 |
-s , –nsze | 名前空間の最大サイズ。-fで指定したブロック数単位で指定する。ここでは100GiB÷512バイト=209715200としている。 |
-c , –ncap | 名前空間の確保サイズ。-sのブロック数以下で指定する。最大サイズ未満を指定すればオーバープロビジョニング状態となる。 |
作成した名前空間はコントローラにアタッチして初めて使えるようになる。
$ sudo nvme attach-ns /dev/nvme0 -n 1 -c 0x6 attach-ns: Success, nsid:1
同じ要領で、もう1つ名前空間を追加する。
$ sudo nvme create-ns /dev/nvme0 -s 209715200 -c 209715200 -f 0 create-ns: Success, created nsid:2 $ sudo nvme attach-ns /dev/nvme0 -n 2 -c 0x6 attach-ns: Success, nsid:2
システムからnvme0n1
, nvme0n2
として認識されていることが分かる。
$ sudo nvme list Node SN Model Namespace Usage Format FW Rev --------------------- ------- ---------------------------------------- --------- -------------------------- ---------------- -------- /dev/nvme0n1 Serial SAMSUNG MZ1L21T9HCLS-00A07 1 107.37 GB / 107.37 GB 512 B + 0 B GDC7302Q /dev/nvme0n2 Serial SAMSUNG MZ1L21T9HCLS-00A07 2 107.37 GB / 107.37 GB 512 B + 0 B GDC7302Q $ lsblk | grep nvme0 nvme0n1 259:0 0 100G 0 disk nvme0n2 259:1 0 100G 0 disk
それぞれのS.M.A.R.T.はこんな感じ。デバイスが対応していれば、名前空間ごとに固有のS.M.A.R.T.を持つこともできるようだ。
nvme0n1 | nvme0n2 |
---|---|
$ sudo smartctl -a /dev/nvme0n1 smartctl 7.2 2020-12-30 r5155 [x86_64-linux-5.15.0-60-generic] (local build) Copyright (C) 2002-20, Bruce Allen, Christian Franke, www.smartmontools.org === START OF INFORMATION SECTION === Model Number: SAMSUNG MZ1L21T9HCLS-00A07 Serial Number: S666NE0Rxxxxxx Firmware Version: GDC7302Q PCI Vendor/Subsystem ID: 0x144d IEEE OUI Identifier: 0x002538 Total NVM Capacity: 1,920,383,410,176 [1.92 TB] Unallocated NVM Capacity: 1,705,635,045,376 [1.70 TB] Controller ID: 6 NVMe Version: 1.4 Number of Namespaces: 32 Namespace 1 Size/Capacity: 107,374,182,400 [107 GB] Namespace 1 Formatted LBA Size: 512 Local Time is: Fri May 5 10:11:28 2023 UTC Firmware Updates (0x17): 3 Slots, Slot 1 R/O, no Reset required Optional Admin Commands (0x005f): Security Format Frmw_DL NS_Mngmt Self_Test MI_Snd/Rec Optional NVM Commands (0x005f): Comp Wr_Unc DS_Mngmt Wr_Zero Sav/Sel_Feat Timestmp Log Page Attributes (0x0e): Cmd_Eff_Lg Ext_Get_Lg Telmtry_Lg Maximum Data Transfer Size: 512 Pages Warning Comp. Temp. Threshold: 77 Celsius Critical Comp. Temp. Threshold: 85 Celsius Namespace 1 Features (0x1a): NA_Fields No_ID_Reuse NP_Fields Supported Power States St Op Max Active Idle RL RT WL WT Ent_Lat Ex_Lat 0 + 8.25W 8.25W - 0 0 0 0 70 70 Supported LBA Sizes (NSID 0x1) Id Fmt Data Metadt Rel_Perf 0 + 512 0 0 1 - 4096 0 0 === START OF SMART DATA SECTION === SMART overall-health self-assessment test result: PASSED SMART/Health Information (NVMe Log 0x02) Critical Warning: 0x00 Temperature: 51 Celsius Available Spare: 100% Available Spare Threshold: 10% Percentage Used: 13% Data Units Read: 3,211,446,954 [1.64 PB] Data Units Written: 3,198,599,733 [1.63 PB] Host Read Commands: 7,123,174,983 Host Write Commands: 3,057,480,670 Controller Busy Time: 35,138 Power Cycles: 183 Power On Hours: 8,877 Unsafe Shutdowns: 106 Media and Data Integrity Errors: 0 Error Information Log Entries: 14 Warning Comp. Temperature Time: 0 Critical Comp. Temperature Time: 0 Temperature Sensor 1: 51 Celsius Temperature Sensor 2: 80 Celsius Error Information (NVMe Log 0x01, 16 of 64 entries) Num ErrCount SQId CmdId Status PELoc LBA NSID VS 0 14 0 0xb007 0x4238 0x000 0 1 - 1 13 0 0x8007 0x4238 0x000 0 1 - 2 12 0 0x8006 0x4238 0x000 0 1 - 3 11 0 0x7007 0x422a 0x000 0 0 - | $ sudo smartctl -a /dev/nvme0n2 smartctl 7.2 2020-12-30 r5155 [x86_64-linux-5.15.0-60-generic] (local build) Copyright (C) 2002-20, Bruce Allen, Christian Franke, www.smartmontools.org === START OF INFORMATION SECTION === Model Number: SAMSUNG MZ1L21T9HCLS-00A07 Serial Number: S666NE0Rxxxxxx Firmware Version: GDC7302Q PCI Vendor/Subsystem ID: 0x144d IEEE OUI Identifier: 0x002538 Total NVM Capacity: 1,920,383,410,176 [1.92 TB] Unallocated NVM Capacity: 1,705,635,045,376 [1.70 TB] Controller ID: 6 NVMe Version: 1.4 Number of Namespaces: 32 Namespace 2 Size/Capacity: 107,374,182,400 [107 GB] Namespace 2 Formatted LBA Size: 512 Local Time is: Fri May 5 10:12:01 2023 UTC Firmware Updates (0x17): 3 Slots, Slot 1 R/O, no Reset required Optional Admin Commands (0x005f): Security Format Frmw_DL NS_Mngmt Self_Test MI_Snd/Rec Optional NVM Commands (0x005f): Comp Wr_Unc DS_Mngmt Wr_Zero Sav/Sel_Feat Timestmp Log Page Attributes (0x0e): Cmd_Eff_Lg Ext_Get_Lg Telmtry_Lg Maximum Data Transfer Size: 512 Pages Warning Comp. Temp. Threshold: 77 Celsius Critical Comp. Temp. Threshold: 85 Celsius Namespace 2 Features (0x1a): NA_Fields No_ID_Reuse NP_Fields Supported Power States St Op Max Active Idle RL RT WL WT Ent_Lat Ex_Lat 0 + 8.25W 8.25W - 0 0 0 0 70 70 Supported LBA Sizes (NSID 0x2) Id Fmt Data Metadt Rel_Perf 0 + 512 0 0 1 - 4096 0 0 === START OF SMART DATA SECTION === SMART overall-health self-assessment test result: PASSED SMART/Health Information (NVMe Log 0x02) Critical Warning: 0x00 Temperature: 51 Celsius Available Spare: 100% Available Spare Threshold: 10% Percentage Used: 13% Data Units Read: 3,211,446,954 [1.64 PB] Data Units Written: 3,198,599,733 [1.63 PB] Host Read Commands: 7,123,174,983 Host Write Commands: 3,057,480,670 Controller Busy Time: 35,138 Power Cycles: 183 Power On Hours: 8,877 Unsafe Shutdowns: 106 Media and Data Integrity Errors: 0 Error Information Log Entries: 14 Warning Comp. Temperature Time: 0 Critical Comp. Temperature Time: 0 Temperature Sensor 1: 51 Celsius Temperature Sensor 2: 80 Celsius Error Information (NVMe Log 0x01, 16 of 64 entries) Num ErrCount SQId CmdId Status PELoc LBA NSID VS 0 14 0 0xb007 0x4238 0x000 0 1 - 1 13 0 0x8007 0x4238 0x000 0 1 - 2 12 0 0x8006 0x4238 0x000 0 1 - 3 11 0 0x7007 0x422a 0x000 0 0 - |
実はここからが本題。
複数の名前空間が持てるのは良いが、UEFI (BIOS)やOSから2つ目以降の名前空間はどのように認識されるのだろうか。NVMe Namespaceはハードウェアに近いレイヤーでのデバイス分割技術ではあるものの、PCIデバイスとしてはあくまで1つである。名前空間の実現には、ホストのNVMeドライバに拠るところが大きい気がして、特にPCのUEFI (BIOS)での対応状況が気になるところ。
それぞれのNVMe名前空間からシステムを自由にブートできれば夢が広がリングなのだが、情報がさっぱり見当たらないので実際に試してみた。
Linuxの場合、これまで見てきたとおり名前空間は/dev/nvme0n1
, /dev/nvme0n2
という感じで独立したデバイスのように見える。インストール先の選択肢にも上がっており、任意の名前空間にインストールが可能である。
FreeBSDでは/dev/nvme0ns1
, /dev/nvme0ns1
のように見える(さらに言うと対応する汎用ディスクレイヤーのデバイスとして/dev/nvd0
, /dev/nvd1
が生えてくる)。こちらも任意の名前空間にインストールが可能である。
WindowsとNVMe→USB変換器経由で複数名前空間を持つSSDをつないだ時の認識のされ方。
変換チップ | 認識のされ方 |
---|---|
ASM2362 | 最初の名前空間のみドライブとして認識される |
JMS583 | 全く認識されない。名前空間が1つのみのSSDなら問題なく認識されるので、複数名前空間があるとダメっぽい。 |
UEFIからの見え方は、恐らくマザボごとにまちまちである可能性が高い。NVMe対応UEFIは必須として、そのUEFIが持つNVMeドライバの対応状況次第だと思う。
比較的初期のNVMe対応品であると思われるTS150では、名前空間IDが1にあるESPを優先的にブートデバイスとして扱うようだ(あるいは、UEFIの最初のブートエントリが優先されてるのかも)。なお、NSID 1にはUbuntu Server、NSID 2にはFreeBSDをインストールした状態である。
UEFIのブートエントリは以下のような感じで、名前空間2にインストールしたFreeBSDも、正しく登録されているようだ。
$ efibootmgr -v BootCurrent: 0000 Timeout: 1 seconds BootOrder: 0000,0002,0003 Boot0000* ubuntu HD(1,GPT,0066403c-e597-4cfa-aa56-ad2f79960c92,0x800,0x219800)/File(\EFI\UBUNTU\SHIMX64.EFI) Boot0002* FreeBSD HD(1,GPT,a0fad4cc-eb36-11ed-bb5d-4ccc6acb7c47,0x28,0x82000)/File(\EFI\FREEBSD\LOADER.EFI) Boot0003* UEFI OS HD(1,GPT,a0fad4cc-eb36-11ed-bb5d-4ccc6acb7c47,0x28,0x82000)/File(\EFI\BOOT\BOOTX64.EFI)..BO $ sudo blkid /dev/nvme0n1p1: UUID="8030-A0AE" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="0066403c-e597-4cfa-aa56-ad2f79960c92" /dev/nvme0n2p1: SEC_TYPE="msdos" UUID="C23B-12F9" BLOCK_SIZE="512" TYPE="vfat" PARTLABEL="efiboot0" PARTUUID="a0fad4cc-eb36-11ed-bb5d-4ccc6acb7c47"
ここでefibootmgr -n 0003
とし次のブートデバイスをFreeBSDにすると、しっかりFreeBSDが立ち上がってくる。ただしUEFI上でのブートデバイスとしての認識は「ubuntu」のままだった。
一方で、efibootmgr -o 0003,0002,0000
としてブートオーダーをFreeBSD優先にしても、相変わらずUbuntuが立ち上がってきた。
いまいち釈然としない挙動だが、とりあえず名前空間が分かれていてもブート自体は可能なことは分った。恒常的に起動OSを切り替えたいなら、rEFIndやCloverBootloaderあたりを名前空間1に入れておけば良いだろう。
SupermicroのマザボX10SRL-Fでは、正しいESPさえあれば名前空間問わずブートデバイスとして検出してくれる模様。
どちらも「UEFI OS」となっていて分かりづらいが、上が名前空間1のESPにあるFreeBSDのブートローダ、下が名前空間2のESPにあるProxmox VEのブートローダである。ブートオーダーはPVEが優先となっており、問題なくPVEが起動する。さすがSupermicro。