固态硬盘

来自 Arch Linux 中文维基

本文介绍如何管理固态硬盘等基于闪存的存储设备。如果出于特定目的要对SSD进行分区,请考虑针对闪存优化的文件系统。对于一般用途,您只需选择喜好的文件系统并启用#TRIM

使用[编辑 | 编辑源代码]

TRIM[编辑 | 编辑源代码]

在机械硬盘上,只需在文件系统层面处理文件的删除即可[1]。但在固态硬盘上,每次写操作都会对相应闪存单元产生一定磨损,因此主控会使用算法来将写操作平衡到整块闪存上,这被称作耗损平均技术。在删除文件后通知主控对应的存储单元为可用状态将有助于这个过程。在不使用NVMe DEALLOCATE, SAS UNMAPATA_TRIM命令的情况下,由于主控不知道被删除的文件对应的空间已空闲,很快闪存上将没有“空闲”空间。在执行写入操作时,主控将需要反复搬运数据以空出一个最小擦除单元并擦除该单元以写入数据,导致写入用时增加(详见:写入放大)。此文展示了SSD装满数据前后的速度变化。

注意: 只需使用Periodic TRIM或Continuous TRIM中的一个即可。Continuous TRIM不是最被Linux社区推荐的TRIM方式。例如,Ubuntu默认使用periodic TRIM[2], Debian不建议使用continuous TRIM continuous TRIM,Red Hat建议在可行的情况下使用periodic TRIM[3]

自 Linux 内核版本 3.8 开始,对 TRIM 的支持不断被添加到不同的文件系统中。见下表:

文件系统 Continuous TRIM
(discard 选项)
Periodic TRIM
(fstrim)
参考与备注
Btrfs 从6.2版内核开始,默认启用了异步discard。
exFAT 从5.13版内核开始支持fstrim[4]
ext3
ext4 "discard, nodiscard(*)" in [5]
F2FS
JFS [6]
NILFS2
NTFS ntfs3内核驱动仅支持continuous TRIM。
NTFS-3G仅支持periodic TRIM。
VFAT 从4.19版内核开始支持fstrim[7]
XFS [8]
警告: 在启用TRIM功能前,请确保SSD支持TRIM。否则可能导致数据丢失!

要检查TRIM支持,执行:

$ lsblk --discard

若DISC-GRAN (discard granularity)和DISC-MAX (discard max bytes)列上的数值不为零,则表示对应设备支持TRIM。

对于SATA SSD,可通过hdparm检测TRIM支持:以root用户执行hdparm -I /dev/sda | grep TRIMhdparm不支持NVMe SSD。

Periodic TRIM[编辑 | 编辑源代码]

util-linux提供了fstrim.servicefstrim.timer两个systemd unit文件。启用fstrim.timer计时器会在每周激活服务,在所有已挂载的支持discard操作的文件系统上执行fstrim(8)

该计时器使用/var/lib/systemd/timers/stamp-fstrim.timer(将在服务第一次启动时创建)的时间戳来判断上次运行的时间。因此,不必担心服务被过于频繁地调用(类似anacron)。

该unit的状态与活动可通过journalctl查看。若要修改运行的周期或执行的指令,可编辑unit文件。

Continuous TRIM[编辑 | 编辑源代码]

除定期执行TRIM指令外(若使用fstrim.timer则默认为每周),也可每次在文件被删除后就立即执行TRIM指令(这被称为Continuous TRIM)。

警告:SATA 3.1前,所有TRIM指令都是非队列的(non-queued),使用Continuous TRIM将造成频繁的卡顿,这种情况下应使用#Periodic TRIM。此外,对于某些设备,队列的(queued)TRIM指令会造成严重的数据损坏(参见Linux源码中的ata_device_blacklist)。因此,在这些设备上,系统可能会强制发送非队列的(non-queued)TRIM指令。详见Wikipedia:Trim_(computing)#Disadvantages

要使用Continuous TRIM,在/etc/fstab中对应挂载点指定discard选项:

