Skip to content

Commit 7cda1ad

Browse files
committed
ops/storage: Optional guide for trimming USB block devices
1 parent 760dad8 commit 7cda1ad

2 files changed

Lines changed: 92 additions & 6 deletions

File tree

docs/ops/storage/intro.md

Lines changed: 90 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,19 +137,103 @@ $ sudo smartctl -a /dev/nvme0
137137

138138
### Trim (Discard/Unmap) {#trim}
139139

140-
SSD 的闪存存储的特点是:不支持任意的随机写,修改数据只能通过清空区块之后重新写入来实现。并且区块能够经受的写入次数是有限的。
141-
SSD 中的固件会进行区块管理,以将写入带来的磨损分散到所有区块中。但是,固件并不清楚文件系统的情况,因此在文件系统中删除某个文件之后,
142-
SSD 固件会仍然认为对应的区块存储了数据,不能释放。Trim 操作由操作系统发出,告诉固件哪些区块可以释放,以提升性能,延长 SSD 使用寿命。一些特殊的存储设备也会支持 trim 操作,例如虚拟机磁盘(`virtio-scsi`)、部分企业级的 SAN 等。
140+
SSD 的闪存存储的特点是:不支持任意的随机写,修改数据只能通过清空区块之后重新写入来实现。并且区块能够经受的写入次数是有限的。SSD 中的固件会进行区块管理,以将写入带来的磨损分散到所有区块中。但是,固件并不清楚文件系统的情况,因此在文件系统中删除某个文件之后,SSD 固件会仍然认为对应的区块存储了数据,不能释放。Trim 操作由操作系统发出,告诉固件哪些区块可以释放,以提升性能,延长 SSD 使用寿命。一些特殊的存储设备也会支持 trim 操作,例如虚拟机磁盘(`virtio-scsi`)、部分企业级的 SAN 等。
143141

144-
??? note "关注存储的可用空间比例"
142+
!!! note "关注存储的可用空间比例"
145143

146144
不建议将存储的可用空间全部或接近全部耗尽,这是因为:
147145

148146
- 机械硬盘:可用空间不足时,文件系统为了存储数据,会不得不产生大量磁盘碎片,而机械硬盘的随机读写性能很差;
149147
- 固态硬盘:可用空间不足会导致没有足够的空区块改写内容,因此可能不得不大量重复擦写已有的区块,加速磨损。
150148

