固态硬盘 - Arch Linux 中文维基

跳转到内容

# 固态硬盘

来自 Arch Linux 中文维基
翻译状态：

- 本文（或部分内容）译自 Solid_State_Drives，最近一次同步于 2025-02-05，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

相关文章

- 固态硬盘/NVMe
- 固态硬盘/存储单元擦除
- 基准测试
- 性能优化#存储设备

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

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

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

## 使用

### TRIM

在机械硬盘上，删除操作是在文件系统层级上处理的[1]，而 SSD 会向硬盘主控通知特定区域的空间可以被再次使用。由于每次写入操作都会对闪存单元一定磨损，因此主控会使用算法来将写操作平衡到闪存的所有单元上，这被称作耗损平均技术。在不使用 NVMe DEALLOCATE，SAS UNMAP 或 ATA_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.service` 和 `fstrim.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文件系统，也可用 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

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

为 LUKS 和普通 dm-crypt 设备启用 discard 的步骤请参考 dm-crypt/特殊应用#固态硬盘的Discard/TRIM支持。

#### 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，都可以参考固态硬盘/存储单元擦除中的对应步骤进行重置。

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

### 安全

#### 冻结（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]

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

如果你想擦除 SSD，请参考安全地擦除磁盘#hdparm 和 /存储单元擦除。

##### 从睡眠中唤醒时设置 SATA SSD 为冻结模式

当从 S3 睡眠状态唤醒时，SATA SSD 很可能会回到 SEC1 状态（禁用安全、非锁定、非冻结），导致其有可能受 /存储单元擦除中描述的 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 产生的。在尝试排除故障前，请检查固件是否有更新：

- SSD 的固件
- 主板的 BIOS/UEFI 固件

即使是固件的 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

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

原因：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) 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。

注意：对于这些信息，三星提供得并不十分明确。他们似乎有 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` 分区下，并用 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”型号。

## 另见

- Discussion on Reddit about installing Arch on an SSD
- Re: Varying Leafsize and Nodesize in Btrfs
- Re: SSD alignment and Btrfs sector size
- Erase Block (Alignment) Misinformation?
- Is alignment to erase block size needed for modern SSD's?
- Btrfs support for efficient SSD operation (data blocks alignment)

分类：​

- 存储
- 使用“模板:风格”标记的页面或章节

固态硬盘
添加话题