/dev/sda1  /           ext4  defaults,discard   0  1
注意: 不能在/etc/fstab中为XFS / 分区指定discard挂载选项。根据此帖子,必须使用rootflags=discard 内核参数

对于Ext4文件系统,也可用tune2fsdiscard设置为一个默认挂载选项

# tune2fs -o discard /dev/sdXY

对于可移动设备,使用此方式而不是在/etc/fstab中新增条目尤其有用。这样,在其他计算机上挂载分区时,就不需要每次修改/etc/fstab了。

注意: 此默认挂载选项不会在/proc/mounts中列出。

Trim整个设备[编辑 | 编辑源代码]

当在全新安装或想卖掉你的SSD时,你可能想Trim整个设备。可以使用blkdiscard命令,

为LVM启用TRIM[编辑 | 编辑源代码]

由LVM逻辑卷上的文件系统产生的TRIM请求将直达对应物理卷,无需额外的配置。

LVM操作(lvremove, lvreduce等)默认不会产生TRIM请求,以便使用vgcfgrestore(8)恢复之前的卷组设定。/etc/lvm/lvm.conf中的issue_discards设置决定是否在逻辑卷不再占用卷组空间时将discard发送给底层物理卷。

注意: 在修改issue_discards设置前,请仔细阅读/etc/lvm/lvm.conf中的注释。issue_discards设置不会影响由逻辑卷文件系统产生的TRIM请求(如在文件系统内删除文件)的传递,也不会影响thin pool中的空间管理。
警告: 启用issue_discards后,将不能再使用vgcfgrestore恢复卷组元数据。一旦执行LVM命令,将无法撤销。

为dm-crypt启用TRIM[编辑 | 编辑源代码]

警告: discard选项允许discard请求通过加密的块设备传递。这不一定能[9]提升性能,而且有安全风险。详见:

