固态硬盘
本文介绍如何管理固态硬盘(SSD)等基于闪存的存储设备。
如果要针对特定目的对 SSD 进行分区,请参考针对闪存优化的文件系统清单。
使用[编辑 | 编辑源代码]
TRIM[编辑 | 编辑源代码]
在机械硬盘上,删除操作是在文件系统层级上处理的[1],而 SSD 会向硬盘主控通知特定区域的空间可以被再次使用。由于每次写入操作都会对闪存单元一定磨损,因此主控会使用算法来将写操作平衡到闪存的所有单元上,这被称作耗损平均技术。在不使用 NVMe DEALLOCATE,SAS UNMAP 或 ATA_TRIM 命令(多数 SSD 都支持)的情况下,如果没有空余的存储块,主控就需要反复搬运数据以空出一个最小擦除单元,并擦除该单元以写入数据,导致写入耗时增加(详见:写入放大)。关于 SSD 空间占满前后的性能对比可参考 TechSpot 的评测。
自 Linux 内核版本 3.8 开始,对 TRIM 的支持不断被添加到不同的文件系统中。见下表:
文件系统 | 持续性 TRIM ( discard 选项) |
定期 TRIM (fstrim) |
参考与备注 |
---|---|---|---|
Bcachefs | 是 | 否 | |
Btrfs | 是 | 是 | 从 6.2 内核版本开始默认启用异步 discard |
exFAT | 是 | 是 | 从 5.13 内核版本开始支持 fstrim [4] |
ext3 | 是 | 是 | |
ext4 | 是 | 是 | “discard, nodiscard(*)” [5] |
F2FS | 是 | 是 | |
JFS | 是 | 是 | [6] |
NILFS2 | 是 | 是 | |
NTFS | 是 | 否 | ntfs3 内核驱动仅支持持续性 TRIM |
否 | 是 | NTFS-3G 驱动仅支持定期 TRIM | |
VFAT | 是 | 是 | 从 4.19 内核版本开始支持 fstrim [7] |
XFS | 是 | 是 | [8] |
Swap | 是 | 否 | 理论上不是个“文件系统”,但也适用于 TRIM。“once” 选项在启动时提供了定期 TRIM 的功能,具体请参考 swapon(8) |
要检查 TRIM 支持,执行:
$ lsblk --discard
若 DISC-GRAN(discard granularity)和 DISC-MAX(discard max bytes)列上的数值不为零,则表示对应设备支持 TRIM。
对于 SATA SSD,可通过 hdparm包 检测 TRIM 支持:以根用户执行 hdparm -I /dev/sda | grep TRIM
。注意:hdparm
不支持 NVMe SSD。
定期 TRIM[编辑 | 编辑源代码]
util-linux包 提供了 fstrim.service
和 fstrim.timer
两个 systemd 单元文件。启用 fstrim.timer
计时器会在每周激活服务,在所有已挂载的支持 discard 操作的文件系统上执行 fstrim(8)。
该计时器使用 /var/lib/systemd/timers/stamp-fstrim.timer
(将在服务第一次启动时创建)的时间戳来判断上次运行的时间。因此,不必担心服务被过于频繁地调用(类似 anacron)。
单元的状态与活动记录可通过 journalctl 查看。若要修改运行的周期或执行的指令,可编辑单元文件。
持续性 TRIM[编辑 | 编辑源代码]
除定期执行 TRIM 指令外(若使用 fstrim.timer
则默认为每周一次),也可每次在文件被删除后就立即执行 TRIM 指令(这被称为持续性 TRIM)。
__ata_dev_quirks
内带有 ATA_QUIRK_NO_NCQ_TRIM
的项)使用队列化 TRIM 命令会造成严重的数据损坏,因此系统会对这些设备强制发送非队列化的 TRIM 命令,具体请参考 Wikipedia:Trim_(computing)#Disadvantages。要使用持续性 TRIM,在 /etc/fstab
中对应挂载点指定 discard
选项:
/dev/sda1 / ext4 defaults,discard 0 1
对于Ext4文件系统,也可用 tune2fs 将 discard
设置为一个默认挂载选项:
# tune2fs -o discard /dev/sdXY
对于可移动设备,由于配置后的分区在其它设备上也会使用默认挂载选项,使用此方式而不是在 /etc/fstab
中新增条目尤其有用。这样,在其他计算机上挂载分区时,就不需要每次修改 /etc/fstab
了。
/proc/mounts
中列出。Trim 整个设备[编辑 | 编辑源代码]
当在全新安装或想卖掉你的 SSD 时,你可能想 Trim 整个设备,这时候可以使用 blkdiscard 命令。
LVM[编辑 | 编辑源代码]
由 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[编辑 | 编辑源代码]
为 LUKS 和普通 dm-crypt 设备启用 discard 的步骤请参考 dm-crypt/Specialties#Discard/TRIM support for solid state drives (SSD)。
swap[编辑 | 编辑源代码]
可以通过将 discard
选项添加到 fstab 中的 swap 设备条目或调用 swapon
时传递 --discard
选项为 swap 启用 discard。
在使用 Systemd#GPT分区自动挂载 时,discard 不会被自动应用到 swap 分区。
See swapon(8) for discussion on when swap is discarded: discard=once
or discard=pages
. If discard
is specified without a specific mode, the default is to enable both.
提升性能[编辑 | 编辑源代码]
参见性能优化#存储设备。
清空 SSD[编辑 | 编辑源代码]
有时用户可能会想将 SSD 的存储单元重置回出厂状态,从而恢复到出厂时的写入性能。由于 TRIM 只对文件删除有用,而对替换操作(如增量保存)无能为力,因此就算 SSD 带有原生 TRIM 支持,其写入性能还是会随时间逐渐下降。
无论是 SATA 还是 NVMe SSD,都可以参考 固态硬盘/Memory cell clearing 中的对应步骤进行重置。
安全[编辑 | 编辑源代码]
冻结(Frozen)模式[编辑 | 编辑源代码]
有些主板的固件会在初始化时向 SATA 设备发送 ATA SECURITY FREEZE LOCK 命令,将硬盘设为冻结模式(即切换到 SEC2 状态,禁用安全、非锁定并冻结)。同样,有些 SSD 和 HDD 在出厂时也会设成该状态。可以通过 hdparm 和 smartctl 的输出确认该现象:
# 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.
# smartctl -g security /dev/sda
ATA Security is: Disabled, frozen [SEC2]
格式化或安装系统等操作不受冻结模式的影响。
上面的 hdparm 输出显示设备在启动时未被 HDD 密码锁定,frozen 冻结状态可防止恶意软件在运行时对设备设置密码进行锁定。
如果你想手动为“冻结”的设备设置密码,需要主板 BIOS 支持该功能的。由于硬件加密的需要,很多笔记本都支持该功能,但台式机/服务器主板上则不然。以 Intel DH67CL/BL 主板为例,需要通过板上跳线将主板设为“维护模式”才能访问该设置。[10]
如果你想擦除 SSD,请参考 Securely wipe disk#hdparm 和 /Memory cell clearing。
从睡眠中唤醒时设置 SATA SSD 为冻结模式[编辑 | 编辑源代码]
当从 S3 睡眠状态唤醒时,SATA SSD 很可能会回到 SEC1 状态(禁用安全、非锁定、非冻结),导致其有可能受 /Memory cell clearing 中描述的 ATA SECURITY ERASE UNIT 命令攻击。
要防止这一问题,可以在每次唤醒后运行一个脚本:
/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
如果系统有多个存储设备和/或移动 USB 盘,可以通过 Hdparm#使用 udev 规则使配置持久化 为所有硬盘(包括机械硬盘)指定 --security-freeze
。
硬件加密[编辑 | 编辑源代码]
正如#冻结(Frozen)模式中提到的,在设备支持的情况下,在 BIOS 中为存储设备(SSD/HDD)设置密码可能同时会启用硬件加密。如果设备同时符合 OPAL 标准,即使 BIOS 没有设置密码的功能,硬件加密也可能启动,具体请参考 Self-encrypting drives。
故障排除[编辑 | 编辑源代码]
你遇到的问题可能是由于 SSD 固件而不是 Linux 产生的。在尝试排除故障前,请检查固件是否有更新:
即使是固件的 bug,也可能在不更新固件的情况下避免。若没有固件更新可用,或你不想进行固件更新,以下内容可能有所帮助。
处理 NCQ 错误[编辑 | 编辑源代码]
部分 SSD 和 SATA 芯片组在 Linux 的原生命令队列(NCQ)下不能正常工作。通过 journal 可看到如下错误信息:
ata9: exception Emask 0x0 SAct 0xf SErr 0x0 action 0x10 frozen ata9.00: failed command: READ FPDMA QUEUED ata9.00: cmd 60/04:00:d4:82:85/00:00:1f:00:00/40 tag 0 ncq 2048 in res 40/00:18:d3:82:85/00:00:1f:00:00/40 Emask 0x4 (timeout)
要在系统启动时禁用 NCQ,需要在引导加载程序配置的内核命令行中添加 libata.force=noncq
。例如,要仅为硬盘 0 端口 9 禁用 NCQ,可以使用:libata.force=9.00:noncq
或者,可通过 sysfs 在不重启的情况下为指定设备禁用 NCQ:
# echo 1 > /sys/block/sdX/device/queue_depth
如果更新固件并完成操作后问题仍未解决或导致了其他问题,请提交 bug 报告。
处理与 SATA 电源管理有关的错误[编辑 | 编辑源代码]
某些 SSD(如 Transcend MTS400 或 Crucial M550)搭配特定 SATA 控制器时,在 ALPM 启用时会出现故障。
Linux 从 4.16 版本开始默认启用,也可能会被节能守护进程(例如 TLP 和 Laptop Mode Tools)启用。更多信息请参考电源管理#SATA 活动链路电源管理。
支持 TRIM 的外接 SSD[编辑 | 编辑源代码]
有多个 USB 转 SATA 桥接芯片(如 VL715,VL716 等)及 USB 转 PCIe 桥接芯片(如 IB-1817M-C31 外置 NVMe 硬盘盒使用的 JMicron JMS583)支持类似 TRIM 的命令,这些命令可通过 USB Attached SCSI 驱动程序(在 Linux 下称为"uas")发送。
然而内核可能不会自动检测到并启用这一功能。 假设有问题的设备为 /dev/sdX,可以通过 sg3_utils包 使用以下命令确定是否为这种情况:
# sg_readcap -l /dev/sdX
如果输出中有一行写着“Logical block provisioning: lbpme=0”,就意味着由于没有设置 LBPME 位,内核认为该设备不支持“Logical Block Provisioning Management”。
在这种情况下,就需要找出设备上的“Logical Block Provisioning”中的“Vital Product Data”(VPD)页是否说明了支持的解除数据映射机制。可以使用该命令进行查看:
# 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”,则表明内核没有检测到该设备有能力解除数据映射。 除了“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
现在就可以在 /dev/sdX 上使用 blkdiscard 等工具,或是对 /dev/sdX 上的文件系统上使用 fstrim。
如果想在特定厂商或产品设备连接时自动启用一个“provisioning_mode”,可以使用 udev。首先找到 USB Vendor 和 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 工具来更新固件。
检查当前固件版本:
# smartctl -i /dev/ssd_device
威刚(ADATA)[编辑 | 编辑源代码]
威刚不支持在 Linux 下更新 SSD 固件。可以在支持页下载仅支持 Windows 的 SSD ToolBox 工具,也可从支持页下载 ADATA XPG 来对 SSD 进行监控、TRIM、基准测试或更新固件。
英睿达(Crucial)[编辑 | 编辑源代码]
英睿达提供了以 ISO 镜像文件升级固件的选项。在 SSD 支持页选择产品后,下载“Manual Boot File”可获取 ISO 镜像。
dd
命令将镜像复制到设备上,由于没有配置 MBR,将导致无法从该设备启动。要解决这一问题,可安装 syslinux包 并执行 isohybrid path/to/image.iso
。Crucial M4 用户可通 过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 软件的系统,英特尔提供了一个基于 Linux live 系统的固件更新工具。
此外,还可用使用 Intel Memory and Storage (MAS) Tool(intel-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.
如果只有一个 Intel SSD,可以省略 -intelssd 0
;如果要指定第二块 SSD,则修改为 -intelssd 1
,依此类推。
如果有可用的更新,可通过 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-utilityAUR、ocztoolboxAUR、oczcloutAUR。
三星(Samsung)[编辑 | 编辑源代码]
除了使用 Magician 软件外,也有其它方法升级固件(尽管三星认为这是“不受支持”的)。Magician 软件可以创建包含固件更新的启动盘,然而三星不再为消费级 SSD 提供该软件。此外,三星提供的可引导 ISO 镜像也能用来更新固件。另外一种方法是使用 magician 工具(samsung_magician-consumer-ssdAUR)。Magician 只支持三星品牌的 SSD,不支持三星为其它 OEM(如联想)制造的 SSD。
如果你想通过在 Linux 下创建的 Live USB 来更新固件(而不是在 Windows 下使用三星的 Magician 软件),参见[11]。注意,该文章描述的通过 MBR 创建可启动 U 盘的方法在一些新主板上(例如 Intel NUC)不再受支持。
在 Linux 下更新[编辑 | 编辑源代码]
以下方法可以原生(不使用可启动 U 盘)更新 SSD 固件。首先,访问三星的下载页,进入”Samsung SSD Firmware“一节,然后下载适用于你的 SSD 的最新固件(ISO 镜像)。
initrd
Linux 镜像,请跳到#较旧的 SSD 一节。从 ISO 镜像中解压 Linux initrd
镜像(将 samsung_ssd_firmware 替换为对应的 ISO 镜像文件名):
$ bsdtar xf samsung_ssd_firmware.iso initrd
解压 root/fumagician/
。该目录中包含固件更新文件:
$ bsdtar xf initrd root/fumagician
最后,以根用户权限运行 root/fumagician/fumagician
,确认成功更新固件后,重启计算机。
如果重启后固件版本没有变化,可以执行 root/fumagician/fumagician 2> log
并检查日志里的报错。例如,如果日志里写着 'unzip is not available',就说明需要安装 unzip 或从 initrd 中提取 unzip。
较旧的 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 的 Disk Number 获取 SSD 对应的硬盘编号:
# magician --list
更新 SSD 固件(将 firmware_package_path 替换为对应的固件包路径):
# magician --disk Disk Number --firmware-update --fwpackage-path /mnt/firmware_package_path
最后,以根用户权限执行 magician --list
,检查输出中 Firmware 对应的固件版本是否成功更新,并重启计算机。
闪迪(SanDisk)[编辑 | 编辑源代码]
对于 SanDisk SSD Toolkit 不支持的操作系统,闪迪提供了 ISO 镜像来进行固件更新。
你必须选择对应 SSD 型号和容量(例如 60GB 或 256GB)正确的固件。烧录 ISO 镜像后,从创建的 CD/DVD 启动盘启动计算机即可(或许能使用 USB 启动盘)。
此外,由于 ISO 镜像只包含了 Linux 内核及 initrd,也可以将它们提取到 /boot
分区下,并用 GRUB 或 Syslinux 启动来更新固件。
另见:
- SanDisk Extreme SSD Manual Firmware update version R211
- SanDisk Ultra SSD Manual Firmware update version 365A13F0
- SanDisk Ultra+ SSD Manual Firmware update version X2316RL - 以根用户权限执行
smartctl -i dev/disk/by-id/*SanDisk!(*part*)
检查是否使用了“H2”或“HP”型号。