151-
一般来说,确保 `fstrim.timer` 处于启用状态即可。一些文件系统也支持调整 trim/discard 参数(立即 discard 或周期性 discard,
152-
一般推荐后者)。
149+
一般来说,确保 `fstrim.timer` 处于启用状态即可。一些文件系统也支持调整 trim/discard 参数(立即 discard 或周期性 discard,一般推荐后者)。
150+
151+
??? tip "为 USB 设备开启 Trim"
152+
153+
由于老旧的 USB 设备对获取设备功能的请求的支持存在问题,因此 Linux 内核默认不会尝试请求相关数据,进而无法探测 USB 连接的存储设备是否支持 trim 功能。可以使用 `lsblk --discard` 或查看 `/sys/block/sdX/queue/discard_max_bytes` 确认(以下 `sda` 为 USB 磁盘设备):
154+
155+
```console
156+
$ lsblk --discard
157+
NAME DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
158+
sda 0 512B 0 0
159+
├─sda1 0 512B 0 0
160+
├─sda2 0 512B 0 0
161+
├─sda3 0 512B 0 0
162+
└─sda4 0 512B 0 0
163+
nvme0n1 0 512B 2T 0
164+
├─nvme0n1p1 0 512B 2T 0
165+
├─nvme0n1p2 0 512B 2T 0
166+
└─nvme0n1p3 0 512B 2T 0
167+
```
168+
169+
不过,Linux 允许用户手动覆盖这一行为。由于 USB 设备一般都以 USB Attached SCSI (UAS) 或 USB Mass Storage (UMS) 的形式连接,因此其由内核的 SCSI 子系统管理,可以发送 SCSI 命令来确认设备是否支持 trim 功能。
170+
171+
安装 `sg3-utils` 包后,使用 `sg_vpd` 查询 unmap 支持情况:
172+
173+
```console
174+
$ sudo sg_vpd --all /dev/sda
175+
Supported VPD pages VPD page:
176+
Supported VPD pages [sv]
177+
Unit serial number [sn]
178+
Device identification [di]
179+
Block limits (SBC) [bl]
180+
Block device characteristics (SBC) [bdc]
181+
Logical block provisioning (SBC) [lbpv]
182+
(省略)
183+
Block limits VPD page (SBC):
184+
Write same non-zero (WSNZ): 0
185+
Maximum compare and write length: 0 blocks [Command not implemented]
186+
Optimal transfer length granularity: 1 blocks
187+
Maximum transfer length: 65535 blocks
188+
Optimal transfer length: 65535 blocks
189+
Maximum prefetch transfer length: 65535 blocks
190+
Maximum unmap LBA count: 134217728
191+
Maximum unmap block descriptor count: 1
192+
Optimal unmap granularity: 0 blocks [not reported]
193+
Unmap granularity alignment valid: false
194+
Unmap granularity alignment: 0 [invalid]
195+
Maximum write same length: 0 blocks [not reported]
196+
Maximum atomic transfer length: 0 blocks [not reported]
197+
Atomic alignment: 0 [unaligned atomic writes permitted]
198+
Atomic transfer length granularity: 0 [no granularity requirement
199+
Maximum atomic transfer length with atomic boundary: 0 blocks [not reported]
200+
Maximum atomic boundary size: 0 blocks [can only write atomic 1 block]
201+
(省略)
202+
Logical block provisioning VPD page (SBC):
203+
Unmap command supported (LBPU): 1
204+
Write same (16) with unmap bit supported (LBPWS): 0
205+
Write same (10) with unmap bit supported (LBPWS10): 0
206+
Logical block provisioning read zeros (LBPRZ): 0
207+
Anchored LBAs supported (ANC_SUP): 0
208+
Threshold exponent: 0 [threshold sets not supported]
209+
Descriptor present (DP): 0
210+
Minimum percentage: 0 [not reported]
211+
Provisioning type: 0 (not known or fully provisioned)
212+
Threshold percentage: 0 [percentages not supported]
213+
```
214+
215+
LBPU、LBPWS 和 LBPWS10 分别为 unmap 的不同实现方式,详情参考 [sg_unmap(8)][sg_unmap.8] 和 [sg_write_same(8)][sg_write_same.8]。
216+
217+
对 SCSI 设备,sysfs 中的 "provisioning_mode" 控制 trim 功能,用户可以写入[支持的选项](https://elixir.bootlin.com/linux/v6.16.3/source/drivers/scsi/sd.c#L446-L453)。LBPU、LBPWS 和 LBPWS10 分别对应 `unmap`、`writesame_16` 和 `writesame_10`。
218+
219+
```sh
220+
# 在你的设备上,路径会有所不同
221+
echo unmap | sudo tee /sys/block/sda/device/scsi_disk/0:0:0:0/provisioning_mode
222+
```
223+
224+
此外,在设置 `provisioning_mode` 之后,`discard_max_bytes` 不会根据设备的实际能力更新(因为内核没有记录相应的数值),而是设置为[默认的 4G](https://elixir.bootlin.com/linux/v6.16.3/source/drivers/scsi/sd.c#L863-L864)。在一些场景下可能过大(设备不支持)。根据上面的输出得到的 "Maximum unmap LBA count",乘以 LBA 的大小(通常为 512 字节,需要使用 `sg_readcap /dev/sdX` 确认)后,即可得到设备实际支持的 `discard_max_bytes`。只要小于 `/sys/block/sdX/queue/discard_max_hw_bytes` 的数值,即可写入 `discard_max_bytes`。
225+
226+
```sh
227+
# 例子:限制到每次最多 discard 1GiB
228+
echo 1073741824 | sudo tee /sys/block/sda/queue/discard_max_bytes
229+
```
230+
231+
其他介绍可参考:
232+
233+
- [Enabling TRIM on an external SSD on a Raspberry Pi](https://www.jeffgeerling.com/blog/2020/enabling-trim-on-external-ssd-on-raspberry-pi)
234+
- [Gentoo Wiki: Discard over USB](https://wiki.gentoo.org/wiki/Discard_over_USB)
235+
- [Superuser: No TRIM/DISCARD with a SATA SSD connected through an UASP-enabled USB adapter?](https://superuser.com/a/1741030)
236+
- [scsi: sd: Enable modern protocol features on more devices](https://git.kernel.org/pub/scm/linux/kernel/git/mkp/linux.git/commit/?h=5.18/discovery&id=916740efdd2208564decee40a6049674f2063811)
153237

154238
## RAID
155239

includes/man.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ Do not link to a "generic" man page for these commands -->
6666
[deluser.8]: https://manpages.debian.org/stable/adduser/deluser.8.en.html
6767
[logrotate.8]: https://linux.die.net/man/8/logrotate
6868
[mount.8]: https://man7.org/linux/man-pages/man8/mount.8.html
69+
[sg_unmap.8]: https://linux.die.net/man/8/sg_unmap
70+
[sg_write_same.8]: https://linux.die.net/man/8/sg_write_same
6971
[sshd.8]: https://linux.die.net/man/8/sshd
7072
[systemd-logind.8]: https://www.freedesktop.org/software/systemd/man/latest/systemd-logind.html
7173
[useradd.8]: https://manpages.debian.org/stable/passwd/useradd.8.en.html

0 commit comments

Comments
 (0)