对非/文件系统,可修改/etc/crypttab,在相应设备的options中加入discard选项。(见 Dm-crypt/System configuration#crypttab)。

对于/文件系统,依照 Dm-crypt/TRIM support for SSD 中的步骤来将正确的内核参数加入到bootloader配置中。

提升性能[编辑 | 编辑源代码]

参见Improving performance#Storage devices

物理块大小[编辑 | 编辑源代码]

参见 Advanced Format#Solid state drives

清空SSD[编辑 | 编辑源代码]

TRIM只在删除文件时起作用,而在增量保存等替换操作上无能为力。因此,即使在支持TRIM的SSD上,写入性能也会随时间降低。你可能想将SSD存储单元恢复到出厂时的状态,来使其恢复出厂时的写入性能

要清除存储单元,依照SSD memory cell clearing中的步骤。

注意: 如果你想通过清除存储单元来清除数据,靠SSD控制器来执行该操作可能并不安全可靠。如果你不信任SSD制造商或担心固件中潜在的bug,参见Securely wipe disk#Flash memory

安全[编辑 | 编辑源代码]

Hdparm 显示 "frozen" 状态[编辑 | 编辑源代码]

一些主板BIOS在初始化时发送了"security freeze"命令给连接的SATA存储设备。同样,一些SSD(和HDD) BIOS在工厂时已被设置为"security freeze"。二者都会导致设备的密码安全设置设为 frozen,如下面的输出:

:~# hdparm -I /dev/sda
Security: 
 	Master password revision code = 65534
 		supported
 	not	enabled
 	not	locked
 		frozen
 	not	expired: security count
 		supported: enhanced erase
 	4min for SECURITY ERASE UNIT. 2min for ENHANCED SECURITY ERASE UNIT.

如格式化设备或安装新系统之类的操作不受"security freeze"影响。

上面的输出显示了设备在启动处于not locked状态(未设置HDD密码),其frozen状态可防止恶意软件在运行时对设备设置密码。

如果你想为"frozen"的设备设置密码,则主板BIOS必须支持该功能。因为支持设备密码是硬件加密所必需的,许多笔记本都支持该功能,但台式机/服务器主板则不然。例如,对于 Intel DH67CL/BL 主板,必须用跳线设置为"maintenance mode"来查看该设置 (见 [10], [11])。

警告: 不要试图用hdparm来改变上述的lock安全设置,除非你十分清楚自己在干什么。

如果你想擦除SSD,见 Securely wipe disk#hdparm 以及上文

从睡眠中唤醒时设置SSD为"frozen"状态[编辑 | 编辑源代码]

当从睡眠中唤醒时,SSD很可能失去"frozen"状态,这导致其可被ATA SECURE ERASE命令擦除。

要防止这一问题,可以在每次唤醒后运行一个脚本:

/usr/lib/systemd/system-sleep/ssd-freeze.sh
#!/bin/sh
if [ "$1" = 'post' ]; then
	sleep 1
	if hdparm --security-freeze /dev/disk/by-id/ata-name-of-disk; then
		logger "$0: SSD freeze command executed successfully"
	else
		logger "$0: SSD freeze command failed"
	fi	
fi

硬件加密[编辑 | 编辑源代码]

正如#Hdparm 显示 "frozen" 状态中提到的,在支持的设备上,在BIOS中为存储设备(SSD/HDD)设置密码可能启动硬件加密。如果设备同时符合OPAL标准,即使BIOS没有设置密码的功能,硬件加密也可能启动,见Self-encrypting drives

故障排除[编辑 | 编辑源代码]

你遇到的问题可能是由于SSD固件而不是Linux产生的。在尝试排除故障前,请检查固件是否有更新:

即使是固件的bug,也可能在不更新固件的情况下避免。若没有固件更新可用,或你不想进行固件更新,以下内容可能有所帮助。

处理NCQ错误[编辑 | 编辑源代码]

部分SSD和SATA芯片组在Linux的原生命令队列(NCQ)下不能正常工作。通过dmesg可看到如下错误信息:

[ 9.115544] ata9: exception Emask 0x0 SAct 0xf SErr 0x0 action 0x10 frozen
[ 9.115550] ata9.00: failed command: READ FPDMA QUEUED
[ 9.115556] ata9.00: cmd 60/04:00:d4:82:85/00:00:1f:00:00/40 tag 0 ncq 2048 in
[ 9.115557] res 40/00:18:d3:82:85/00:00:1f:00:00/40 Emask 0x4 (timeout)

要在系统启动时禁用NCQ,在引导加载程序配置中添加内核命令行libata.force=noncq。例如,要仅为disk0 port9关闭NCQ,使用:libata.force=9.00:noncq

或者,可通过sysfs在不重启的情况下在指定设备上关闭NCQ:

# echo 1 > /sys/block/sdX/device/queue_depth

如果问题仍未得到解决或导致了其他问题,提交一个bug

处理与SATA电源管理有关的错误[编辑 | 编辑源代码]

某些SSD(如Transcend MTS400)在SATA Active Link Power Management(ALPM)启用时会出现错误。 ALPM默认关闭,但会被节能程序(如TLP, Laptop Mode Tools)启用。

如果在使用这些节能程序时遇到SATA相关错误,应将使用电池时与充电时的电源配置都设为max_performance来关闭ALPM。

支持TRIM的外接SSD[编辑 | 编辑源代码]

一些USB转SATA芯片(如VL715、VL716等)以及在外接NVMe硬盘盒(如IB-1817M-C31[失效链接 2022-09-23 ⓘ]))中使用的USB转PCIe芯片(如智微(JMicron) JMS583 )支持类似TRIM的命令,这些命令可通过 USB Attached SCSI 驱动程序(在Linux下称为"uas")发送。

然而内核可能不会自动检测到并启用这一功能。假设有问题的设备为/dev/sdX,可以用以下命令确定是否为这种情况:

# sg_readcap -l /dev/sdX

如果输出中有一行写着“Logical block provisioning: lbpme=0”,则由于没有设置LBPME位,内核认为该设备不支持Logical Block Provisioning Management 。此时,你应该检查设备的"Logical Block Provisioning"中的"Vital Product Data"页是否显示了支持的unmapping data机制。你可以执行以下命令:

# sg_vpd -a /dev/sdX

查看有无类似下面的输出:

Unmap command supported (LBPU): 1
Write same (16) with unmap bit supported (LBPWS): 0
Write same (10) with unmap bit supported (LBPWS10): 0

上例中,设备支持"UNMAP"命令。

此外,查看如下命令的输出:

$ cat /sys/block/sdX/device/scsi_disk/*/provisioning_mode

如果输出为"full",则表明内核没有检测到该设备支持unmap data。 除了"full"外,内核的SCSI存储驱动目前接受以下provisioning_mode的值:

unmap
writesame_16
writesame_10
writesame_zero
disabled

对于上例,要使内核使用"unmap"模式,你可以向"provisioning_mode"中写入"unmap":

# echo "unmap" >/sys/block/sdX/device/scsi_disk/*/provisioning_mode

之后,你应该能立刻在对应设备上使用blkdiscard等工具,并在其文件系统上使用fstrim。

如果你想对于特定制造商的所有产品或特定产品,当通过USB其连接时,都能自动设置provisioning_mode,可配置udev

首先,找到对应设备的Vendor ID和Product ID:

$ cat /sys/block/sdX/../../../../../../idVendor
$ cat /sys/block/sdX/../../../../../../idProduct

然后,创建或修改相应的udev规则(本例中使用idVendor 152d和idProduct 0583):

# echo 'ACTION=="add|change", ATTRS{idVendor}=="152d", ATTRS{idProduct}=="0583", SUBSYSTEM=="scsi_disk", ATTR{provisioning_mode}="unmap"' >>/etc/udev/rules.d/10-uas-discard.rules

(也可以使用lsusb命令来查看idVendor/idProduct。)

固件更新[编辑 | 编辑源代码]

如果设备制造商支持,建议使用fwupd工具来更新固件。

ADATA[编辑 | 编辑源代码]

ADATA不支持在Linux下更新SSD固件。可以在此处下载仅支持Windows的SSD ToolBox工具。也可从此处下载ADATA XPG来对SSD进行监控、TRIM、基准测试或更新固件。

警告: 不建议尝试通过Wine来更新固件,Wine不是被设计来处理硬件接口操作的。使用Wine可能使固件更新不完整,导致SSD变砖。

Crucial[编辑 | 编辑源代码]

Crucial 提供了以ISO镜像文件升级固件的选项。选择产品后,下载"Manual Boot File"可获取ISO镜像。

注意: Crucial提供的ISO镜像可能不是hybrid格式。如果直接使用dd命令将镜像复制到设备上,由于MBR不会被设置,将无法从该设备启动。要解决这一问题,可安装syslinux并执行isohybrid path/to/image.iso

M4 Crucial model用户可通过smartctl检查是否有需要的固件更新。

$ smartctl --all /dev/sdX
==> WARNING: This drive may hang after 5184 hours of power-on time:
https://www.tomshardware.com/news/Crucial-m4-Firmware-BSOD,14544.html
See the following web page for firmware updates:
https://www.crucial.com/usa/en/support-ssd

建议看见这个警告的用户备份所有重要数据并立即更新。参见该指引来使用ISO镜像和grub更新Crucial MX100的固件。

Intel[编辑 | 编辑源代码]

对于无法使用Windows版本Intel® Solid-State Drive Toolbox软件的系统,Intel提供了一个基于Linux live系统的固件更新工具

