持久块设备命名

来自 ArchWiki
(重定向自 LABEL

本文介绍如何为您的块设备使用持久化命名。这得益于 udev 的引入,并且相比于基于总线的命名方式有一些优势。如果您的机器有多个驱动器共享一个命名方案,则添加它们对应的设备节点的顺序是任意的。这可能会导致块设备名称 (例如 /dev/sda/dev/sdb/dev/nvme0n1/dev/nvme1n1/dev/mmcblk0/dev/mmcblk1) 在每次启动时发生切换,最终导致系统无法启动、内核崩溃或块设备消失。持久化命名解决了这些问题。

注意
  • 持久化命名有一些超出本文范围的限制。例如,虽然 mkinitcpio 可能支持一种方法,但 systemd 可能会对其在启动期间可以处理的命名施加其自身的限制 (例如 FS#42884)。
  • 本文与 LVM 逻辑卷无关,因为 /dev/VolumeGroupName/LogicalVolumeName 设备路径是持久的。

持久命名方法

有不同的方案提供由 udev 管理的持久命名。

/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.* 实用程序的 man page。对于某些文件系统,也可以更改标签。以下是一些用于更改常见文件系统标签的方法

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 使用 exfatprogs
exfatlabel /dev/XXX "new label" 使用 exfatprogsexfat-utils
ext2/3/4
e2label /dev/XXX "new label" 使用 e2fsprogs
fat/vfat
fatlabel /dev/XXX "new label" 使用 dosfstools
mlabel -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 使长代码行难以阅读,并破坏许多配置文件 (例如 fstabcrypttab) 中的格式。此外,每次重新格式化卷时都会生成新的 UUID,并且必须手动调整配置文件。

提示: 如果您的交换分区卷没有分配 UUID,您将需要使用 mkswap 实用程序重置它。

by-id 和 by-path

by-id 根据硬件序列号创建唯一名称,by-path 根据最短物理路径 (根据 sysfs) 创建唯一名称。两者都包含指示它们所属子系统的字符串 (by-pathpci-by-idata-),因此它们链接到控制设备的硬件。这意味着不同的持久性级别:当设备插入控制器的不同端口时,by-path 已经会发生变化,当设备插入到受另一个子系统控制的硬件控制器的端口时,by-id 会发生变化。[1] 因此,两者都不适合实现对硬件更改具有容错性的持久命名。

但是,两者都提供了重要的信息,以便在大型硬件基础设施中找到特定设备。例如,如果您不手动分配持久标签 (by-labelby-partlabel) 并保留一个包含硬件端口使用情况的目录,则可以使用 by-idby-path 查找特定设备。[2] [3]

注意
  • by-idby-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

World Wide Name

by-id 还会创建支持它的存储设备的 World Wide Name (WWN) 链接。与其他 by-id 链接不同,WWN 是完全持久的,并且不会根据使用的子系统而更改。

SATA 和 SAS 设备具有 wwn- 前缀,而 NVMe 设备使用不同的 WWN 格式,并以 nvme-eui. 为前缀。[4]

提示: 存储设备的 WWN 通常印在其标签上 (驱动器顶部的贴纸)。
$ 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

注意: 此方法仅适用于带有 GUID 分区表 (GPT) 的磁盘。

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
注意
  • GPT 分区标签也必须不同,以避免冲突。要更改分区标签,您可以使用 gdisk 或基于 ncurses 的版本 cgdisk。两者都可从 gptfdisk 软件包获得。请参阅 分区#分区工具
  • 根据规范,GPT 分区标签最多可以包含 72 个字符。

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#识别文件系统

内核参数

要在内核参数中使用持久名称,必须满足以下先决条件。在遵循安装指南的标准安装中,这两个先决条件都已满足

根文件系统的位置由内核命令行上的参数 root 给出。内核命令行是从引导加载程序配置的,请参阅内核参数#引导加载程序配置。要更改为持久设备命名,只需更改指定块设备的参数,例如 rootresume,同时保持其他参数不变。支持各种命名方案

持久设备命名 使用标签LABEL= 格式,在本例中 Arch Linux 是根文件系统的标签。

root="LABEL=Arch Linux"

持久设备命名 使用 UUIDUUID= 格式,在本例中 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 分区 UUIDPARTUUID= 格式,在本例中 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