USB接続された外部HDDのシリアルナンバーとWWNが同一になる問題
いくつかの外付けUSB HDD用制御チップは、UASPモードの場合にディスクのシリアルナンバーとWWNを正しく報告しない。これにより/dev/disk/by-id/
を用いたプログラムが想定通りに動作しないことがある。Linuxの場合、uas
ドライバーの代わりにusb-storage
ドライバーを使用することで解決できる。
Sabrentというメーカーが販売している5ベイの3.5インチHDDエンクロージャー(DS-SC5B)を買った。このエンクロージャーはRAID機能は搭載せず、単に最大5つのHDDをUSB 3.2 Gen 2 (10 Gbps)で接続できるだけのシンプルなものになっている。搭載されている制御チップは、ASMedia TechnologyのASM235CMのようだ。
このエンクロージャーをPCに接続して、Ubuntu 22.04をインストールしようとしたところ、インストーラーがディスクのフォーマットの段階でクラッシュする現象が発生した。Ubuntuの場合、本来はUSB接続のHDDに問題なくインストールが可能で、そこから問題なくブートすることができる。
インストール時のディスクの設定はmdadmでRAID1を組み、その上にLVMでVGとLVを作るというよくある構成であったが、色々と試してみたところ、エンクロージャーに内蔵されているディスクを2台以上設定しようとするとクラッシュすることがわかった。
クラッシュ時のエラーメッセージは以下のようなものになる。
start: cmd-install/stage-partitioning/builtin/cmd-block-meta: configuring partition: partition-1
get_path_to_storage_volume for volume disk-sdc({'ptable': 'gpt', 'serial': '35000000000000001', 'wwn': '0x5000000000000001', 'path': '/dev/sdc', 'preserve': False, 'name': '', 'grub_device': False, 'type': 'disk', 'id': 'disk-sdc'})
Processing serial 0x5000000000000001 via udev to 0x5000000000000001
lookup_disks found: ['wwn-0x5000000000000001', 'wwn-0x5000000000000001-part1']
Running command ['udevadm', 'info', '--query=property', '--export', '/dev/sdb'] with allowed return codes [0] (capture=True)
/dev/sdb is multipath device? False
Running command ['udevadm', 'info', '--query=property', '--export', '/dev/sdb'] with allowed return codes [0] (capture=True)
/dev/sdb is multipath device member? False
block.lookup_disk() returning path /dev/sdb
Running command ['partprobe', '/dev/sdb'] with allowed return codes [0, 1] (capture=False)
Running command ['udevadm', 'settle'] with allowed return codes [0] (capture=False)
TIMED udevadm_settle(): 0.181
devsync happy - path /dev/sdb now exists
return volume path /dev/sdb
Running command ['lsblk', '--noheadings', '--bytes', '--pairs', '--output=ALIGNMENT,DISC-ALN,DISC-GRAN,DISC-MAX,DISC-ZERO,FSTYPE,GROUP,KNAME,LABEL,LOG-SEC,MAJ:MIN,MIN-IO,MODE,MODEL,MOUNTPOINT,NAME,OPT-IO,OWNER,PHY-SEC,RM,RO,ROTA,RQ-SIZE,SIZE,STATE,TYPE,UUID', '/dev/sdb'] with allowed return codes [0] (capture=True)
get_blockdev_sector_size: info:
{
"sdb": {
"ALIGNMENT": "0",
"DISC-ALN": "0",
"DISC-GRAN": "0",
"DISC-MAX": "0",
"DISC-ZERO": "0",
"FSTYPE": "",
"GROUP": "disk",
"KNAME": "sdb",
"LABEL": "",
"LOG-SEC": "512",
"MAJ:MIN": "8:16",
"MIN-IO": "4096",
"MODE": "brw-rw----",
"MODEL": "ASM235CM",
"MOUNTPOINT": "",
"NAME": "sdb",
"OPT-IO": "0",
"OWNER": "root",
"PHY-SEC": "4096",
"RM": "0",
"RO": "0",
"ROTA": "1",
"RQ-SIZE": "60",
"SIZE": "4000787030016",
"STATE": "running",
"TYPE": "disk",
"UUID": "",
"device_path": "/dev/sdb"
},
"sdb1": {
"ALIGNMENT": "0",
"DISC-ALN": "0",
"DISC-GRAN": "0",
"DISC-MAX": "0",
"DISC-ZERO": "0",
"FSTYPE": "vfat",
"GROUP": "disk",
"KNAME": "sdb1",
"LABEL": "",
"LOG-SEC": "512",
"MAJ:MIN": "8:17",
"MIN-IO": "4096",
"MODE": "brw-rw----",
"MODEL": "",
"MOUNTPOINT": "",
"NAME": "sdb1",
"OPT-IO": "0",
"OWNER": "root",
"PHY-SEC": "4096",
"RM": "0",
"RO": "0",
"ROTA": "1",
"RQ-SIZE": "60",
"SIZE": "1127219200",
"STATE": "",
"TYPE": "part",
"UUID": "E307-5D1B",
"device_path": "/dev/sdb1"
}
}
get_blockdev_sector_size: (log=512, phys=4096)
sdb logical_block_size_bytes: 512
adding partition 'partition-1' to disk 'disk-sdc' (ptable: 'gpt')
partnum: 1 offset_sectors: 2048 length_sectors: 2201599
Preparing partition location on disk /dev/sdb
Wiping 1M on /dev/sdb at offset 1048576
Running command ['sgdisk', '--new', '1:2048:2203647', '--typecode=1:ef00', '/dev/sdb'] with allowed return codes [0] (capture=True)
An error occured handling 'partition-1': ProcessExecutionError - Unexpected error while running command.
Command: ['sgdisk', '--new', '1:2048:2203647', '--typecode=1:ef00', '/dev/sdb']
Exit code: 4
Reason: -
Stdout: ''
Stderr: Could not create partition 1 from 2048 to 2203647
Error encountered; not saving changes.
finish: cmd-install/stage-partitioning/builtin/cmd-block-meta: FAIL: configuring partition: partition-1
TIMED BLOCK_META: 5.419
finish: cmd-install/stage-partitioning/builtin/cmd-block-meta: FAIL: curtin command block-meta
Traceback (most recent call last):
File "/snap/subiquity/3359/lib/python3.8/site-packages/curtin/commands/main.py", line 202, in main
ret = args.func(args)
File "/snap/subiquity/3359/lib/python3.8/site-packages/curtin/log.py", line 97, in wrapper
return log_time("TIMED %s: " % msg, func, *args, **kwargs)
File "/snap/subiquity/3359/lib/python3.8/site-packages/curtin/log.py", line 79, in log_time
return func(*args, **kwargs)
File "/snap/subiquity/3359/lib/python3.8/site-packages/curtin/commands/block_meta.py", line 117, in block_meta
return meta_custom(args)
File "/snap/subiquity/3359/lib/python3.8/site-packages/curtin/commands/block_meta.py", line 2045, in meta_custom
handler(command, storage_config_dict, command_handlers)
File "/snap/subiquity/3359/lib/python3.8/site-packages/curtin/commands/block_meta.py", line 998, in partition_handler
util.subp(cmd, capture=True)
File "/snap/subiquity/3359/lib/python3.8/site-packages/curtin/util.py", line 275, in subp
return _subp(*args, **kwargs)
File "/snap/subiquity/3359/lib/python3.8/site-packages/curtin/util.py", line 139, in _subp
raise ProcessExecutionError(stdout=out, stderr=err,
curtin.util.ProcessExecutionError: Unexpected error while running command.
Command: ['sgdisk', '--new', '1:2048:2203647', '--typecode=1:ef00', '/dev/sdb']
Exit code: 4
Reason: -
Stdout: ''
Stderr: Could not create partition 1 from 2048 to 2203647
Error encountered; not saving changes.
Unexpected error while running command.
Command: ['sgdisk', '--new', '1:2048:2203647', '--typecode=1:ef00', '/dev/sdb']
Exit code: 4
Reason: -
Stdout: ''
Stderr: Could not create partition 1 from 2048 to 2203647
Error encountered; not saving changes.
curtin: Installation failed with exception: Unexpected error while running command.
Command: ['curtin', 'block-meta', 'simple']
Exit code: 3
エラーをよく見ると、get_path_to_storage_volume()
という関数を使って/dev/sdc
を探しているにもかかわらず、途中から処理が/dev/sdb
に置き換わってしまっている。そのため、本来/dev/sdc
に作るはずだったパーティションを/dev/sdb
に作ろうとしてしまい、エラーになっている。
get_path_to_storage_volume()
の実装を見てみると、与えられた引数を使ってデバイスの特定を試みるにあたって、wwn
、serial
、disk_id
、path
の順番に値を使用して検索している。wwn
とserial
に関しては、単純に/dev/disk/by-id
の中に値が含まれるファイルが存在しているかを見ているようだ。
ここで、シリアルナンバーとして与えられている35000000000000001
とWWNの0x5000000000000001
が問題となる。一見して怪しいこれらの番号だが、実際のところ、接続されたHDDに関わらず一定の値が報告されているようだ。
実際に、udevadmを用いて各HDDのシリアルナンバーとWWNを確認すると、どのデバイスも同じ値が報告されている。
$ sudo udevadm info --query=all --name=/dev/sdb
P: /devices/pci0000:00/0000:00:14.0/usb2/2-5/2-5.3/2-5.3.1/2-5.3.1:1.0/host2/target2:0:0/2:0:0:0/block/sdb
N: sdb
L: 0
S: disk/by-id/scsi-35000000000000001
S: disk/by-path/pci-0000:00:14.0-usb-0:5.3.1:1.0-scsi-0:0:0:0
S: disk/by-id/wwn-0x5000000000000001
S: disk/by-id/scsi-SASMT_ASM235CM_10C000000519
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb2/2-5/2-5.3/2-5.3.1/2-5.3.1:1.0/host2/target2:0:0/2:0:0:0/block/sdb
E: DEVNAME=/dev/sdb
E: DEVTYPE=disk
E: DISKSEQ=10
E: MAJOR=8
E: MINOR=16
E: SUBSYSTEM=block
E: USEC_INITIALIZED=4864398
E: SCSI_TPGS=0
E: SCSI_TYPE=disk
E: SCSI_VENDOR=ASMT
E: SCSI_VENDOR_ENC=ASMT\x20\x20\x20\x20
E: SCSI_MODEL=ASM235CM
E: SCSI_MODEL_ENC=ASM235CM\x20\x20\x20\x20\x20\x20\x20\x20
E: SCSI_REVISION=0
E: ID_SCSI=1
E: ID_SCSI_INQUIRY=1
E: SCSI_IDENT_SERIAL=10C000000519
E: SCSI_IDENT_LUN_NAA_REG=5000000000000001
E: ID_VENDOR=ASMT
E: ID_VENDOR_ENC=ASMT\x20\x20\x20\x20
E: ID_MODEL=ASM235CM
E: ID_MODEL_ENC=ASM235CM\x20\x20\x20\x20\x20\x20\x20\x20
E: ID_REVISION=0
E: ID_TYPE=disk
E: ID_WWN_WITH_EXTENSION=0x5000000000000001
E: ID_WWN=0x5000000000000001
E: ID_BUS=scsi
E: ID_SERIAL=35000000000000001
E: ID_SERIAL_SHORT=5000000000000001
E: ID_SCSI_SERIAL=10C000000519
E: MPATH_SBIN_PATH=/sbin
E: DM_MULTIPATH_DEVICE_PATH=0
E: ID_PATH=pci-0000:00:14.0-usb-0:5.3.1:1.0-scsi-0:0:0:0
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_5_3_1_1_0-scsi-0_0_0_0
E: ID_PART_TABLE_UUID=5dde5dc1-6c68-40cb-b9f1-3683ea376140
E: ID_PART_TABLE_TYPE=gpt
E: DEVLINKS=/dev/disk/by-id/scsi-35000000000000001 /dev/disk/by-path/pci-0000:00:14.0-usb-0:5.3.1:1.0-scsi-0:0:0:0 /dev/disk/by-id/wwn-0x5000000000000001 /dev/disk/by-id/scsi-SASMT_ASM235CM_10C000000519
E: TAGS=:systemd:
E: CURRENT_TAGS=:systemd:
$ sudo udevadm info --query=all --name=/dev/sdc
P: /devices/pci0000:00/0000:00:14.0/usb2/2-5/2-5.3/2-5.3.3/2-5.3.3:1.0/host3/target3:0:0/3:0:0:0/block/sdc
N: sdc
L: 0
S: disk/by-id/wwn-0x5000000000000001
S: disk/by-id/scsi-SASMT_ASM235CM_30C000000519
S: disk/by-id/scsi-35000000000000001
S: disk/by-path/pci-0000:00:14.0-usb-0:5.3.3:1.0-scsi-0:0:0:0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb2/2-5/2-5.3/2-5.3.3/2-5.3.3:1.0/host3/target3:0:0/3:0:0:0/block/sdc
E: DEVNAME=/dev/sdc
E: DEVTYPE=disk
E: DISKSEQ=11
E: MAJOR=8
E: MINOR=32
E: SUBSYSTEM=block
E: USEC_INITIALIZED=5264814
E: SCSI_TPGS=0
E: SCSI_TYPE=disk
E: SCSI_VENDOR=ASMT
E: SCSI_VENDOR_ENC=ASMT\x20\x20\x20\x20
E: SCSI_MODEL=ASM235CM
E: SCSI_MODEL_ENC=ASM235CM\x20\x20\x20\x20\x20\x20\x20\x20
E: SCSI_REVISION=0
E: ID_SCSI=1
E: ID_SCSI_INQUIRY=1
E: SCSI_IDENT_SERIAL=30C000000519
E: SCSI_IDENT_LUN_NAA_REG=5000000000000001
E: ID_VENDOR=ASMT
E: ID_VENDOR_ENC=ASMT\x20\x20\x20\x20
E: ID_MODEL=ASM235CM
E: ID_MODEL_ENC=ASM235CM\x20\x20\x20\x20\x20\x20\x20\x20
E: ID_REVISION=0
E: ID_TYPE=disk
E: ID_WWN_WITH_EXTENSION=0x5000000000000001
E: ID_WWN=0x5000000000000001
E: ID_BUS=scsi
E: ID_SERIAL=35000000000000001
E: ID_SERIAL_SHORT=5000000000000001
E: ID_SCSI_SERIAL=30C000000519
E: MPATH_SBIN_PATH=/sbin
E: DM_MULTIPATH_DEVICE_PATH=0
E: ID_PATH=pci-0000:00:14.0-usb-0:5.3.3:1.0-scsi-0:0:0:0
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_5_3_3_1_0-scsi-0_0_0_0
E: DEVLINKS=/dev/disk/by-id/wwn-0x5000000000000001 /dev/disk/by-id/scsi-SASMT_ASM235CM_30C000000519 /dev/disk/by-id/scsi-35000000000000001 /dev/disk/by-path/pci-0000:00:14.0-usb-0:5.3.3:1.0-scsi-0:0:0:0
E: TAGS=:systemd:
E: CURRENT_TAGS=:systemd:
シリアルナンバーとWWNが同じということは、/dev/disk/by-id/wwn-0x5000000000000001
と/dev/disk/by-id/scsi-35000000000000001
の指す先が一意に定まらなくなる。これにより、Ubuntuのインストーラーのように、/dev/disk/by-id/
以下に依存したロジックを含むアプリケーションが異常な動作をするようになる。
このような振る舞いをするUSBの外付けHDDはいくつか存在するらしく、インターネット上で複数の報告を見ることができる。そのうちの一つから以下のような情報が得られた(Seagateからの情報らしい)。
The issue seems to be related to BOT vs UAS. On new machines with UAS you get the same Unique ID ...(中略)... The issue is not seen when connected to a host via BOT and is only seen when connected via UAS.
このような現象はUSB Attached SCSI (UAS)では発生するが、Bulk Only Transport(BOT)では起こらないらしい。UASはUSB 3.0から追加された規格で、従来から存在するBOTに比べると新しい規格となる(とはいえ、USB 3.0自体がすでに十分古い規格ではあるが)。
Ubuntu 22.04の場合、USBマスストレージをUASモードで操作するためのuas
カーネルモジュールは、デフォルトでインストールされている。そのためUASP対応のデバイスを接続すると自動でuas
ドライバーが使用される。UASP非対応のデバイスの場合、従来のBOT実装であるusb-stoage
ドライバーが使われる。
今回のエンクロージャーの場合も、強制的にusb-storage
ドライバーを割り当てると、ディスクの名前も含めてすべての情報を正常に得ることが出来た。制御チップの問題なのか、UASモードでは情報が正しく報告されず、BOTモードでのみ期待通りの動作をするようだ。
現時点でユーザー側ができる対応策としては、2つの方法が考えられる。usb-storage
ドライバーを強制的に使用する方法と、udevルールを編集して/dev/disk/by-id
以下のエントリーを作らなくする方法である。
usb-storage
ドライバーを強制的に使用したい場合、以下の方法でmodprobe
を設定する。
最初に、エンクロージャーのデバイスIDを取得する。lsusb
コマンドを使用すると簡単に見つけることができる。
$ lsusb
Bus 002 Device 005: ID 174c:55aa ASMedia Technology Inc. ASM1051E SATA 6Gb/s bridge, ASM1053E SATA 6Gb/s bridge, ASM1153 SATA 3Gb/s bridge, ASM1153E SATA 6Gb/s bridge
Bus 002 Device 004: ID 174c:55aa ASMedia Technology Inc. ASM1051E SATA 6Gb/s bridge, ASM1053E SATA 6Gb/s bridge, ASM1153 SATA 3Gb/s bridge, ASM1153E SATA 6Gb/s bridge
...
上記の例ではID
の右側の174c:55aa
がデバイスのIDとなる。
次に、/etc/modprobe.d/
内に適当な設定ファイルを作って、quirks
に上記のIDを指定してusb-storage
を使用するように設定する。quirks
に与えるIDには:u
を追加しておく。
$ cat /etc/modprobe.d/smc235c.conf
options usb-storage quirks=174c:55aa:u
ファイルを作ったらinitramfsを更新してから再起動する。
$ sudo update-initramfs -u
$ sudo reboot
なお、grubのカーネルパラメーターにusb-storage.quirks=174c:55aa:u
と追加する方法でも同様の効果があるらしい(私自身は試していない)。
usb-storage
ドライバーを使用する場合、性能面では劣化が発生する可能性がある。とはいえ、渡しの場合は使用しているHDDが5400rpmで、しかも1Gbpsで接続されたNASとして使用するので、性能面ではあまり気にならなかった。
udevのルールを編集する場合、Ubuntuでは/lib/udev/rules.d/60-persistent-storage.rules
内のルールを変更する必要がある。/etc/udev/rules.d/
内に同名のフィルを作った上で、disk/by-id
関連のルールにENV{SCSI_MODEL}!="ASM235CM"
を追加する。
なお、Ubuntuのインストール中に応急処置を行うのであれば、F2
でシェルに入って、/dev/disk/by-id/
内のファイルを消してしまうのが早い。