此外,还可用使用Intel Memory and Storage (MAS) Toolintel-mas-cli-toolAUR)命令行工具在Linux下刷入固件。(其PDF用户指南

例如,要检查固件状态:

# intelmas show -intelssd 0
DevicePath : /dev/nvme0n1
DeviceStatus : Healthy
Firmware : 002C
FirmwareUpdateAvailable : The selected Intel SSD contains current firmware as of this tool release.

若有多个SSD,请将-intelssd 0修改为对应的值(1对应第二块SSD,以此类推)。

如果有可用的更新,可通过intelmas load -intelssd 0来应用。PDF用户指南建议进行应用操作后重启并再进行一次。所有设备的最新固件都作为MAS工具的一部分发布,无需单独下载。

Kingston[编辑 | 编辑源代码]

适用于基于Sandforce设备的KUF工具可从kingston_fw_updaterAUR获取。

Mushkin[编辑 | 编辑源代码]

不那么出名的 Mushkin 牌固态硬盘也使用 Sandforce 控制器,提供了Linux版的升级工具 (和 Kingston 的几乎一样)。

OCZ[编辑 | 编辑源代码]

OCZ为Linux提供Command Line Online Update Tool (CLOUT)。相关软件包可在AUR找到:ocz-ssd-utilityAURocztoolboxAURoczcloutAUR

Samsung[编辑 | 编辑源代码]

除了使用Magician软件外,也有其它方法升级固件(尽管Samsung认为这是”不受支持“的)。Magician软件可以创建包含固件更新的启动盘,然而Samsung不再为消费级SSD提供该软件。此外,Samsung提供的可引导的ISO镜像也能用来更新固件。还可以使用magician工具(samsung_magician-consumer-ssdAUR)。Magician只支持三星品牌的SSD,不支持Samsung为其它OEM(如联想)制造的SSD。

注意: 对于这些信息,Samsung提供得并不“显然”。它们似乎有4个不同的固件更新页面,每个都介绍了不同的更新方法。

如果你想通过在Linux下创建的Live USB来更新固件(而不是在Microsoft Windows下使用Samsung的Magician软件),参见[12]

在Linux下更新[编辑 | 编辑源代码]

此外,固件可在不使用USB启动盘的情况下直接更新。首先,从这里下载适用于对应SSD的最新固件(一个ISO镜像)。

注意: 若ISO镜像中没有下面提到的initrd镜像,见#较旧的SSD

从ISO镜像中解压Linux initrd镜像(将samsung_ssd_firmware替换为对应的ISO镜像文件名):

$ bsdtar xf samsung_ssd_firmware.iso initrd

解压root/fumagician/。该目录中包含固件更新文件:

$ bsdtar xf initrd root/fumagician

最后,以root权限运行root/fumagician/fumagician,确认成功更新固件后,重启计算机。

较旧的SSD[编辑 | 编辑源代码]

有些SSD固件ISO中包含FreeDOS镜像而不是Linux initrd镜像,故需要采取不同的更新方法。下表展示了这些SSD及固件的相对路径:

SSD型号 FreeDOS镜像路径 固件包路径
470, 830 BTDSK.IMG SSR/
840 isolinux/btdsk.img samsung/DSRD/
840 EVO (mSATA), Pro ISOLINUX/BTDSK.IMG

首先,从ISO镜像中解压FreeDOS镜像(将samsung_ssd_firmware替换为对应的ISO镜像文件名,freedos_image_path替换为FreeDOS镜像路径,下同):

$ bsdtar xf samsung_ssd_firmware.iso freedos_image_path

将FreeDOS镜像挂载到/mnt/

# mount freedos_image_path /mnt

利用Magician SSD management utility获取SSD对应的Disk Number

# magician --list

更新SSD固件(将firmware_package_path替换为对应的固件包路径):

# magician --disk Disk Number --firmware-update --fwpackage-path /mnt/firmware_package_path

最后,以root权限执行magician --list,检查输出中Firmware对应的固件版本是否成功更新,并重启计算机。

SanDisk[编辑 | 编辑源代码]

对于SanDisk SSD Toolkit不支持的操作系统,SanDisk制作了ISO镜像来进行固件更新。

你必须选择对应SSD型号容量的固件。烧录ISO镜像后,从创建的CD/DVD启动盘启动计算机即可(可能可以使用USB启动盘)。

此外,由于ISO镜像只包含了Linux内核及initrd,也可以将内核及initrd提取到/boot下,并用GRUBSyslinux启动来更新固件。

另见:

另见[编辑 | 编辑源代码]