跳转到内容

固态硬盘

来自 Arch Linux 中文维基
(重定向自Solid state drive

本文介绍如何管理固态硬盘(SSD)等基于闪存的存储设备。

如果要针对特定目的对 SSD 进行分区,请参考针对闪存优化的文件系统清单

对于一般用途,您只需选择喜好的文件系统并启用 #TRIM

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

TRIM[编辑 | 编辑源代码]

在机械硬盘上,删除操作是在文件系统层级上处理的[1],而 SSD 会向硬盘主控通知特定区域的空间可以被再次使用。由于每次写入操作都会对闪存单元一定磨损,因此主控会使用算法来将写操作平衡到闪存的所有单元上,这被称作耗损平均技术。在不使用 NVMe DEALLOCATE,SAS UNMAPATA_TRIM 命令(多数 SSD 都支持)的情况下,如果没有空余的存储块,主控就需要反复搬运数据以空出一个最小擦除单元,并擦除该单元以写入数据,导致写入耗时增加(详见:写入放大)。关于 SSD 空间占满前后的性能对比可参考 TechSpot 的评测

注意:如果要使用 TRIM,只能在定期 TRIM 和持续性 TRIM 间二选一。Linux 社区认为持续性 TRIM 不是首选的 TRIM 方法,例如 Ubuntu 就默认使用定期 TRIM [2],Debian 也不建议使用持续性 TRIM,红帽建议尽可能选择使用定期 TRIM [3]

自 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 功能前,请确保 SSD 支持 TRIM,否则可能导致数据丢失!

要检查 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.servicefstrim.timer 两个 systemd 单元文件。启用 fstrim.timer 计时器会在每周激活服务,在所有已挂载的支持 discard 操作的文件系统上执行 fstrim(8)

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

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

持续性 TRIM[编辑 | 编辑源代码]

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

警告:SATA 3.1 前,所有 TRIM 指令都是非队列化的,因此使用持续性 TRIM 将造成系统频繁卡顿,这种情况下应使用 #定期 TRIM。另外,某些设备(具体请参考 Linux 源码中的 __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
注意:不能在 /etc/fstab 中为 XFS / 分区指定 discard 挂载选项。根据此帖子,必须使用 rootflags=discard 内核参数

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

# tune2fs -o discard /dev/sdXY

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

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

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

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

LVM[编辑 | 编辑源代码]

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

LVM 操作(lvremovelvreduce等)默认不会产生 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[编辑 | 编辑源代码]

警告:dm-crypt 支持将 discard 请求传递到底层块设备上。这不一定能提升 SSD 的性能[9],而且还有安全风险,因此默认不被启用。

为 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.

警告:对于使用 mdadm 的 RAID 配置,为 swapon 启用 discard 会导致系统在启动和运行时锁死。

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

参见性能优化#存储设备

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

有时用户可能会想将 SSD 的存储单元重置回出厂状态,从而恢复到出厂时的写入性能。由于 TRIM 只对文件删除有用,而对替换操作(如增量保存)无能为力,因此就算 SSD 带有原生 TRIM 支持,其写入性能还是会随时间逐渐下降。

无论是 SATA 还是 NVMe SSD,都可以参考 固态硬盘/Memory cell clearing 中的对应步骤进行重置。

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

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

冻结(Frozen)模式[编辑 | 编辑源代码]

有些主板的固件会在初始化时向 SATA 设备发送 ATA SECURITY FREEZE LOCK 命令,将硬盘设为冻结模式(即切换到 SEC2 状态,禁用安全、非锁定并冻结)。同样,有些 SSD 和 HDD 在出厂时也会设成该状态。可以通过 hdparmsmartctl 的输出确认该现象:

# 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]

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

如果你想擦除 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 版本开始默认启用,也可能会被节能守护进程(例如 TLPLaptop Mode Tools)启用。更多信息请参考电源管理#SATA 活动链路电源管理

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

本文或本章节的语言、语法或风格需要改进。参考:帮助:风格

原因:Several style and formatting problems, especially too many explicit commands - see Help:Style#File editing requests.(在Talk:固态硬盘讨论)

有多个 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、基准测试或更新固件。

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

英睿达(Crucial)[编辑 | 编辑源代码]

英睿达提供了以 ISO 镜像文件升级固件的选项。在 SSD 支持页选择产品后,下载“Manual Boot File”可获取 ISO 镜像。

注意:英睿达提供的 ISO 镜像似乎不是 hybrid 格式。如果直接使用 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) 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.

如果只有一个 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-utilityAURocztoolboxAURoczcloutAUR

三星(Samsung)[编辑 | 编辑源代码]

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

注意:对于这些信息,三星提供得并不十分明确。他们似乎有 4 个不同的固件更新页面,每个都介绍了不同的更新方法。

如果你想通过在 Linux 下创建的 Live USB 来更新固件(而不是在 Windows 下使用三星的 Magician 软件),参见[11]。注意,该文章描述的通过 MBR 创建可启动 U 盘的方法在一些新主板上(例如 Intel NUC)不再受支持。

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

以下方法可以原生(不使用可启动 U 盘)更新 SSD 固件。首先,访问三星的下载页,进入”Samsung SSD Firmware“一节,然后下载适用于你的 SSD 的最新固件(ISO 镜像)。

注意:若 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 分区下,并用 GRUBSyslinux 启动来更新固件。

另见:

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