我刚买了一个 SATA SSD 和一个 USB-SATA 适配器。我选择了支持 UASP 的适配器,因为我认为它可以运行 TRIM/DISCARD 命令,而且我认为这对 SSD 的使用寿命很重要。
当我将适配器连接到基于 Debian 的计算机时,Linux 内核会按预期检测到它并启用与 UAS 协议的通信。以下是内核报告的内容:
[23886.083296] usb 2-1: new SuperSpeed Gen 1 USB device number 6 using xhci_hcd
[23886.104497] usb 2-1: New USB device found, idVendor=174c, idProduct=55aa, bcdDevice= 1.00
[23886.104508] usb 2-1: New USB device strings: Mfr=2, Product=3, SerialNumber=1
[23886.104513] usb 2-1: Product: 00SSD1
[23886.104518] usb 2-1: Manufacturer: CT500MX5
[23886.104522] usb 2-1: SerialNumber: 12345678D9DA
[23886.110042] scsi host1: uas
[23886.110883] scsi 1:0:0:0: Direct-Access CT500MX5 00SSD1 0 PQ: 0 ANSI: 6
[23886.111967] scsi 1:0:0:0: Attached scsi generic sg1 type 0
[23886.112698] sd 1:0:0:0: [sdb] 976773168 512-byte logical blocks: (500 GB/466 GiB)
[23886.112702] sd 1:0:0:0: [sdb] 4096-byte physical blocks
[23886.112841] sd 1:0:0:0: [sdb] Write Protect is off
[23886.112846] sd 1:0:0:0: [sdb] Mode Sense: 43 00 00 00
[23886.113013] sd 1:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[23886.113224] sd 1:0:0:0: [sdb] Optimal transfer size 33553920 bytes not a multiple of physical block size (4096 bytes)
lsusb
确认uas
驱动程序被使用:
/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/7p, 5000M
|__ Port 1: Dev 6, If 0, Class=Mass Storage, Driver=uas, 5000M
但我无法blkdiscard
在此设备上运行:
# blkdiscard -f /dev/sdb
blkdiscard: /dev/sdb contains existing partition (dos).
blkdiscard: Operation forced, data will be lost!
blkdiscard: /dev/sdb: BLKDISCARD ioctl failed: Operation not supported
lsblk
确认块设备不支持丢弃:
# lsblk -D /dev/sdb
NAME DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
sdb 0 0B 0B 0
`-sdb1 0 0B 0B 0
问题出在哪里?我可以用这个设置运行 TRIM/DISCARD 吗?
答案1
经过一些阅读(感谢 harrymc 在评论中提供的链接),我想我现在可以更好地理解发生了什么。
首先,认为将支持 UASP 的 USB-SATA 桥接器与最近的 SATA SSD(支持 TRIMming)一起使用显然会支持 UNMAPping 是天真的。
事实上,支持 UASP 的 USB-SATA 桥有两个主要功能:
- 第一个是UAS接口,它是一个USB接口,用于封装SCSI命令,
- 第二个是将 SCSI 命令转换为 ATA 命令的转换器。
SCSI 协议定义的命令集非常庞大,并非所有 SCSI 设备都支持所有命令。因此,有多个命令可用于 UNMAP。SCSI-ATA 转换器可能支持其中一个,也可能支持多个,但也可能不支持任何命令。在后一种情况下,无法取消 SSD 块的映射。幸运的是,我的 USB-SATA 桥接器中的 SCSI-ATA 转换器支持 UNMAP 命令。
由于 SCSI 命令集非常丰富,驱动程序必须知道设备支持哪些功能。这是通过设备向驱动程序提供的一些信息页面(称为 VPD(重要产品数据)页面)来完成的。“第一”页是“支持的 VPD 页面”,其中列出了设备支持的页面。
通常情况下,驱动程序会查询“第一”页,然后查询感兴趣的页(如果支持)。至于 UNMAP 功能,感兴趣的页是“逻辑块配置”页。
使用 Linux,可以像这样查询“支持的 VPD 页面”和“逻辑块配置”页面:
# sg_vpd -p sv /dev/sdb
Supported VPD pages VPD page:
Supported VPD pages [sv]
Unit serial number [sn]
Device identification [di]
Block limits (SBC) [bl]
Block device characteristics (SBC) [bdc]
Logical block provisioning (SBC) [lbpv]
# sg_vpd -p lbpv /dev/sdb
Logical block provisioning VPD page (SBC):
Unmap command supported (LBPU): 1
Write same (16) with unmap bit supported (LBPWS): 0
Write same (10) with unmap bit supported (LBPWS10): 0
Logical block provisioning read zeros (LBPRZ): 0
Anchored LBAs supported (ANC_SUP): 0
Threshold exponent: 0 [threshold sets not supported]
Descriptor present (DP): 0
Minimum percentage: 0 [not reported]
Provisioning type: 0 (not known or fully provisioned)
Threshold percentage: 0 [percentages not supported]
这里,我们可以看出“我的” SCSI-ATA 转换器支持取消映射命令,但是不支持带有取消映射位的写入相同(16)或写入相同(10)命令。
通常情况下,驱动程序会读取这些页面并相应地配置设备。不幸的是,显然存在损坏的 USB 设备的历史,当查询某些 VPD 页面时,这些设备会锁定或变砖。因此,Linux 内核的开发人员默认决定不查询 USB 连接的 SCSI 设备的 VPD 页面,也不设置 UNMAP 等高级功能。
好消息是,仍然可以使用特殊文件(路径可能有所不同)从用户空间设置这些功能/sys/block/sdb/device/scsi_disk/1:0:0:0/provisioning_mode
。当我插入适配器时,它显示“full”,但我可以将其设置为“unmap”,因为我的设备支持 unmap 命令。其他支持的值是“writesame_16”、“writesame_10”、“writesame_zero”和“disabled”。
可以进一步设置 udev 规则来自动配置该设备:
ACTION=="add|change", ATTRS{idVendor}=="174c", ATTRS{idProduct}=="55aa", SUBSYSTEM=="scsi_disk", ATTR{provisioning_mode}="unmap"
(idVendor、idProduct 和 provisioning_mode 取决于 USB-SATA 桥)
无论如何,我不建议这样做,因为一个错误可能会损坏您的设备,甚至尝试读取 VPD 页面也sg_vpd
可能会。
我也不知道设置这个discard_max_bytes
设置有多大用处,正如伟大的在 Raspberry Pi 上的外部 SSD 上启用 TRIM文章。
又有好消息了,修补在某些情况下,它可以绕过 USB 连接的 SCSI 设备的限制,只要这样做看起来是安全的,我想它应该可以对大多数最新的启用 UASP 的 USB-SATA 桥接器执行此操作。我还没有尝试过;它显然还没有进入 Linux 6.0-rc4;我不知道是否有计划在不久的将来请求合并它。