持久块设备命名
本文介绍如何为您的块设备使用持久命名。这得益于 udev 的引入,并且相比于基于总线的命名方式具有一些优势。如果您的机器有多个驱动器共享一个命名方案,则它们对应的设备节点被添加的顺序是任意的。这可能会导致块设备名称(例如 /dev/sda
和 /dev/sdb
、/dev/nvme0n1
和 /dev/nvme1n1
、/dev/mmcblk0
和 /dev/mmcblk1
)在每次启动时发生切换,最终导致系统无法启动、内核崩溃或块设备消失。持久命名解决了这些问题。
- 持久命名具有本文范围之外的限制。例如,虽然 mkinitcpio 可能支持一种方法,但 systemd 可能会对其在启动期间可以处理的命名施加自己的限制(例如 FS#42884)。
- 本文与 LVM 逻辑卷无关,因为
/dev/VolumeGroupName/LogicalVolumeName
设备路径是持久的。
持久命名方法
有多种方案提供由 udev 管理的持久命名。
60-persistent-storage.rules
默认提供四种:by-label、by-uuid、by-id 和 by-path。对于带有 GUID 分区表 (GPT) 的磁盘,还有两种额外的方案——by-partlabel 和 by-partuuid。99-systemd.rules
为与 GPT 分区自动挂载 兼容的设置提供了 gpt-auto。
/dev/disk/
中的目录是动态创建和销毁的,具体取决于其中是否有设备。
以下部分描述了不同的持久命名方法是什么以及如何使用它们。
可以使用 lsblk 命令以图形方式查看第一个持久方案
$ lsblk -f
NAME FSTYPE LABEL UUID MOUNTPOINT sda ├─sda1 vfat CBB6-24F2 /boot ├─sda2 ext4 Arch Linux 0a3407de-014b-458b-b5c1-848e92a327a3 / ├─sda3 ext4 Data b411dc99-f0a0-4c87-9e05-184977be8539 /home └─sda4 swap f9fe0b69-a280-415d-a03a-a32752370dee [SWAP] mmcblk0 └─mmcblk0p1 vfat F4CA-5D75
对于使用 GPT 的用户,请改用 blkid
命令。后者对于脚本更方便,但更难阅读。
# blkid
/dev/sda1: UUID="CBB6-24F2" TYPE="vfat" PARTLABEL="EFI system partition" PARTUUID="d0d0d110-0a71-4ed6-936a-304969ea36af" /dev/sda2: LABEL="Arch Linux" UUID="0a3407de-014b-458b-b5c1-848e92a327a3" TYPE="ext4" PARTLABEL="GNU/Linux" PARTUUID="98a81274-10f7-40db-872a-03df048df366" /dev/sda3: LABEL="Data" UUID="b411dc99-f0a0-4c87-9e05-184977be8539" TYPE="ext4" PARTLABEL="Home" PARTUUID="7280201c-fc5d-40f2-a9b2-466611d3d49e" /dev/sda4: UUID="f9fe0b69-a280-415d-a03a-a32752370dee" TYPE="swap" PARTLABEL="Swap" PARTUUID="039b6c1c-7553-4455-9537-1befbc9fbc5b" /dev/mmcblk0: PTUUID="0003e1e5" PTTYPE="dos" /dev/mmcblk0p1: UUID="F4CA-5D75" TYPE="vfat" PARTUUID="0003e1e5-01"
by-label
几乎每种文件系统类型都可以有一个标签。您所有带有标签的卷都列在 /dev/disk/by-label
目录中。
$ ls -l /dev/disk/by-label/
total 0 lrwxrwxrwx 1 root root 10 May 27 23:31 Data -> ../../sda3 lrwxrwxrwx 1 root root 10 May 27 23:31 Arch\x20Linux -> ../../sda2
大多数文件系统都支持在创建文件系统时设置标签,请参阅相关 mkfs.*
实用程序的手册页。对于某些文件系统,也可以更改标签。以下是更改常见文件系统标签的一些方法
- btrfs
btrfs filesystem label /dev/XXX "new label"
(如果设备已挂载,则使用设备的挂载点),使用 btrfs-progs- crypto_LUKS(仅限 LUKS2)
cryptsetup config --label="new label" /dev/XXX
,使用 cryptsetup- exfat
tune.exfat -L "new label" /dev/XXX
,使用 exfatprogsexfatlabel /dev/XXX "new label"
,使用 exfatprogs 或 exfat-utils- ext2/3/4
e2label /dev/XXX "new label"
,使用 e2fsprogs- fat/vfat
fatlabel /dev/XXX "new label"
,使用 dosfstoolsmlabel -i /dev/XXX ::"new label"
,使用 mtools- jfs
jfs_tune -L "new label" /dev/XXX
,使用 jfsutils- ntfs
ntfslabel /dev/XXX "new label"
,使用 ntfs-3g- reiserfs
reiserfstune -l "new label" /dev/XXX
,使用 reiserfsprogsAUR- swap
swaplabel -L "new label" /dev/XXX
,使用 util-linux- udf
udflabel /dev/XXX "new label"
,使用 udftools- xfs
xfs_admin -L "new label" /dev/XXX
(如果设备已挂载,则使用设备的挂载点),使用 xfsprogs
可以使用 lsblk 获取设备的标签
$ lsblk -dno LABEL /dev/sda2
Arch Linux
或使用 blkid
# blkid -s LABEL -o value /dev/sda2
Arch Linux
- 标签必须是明确的,以防止任何可能的冲突。
- 标签最多可以包含 16 个字符。
- 由于标签是文件系统的属性,因此它不适合持久性地寻址单个 RAID 设备。
- 当使用 dm-crypt 加密容器时,容器内部文件系统的标签在容器锁定/加密时不可用。
by-uuid
UUID 是一种为每个文件系统提供唯一标识符的机制。这些标识符由文件系统实用程序(例如 mkfs.*
)在设备格式化时生成,并且经过设计,碰撞的可能性很小。所有 GNU/Linux 文件系统(包括原始加密设备的交换分区和 LUKS 标头)都支持 UUID。FAT、exFAT 和 NTFS 文件系统不支持 UUID,但仍以较短的 UID(唯一标识符)列在 /dev/disk/by-uuid/
中
$ ls -l /dev/disk/by-uuid/
total 0 lrwxrwxrwx 1 root root 10 May 27 23:31 0a3407de-014b-458b-b5c1-848e92a327a3 -> ../../sda2 lrwxrwxrwx 1 root root 10 May 27 23:31 b411dc99-f0a0-4c87-9e05-184977be8539 -> ../../sda3 lrwxrwxrwx 1 root root 10 May 27 23:31 CBB6-24F2 -> ../../sda1 lrwxrwxrwx 1 root root 10 May 27 23:31 f9fe0b69-a280-415d-a03a-a32752370dee -> ../../sda4 lrwxrwxrwx 1 root root 10 May 27 23:31 F4CA-5D75 -> ../../mmcblk0p1
可以使用 lsblk 获取设备的 UUID
$ lsblk -dno UUID /dev/sda1
CBB6-24F2
或使用 blkid
# blkid -s UUID -o value /dev/sda1
CBB6-24F2
使用 UUID 方法的优点是名称冲突的发生可能性比标签小得多。此外,它是在创建文件系统时自动生成的。例如,即使设备插入到另一个系统(该系统可能具有相同标签的设备),它仍将保持唯一。
缺点是 UUID 使长代码行难以阅读,并且会破坏许多配置文件(例如 fstab 或 crypttab)中的格式。此外,每次重新格式化卷时都会生成新的 UUID,并且必须手动调整配置文件。
by-id 和 by-path
by-id
根据硬件序列号创建唯一名称,by-path
根据最短物理路径(根据 sysfs)创建唯一名称。两者都包含指示它们所属子系统的字符串(即 by-path
的 pci-
和 by-id
的 ata-
),因此它们链接到控制设备的硬件。这意味着不同的持久性级别:当设备插入控制器的不同端口时,by-path
已经会发生变化;当设备插入到受另一个子系统控制的硬件控制器的端口时,by-id
会发生变化。[1] 因此,两者都不适合实现对硬件更改具有容错能力的持久命名。
但是,两者都提供了在大型硬件基础设施中查找特定设备的重要信息。例如,如果您不手动分配持久标签(by-label
或 by-partlabel
)并保留硬件端口使用情况目录,则可以使用 by-id
和 by-path
查找特定设备。[2] [3]
by-id
和by-path
链接只能被视为磁盘的持久链接,而不是分区的持久链接。分区将通过它们在分区表中的编号来引用,如果重新排序分区,则该编号可能会更改。- 如果从系统中添加或删除 PCIe 设备,或者系统固件未确定性地枚举它们,则 NVMe 设备的
/dev/disk/by-path/pci-*
路径可能会更改。 - 不带命名空间标识符 (NSID) 的 NVMe 设备
by-id
链接已过时。请改用硬件序列号后带有命名空间标识符的链接(例如,第一个命名空间的_1
或第一个命名空间上第一个分区的_1-part1
)。
$ ls -l /dev/disk/by-id/
total 0 lrwxrwxrwx 1 root root 10 May 27 23:31 ata-WDC_WD2500BEVT-22ZCT0_WD-WXE908VF0470 -> ../../sda lrwxrwxrwx 1 root root 10 May 27 23:31 ata-WDC_WD2500BEVT-22ZCT0_WD-WXE908VF0470-part1 -> ../../sda1 lrwxrwxrwx 1 root root 10 May 27 23:31 ata-WDC_WD2500BEVT-22ZCT0_WD-WXE908VF0470-part2 -> ../../sda2 lrwxrwxrwx 1 root root 10 May 27 23:31 ata-WDC_WD2500BEVT-22ZCT0_WD-WXE908VF0470-part3 -> ../../sda3 lrwxrwxrwx 1 root root 10 May 27 23:31 ata-WDC_WD2500BEVT-22ZCT0_WD-WXE908VF0470-part4 -> ../../sda4 lrwxrwxrwx 1 root root 10 May 27 23:31 mmc-SD32G_0x0040006d -> ../../mmcblk0 lrwxrwxrwx 1 root root 10 May 27 23:31 mmc-SD32G_0x0040006d-part1 -> ../../mmcblk0p1 lrwxrwxrwx 1 root root 13 May 27 23:31 nvme-Samsung_SSD_970_EVO_Plus_2TB_S4J4NJ0N704064T -> ../../nvme1n1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-Samsung_SSD_970_EVO_Plus_2TB_S4J4NJ0N704064T-part1 -> ../../nvme1n1p1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-Samsung_SSD_970_EVO_Plus_2TB_S4J4NJ0N704064T-part2 -> ../../nvme1n1p2 lrwxrwxrwx 1 root root 13 May 27 23:31 nvme-Samsung_SSD_970_EVO_Plus_2TB_S4J4NJ0N704064T_1 -> ../../nvme1n1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-Samsung_SSD_970_EVO_Plus_2TB_S4J4NJ0N704064T_1-part1 -> ../../nvme1n1p1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-Samsung_SSD_970_EVO_Plus_2TB_S4J4NJ0N704064T_1-part2 -> ../../nvme1n1p2 lrwxrwxrwx 1 root root 13 May 27 23:31 nvme-WDS100T1X0E-00AFY0_21455A801268 -> ../../nvme0n1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-WDS100T1X0E-00AFY0_21455A801268-part1 -> ../../nvme0n1p1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-WDS100T1X0E-00AFY0_21455A801268-part2 -> ../../nvme0n1p2 lrwxrwxrwx 1 root root 13 May 27 23:31 nvme-WDS100T1X0E-00AFY0_21455A801268_1 -> ../../nvme0n1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-WDS100T1X0E-00AFY0_21455A801268_1-part1 -> ../../nvme0n1p1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-WDS100T1X0E-00AFY0_21455A801268_2-part2 -> ../../nvme0n1p2 lrwxrwxrwx 1 root root 13 May 27 23:31 nvme-eui.002538570142d716 -> ../../nvme1n1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-eui.002538570142d716-part1 -> ../../nvme1n1p1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-eui.002538570142d716-part2 -> ../../nvme1n1p2 lrwxrwxrwx 1 root root 13 May 27 23:31 nvme-eui.e8238fa6bf530001001b448b4566aa1a -> ../../nvme0n1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-eui.e8238fa6bf530001001b448b4566aa1a-part1 -> ../../nvme0n1p1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-eui.e8238fa6bf530001001b448b4566aa1a-part2 -> ../../nvme0n1p2 lrwxrwxrwx 1 root root 10 May 27 23:31 wwn-0x60015ee0000b237f -> ../../sda lrwxrwxrwx 1 root root 10 May 27 23:31 wwn-0x60015ee0000b237f-part1 -> ../../sda1 lrwxrwxrwx 1 root root 10 May 27 23:31 wwn-0x60015ee0000b237f-part2 -> ../../sda2 lrwxrwxrwx 1 root root 10 May 27 23:31 wwn-0x60015ee0000b237f-part3 -> ../../sda3 lrwxrwxrwx 1 root root 10 May 27 23:31 wwn-0x60015ee0000b237f-part4 -> ../../sda4
$ ls -l /dev/disk/by-path/
total 0 lrwxrwxrwx 1 root root 10 May 27 23:31 pci-0000:00:1f.2-ata-1 -> ../../sda lrwxrwxrwx 1 root root 10 May 27 23:31 pci-0000:00:1f.2-ata-1-part1 -> ../../sda1 lrwxrwxrwx 1 root root 10 May 27 23:31 pci-0000:00:1f.2-ata-1-part2 -> ../../sda2 lrwxrwxrwx 1 root root 10 May 27 23:31 pci-0000:00:1f.2-ata-1-part3 -> ../../sda3 lrwxrwxrwx 1 root root 10 May 27 23:31 pci-0000:00:1f.2-ata-1-part4 -> ../../sda4 lrwxrwxrwx 1 root root 13 May 27 23:31 pci-0000:01:00.0-nvme-1 -> ../../nvme0n1 lrwxrwxrwx 1 root root 15 May 27 23:31 pci-0000:01:00.0-nvme-1-part1 -> ../../nvme0n1p1 lrwxrwxrwx 1 root root 15 May 27 23:31 pci-0000:01:00.0-nvme-1-part2 -> ../../nvme0n1p2 lrwxrwxrwx 1 root root 13 May 27 23:31 pci-0000:04:00.0-nvme-1 -> ../../nvme1n1 lrwxrwxrwx 1 root root 15 May 27 23:31 pci-0000:04:00.0-nvme-1-part1 -> ../../nvme1n1p1 lrwxrwxrwx 1 root root 15 May 27 23:31 pci-0000:04:00.0-nvme-1-part2 -> ../../nvme1n1p2 lrwxrwxrwx 1 root root 10 May 27 23:31 pci-0000:07:00.0-platform-rtsx_pci_sdmmc.0 -> ../../mmcblk0 lrwxrwxrwx 1 root root 10 May 27 23:31 pci-0000:07:00.0-platform-rtsx_pci_sdmmc.0-part1 -> ../../mmcblk0p1
世界通用名称
by-id
还会创建支持它的存储设备的 世界通用名称 (WWN) 链接。与其他 by-id
链接不同,WWN 是完全持久的,并且不会根据使用的子系统而更改。
SATA 和 SAS 设备具有 wwn-
前缀,而 NVMe 设备使用不同的 WWN 格式,并以 nvme-eui.
为前缀。[4]
$ ls -l /dev/disk/by-id/{wwn-,nvme-eui.}*
lrwxrwxrwx 1 root root 13 May 27 23:31 nvme-eui.002538570142d716 -> ../../nvme1n1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-eui.002538570142d716-part1 -> ../../nvme1n1p1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-eui.002538570142d716-part2 -> ../../nvme1n1p2 lrwxrwxrwx 1 root root 13 May 27 23:31 nvme-eui.e8238fa6bf530001001b448b4566aa1a -> ../../nvme0n1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-eui.e8238fa6bf530001001b448b4566aa1a-part1 -> ../../nvme0n1p1 lrwxrwxrwx 1 root root 15 May 27 23:31 nvme-eui.e8238fa6bf530001001b448b4566aa1a-part2 -> ../../nvme0n1p2 lrwxrwxrwx 1 root root 10 May 27 23:31 wwn-0x60015ee0000b237f -> ../../sda lrwxrwxrwx 1 root root 10 May 27 23:31 wwn-0x60015ee0000b237f-part1 -> ../../sda1 lrwxrwxrwx 1 root root 10 May 27 23:31 wwn-0x60015ee0000b237f-part2 -> ../../sda2 lrwxrwxrwx 1 root root 10 May 27 23:31 wwn-0x60015ee0000b237f-part3 -> ../../sda3 lrwxrwxrwx 1 root root 10 May 27 23:31 wwn-0x60015ee0000b237f-part4 -> ../../sda4
by-partlabel
GPT 分区标签可以在 GPT 磁盘的 分区条目的标头中定义。
此方法与 文件系统标签 非常相似,不同之处在于,如果更改分区上的文件系统,分区标签不会受到影响。
所有具有分区标签的分区都列在 /dev/disk/by-partlabel
目录中。
$ ls -l /dev/disk/by-partlabel/
total 0 lrwxrwxrwx 1 root root 10 May 27 23:31 EFI\x20system\x20partition -> ../../sda1 lrwxrwxrwx 1 root root 10 May 27 23:31 GNU\x2fLinux -> ../../sda2 lrwxrwxrwx 1 root root 10 May 27 23:31 Home -> ../../sda3 lrwxrwxrwx 1 root root 10 May 27 23:31 Swap -> ../../sda4
可以使用 lsblk 获取设备的分区标签
$ lsblk -dno PARTLABEL /dev/sda1
EFI system partition
或使用 blkid
# blkid -s PARTLABEL -o value /dev/sda1
EFI system partition
by-partuuid
与 GPT 分区标签 类似,GPT 分区 UUID 在 GPT 磁盘的 分区条目中定义。
MBR 不支持分区 UUID,但 Linux[5] 和使用 libblkid[6] 的软件(例如 udev[7])能够为 MBR 分区生成伪 PARTUUID。格式为 SSSSSSSS-PP
,其中 SSSSSSSS
是零填充的 32 位 MBR 磁盘签名,PP
是十六进制形式的零填充分区号。与 GPT 分区的常规 PARTUUID 不同,如果分区号更改,MBR 的伪 PARTUUID 可能会更改。
动态目录与其他方法类似,并且与 文件系统 UUID 一样,使用 UUID 优先于标签。
$ ls -l /dev/disk/by-partuuid/
total 0 lrwxrwxrwx 1 root root 10 May 27 23:31 0003e1e5-01 -> ../../mmcblk0p1 lrwxrwxrwx 1 root root 10 May 27 23:31 039b6c1c-7553-4455-9537-1befbc9fbc5b -> ../../sda4 lrwxrwxrwx 1 root root 10 May 27 23:31 7280201c-fc5d-40f2-a9b2-466611d3d49e -> ../../sda3 lrwxrwxrwx 1 root root 10 May 27 23:31 98a81274-10f7-40db-872a-03df048df366 -> ../../sda2 lrwxrwxrwx 1 root root 10 May 27 23:31 d0d0d110-0a71-4ed6-936a-304969ea36af -> ../../sda1
可以使用 lsblk 获取设备的分区 UUID
$ lsblk -dno PARTUUID /dev/sda1
d0d0d110-0a71-4ed6-936a-304969ea36af
或使用 blkid
# blkid -s PARTUUID -o value /dev/sda1
d0d0d110-0a71-4ed6-936a-304969ea36af
gpt-auto
如果满足 systemd-gpt-auto-generator 的所有先决条件,udev 将创建一个指向根卷块设备的 /dev/gpt-auto-root
符号链接。如果根分区使用 LUKS 加密,则 /dev/gpt-auto-root
将指向解锁/映射的卷,而 /dev/gpt-auto-root-luks
将指向加密的分区。
$ ls -l /dev/gpt-auto-*
lrwxrwxrwx 1 root root 10 May 27 23:31 /dev/gpt-auto-root -> dm-0 lrwxrwxrwx 1 root root 10 May 27 23:31 /dev/gpt-auto-root-luks -> nvme1n1p2
使用持久命名
有各种应用程序可以使用持久命名进行配置。以下是一些如何配置它们的示例。
fstab
请参阅主文章:fstab#识别文件系统。
内核参数
要在内核参数中使用持久名称,必须满足以下先决条件。在遵循安装指南的标准安装中,这两个先决条件都已满足
- 您正在使用包含 udev 的 initramfs 镜像。
- 对于 mkinitcpio,在
/etc/mkinitcpio.conf
中启用udev
或systemd
钩子。
根文件系统的位置由内核命令行上的参数 root
给出。内核命令行从引导加载器配置,请参阅内核参数#引导加载器配置。要更改为持久设备命名,只需更改指定块设备的参数,例如 root
和 resume
,同时保持其他参数不变。支持各种命名方案
持久设备命名使用标签和 LABEL=
格式,在本例中 Arch Linux
是根文件系统的标签。
root="LABEL=Arch Linux"
持久设备命名使用 UUID 和 UUID=
格式,在本例中 0a3407de-014b-458b-b5c1-848e92a327a3
是根文件系统的 UUID。
root=UUID=0a3407de-014b-458b-b5c1-848e92a327a3
持久设备命名使用磁盘 ID 和 /dev
路径格式,在本例中 wwn-0x60015ee0000b237f-part2
是根分区的 ID。
root=/dev/disk/by-id/wwn-0x60015ee0000b237f-part2
持久设备命名使用 GPT 分区 UUID 和 PARTUUID=
格式,在本例中 98a81274-10f7-40db-872a-03df048df366
是根分区的 PARTUUID。
root=PARTUUID=98a81274-10f7-40db-872a-03df048df366
持久设备命名使用 GPT 分区标签和 PARTLABEL=
格式,在本例中 GNU/Linux
是根分区的 PARTLABEL。
root="PARTLABEL=GNU/Linux"
当使用 GPT 分区自动挂载 时,可以完全省略 root=
参数。如果需要显式配置,请使用
root=gpt-auto