Persistent block device naming (简体中文)

From ArchWiki
翻译状态:本文是 Persistent block device naming翻译。上次翻译日期:2022-08-30。如果英文版本有所更改,则您可以帮助同步翻译。

本文讲述如何为你的块设备提供持久化命名。udev的导入使之成为可能,也使之优于基于总线的命名法。如果你的机器上有不止一个 SATA, SCSI 或 IDE 磁盘控制器,那么它们所对应的设备节点将会依随机次序添加。这样就可能导致每次引导时设备的名字如 /dev/sda/dev/sdb 互换了,最终导致系统不可引导、kernel panic、或者设备不可见。持久化命名法可以解决这些问题。

注意:
  • 持久设备名有一些超出本文范围的限制,比如虽然 mkinitcpio 支持某个方法,但 systemd 会对支持的设备名添加额外的限制(例如 FS#42884)。
  • 本文与 LVM 逻辑卷无关,因为 /dev/VolumeGroupName/LogicalVolumeName 设备路径是持久化的。

持久化命名的方法

有四种持久化命名方案:通过标签通过 uuid通过 id 和 通过路径。对于那些使用GUID 分区表(GPT)的磁盘,还有额外的两种方案,通过分区标签通过分区 uuid。你也可以使用 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

GUID 分区表的分区应改用 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"

通过标签

几乎每一种文件系统都可以有一个标签。所有有标签的卷都在 /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 手册页面。对于一些也可以修改标签的文件系统。下面列出了一些常见文件系统修改标签的方式:

swap
swaplabel -L "new label" /dev/XXX 使用 util-linux
ext2/3/4
e2label /dev/XXX "new label" 使用 e2fsprogs
btrfs
btrfs filesystem label /dev/XXX "new label" 使用 btrfs-progs
reiserfs
reiserfstune -l "new label" /dev/XXX 使用 reiserfsprogs
jfs
jfs_tune -L "new label" /dev/XXX 使用 jfsutils
xfs
xfs_admin -L "new label" /dev/XXX 使用 xfsprogs
fat/vfat
fatlabel /dev/XXX "new label" 使用 dosfstools
mlabel -i /dev/XXX ::"new label" 使用 mtools
exfat
tune.exfat -L "new label" /dev/XXX 使用 exfatprogs
exfatlabel /dev/XXX "new label" 使用 exfatprogsexfat-utils
ntfs
ntfslabel /dev/XXX "new label" 使用 ntfs-3g
udf
udflabel /dev/XXX "new label" 使用 udftools
crypto_LUKS (LUKS2 only)
cryptsetup config --label="new label" /dev/XXX 使用 cryptsetup

可以通过 lsblk 获得设备的标签:

$ lsblk -dno LABEL /dev/sda2
Arch Linux	
注意:
  • 修改文件系统的标签时不能挂载它。对于 root 文件系统,这可以通过从另一个卷引导来完成。
  • 标签必须是唯一的,以防止可能的冲突。
  • 标签最多可以有16个字符。
  • 标签是文件系统的一个属性,所以无法持久地表示单一磁盘阵列设备。
  • 在使用 dm-crypt 的加密容器时,容器内的文件系统的标签在容器被锁定/加密时是不可用的。

通过 uuid

UUID 是一种为每个文件系统提供唯一标识符的机制。这些标识符是在设备被格式化时,通过文件系统工具生成的 (例如 mkfs.*),并且在设计上不太可能发生冲突。所有 GNU/Linux 文件系统 (包括 swap 和 LUKS headers 或 原始加密设备) 都支持 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 工具来重置它。

通过 id 和 通过路径

by-id 会依据硬件序列号创建一个唯一的名字,by-path 则取决于最短的物理路径 (根据 sysfs)。两者都包含字符串以指示它们属于哪个子系统 (例如对于 by-path 来说是 -ide-,对于 by-id 来说是 -ata-),因此它们与控制设备的硬件相关联。这意味着不同级别的持久性: by-path 会在设备插入控制器的不同端口时改变,by-id 会在设备插入受另一个子系统约束的硬件控制器的端口时改变。[1]因此,两者都不适合实现针对硬件更改的持久化命名。

然而,两者都提供了在大型硬件基础设施中查找特定设备的重要信息。举个例子,如果你没有手动分配持久性的标签 (by-labelby-partlabel) 而且保留有一个包含硬件端口使用情况的目录,by-idby-path 就可以用于找到特定的设备。[2] [3]

by-id 还会创建支持 World Wide Name 的存储设备的链接。不像其它 by-id 链接, WWN 是完全持久化而且不会因使用的子系统改变。

Tango-view-fullscreen.pngThis article or section needs expansion.Tango-view-fullscreen.png

Reason: 解释并提供关于 /dev/disk/by-id/nvme-eui.* 链接[4]的例子。NVME 设备的 WWID 是否总是以 eui. 开头? (Discuss in Talk:Persistent block device naming (简体中文))
注意: by-idby-path 链接只能被视为磁盘持久化,而不是分区。分区将通过其在分区表中的编号进行引用,并且如果对分区重新排序,该编号可能会发生变化。
$ 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 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 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

通过分区标签

注意: 此方法仅涉及具有 GUID 分区表的磁盘。

在 GPT 磁盘上,GPT 分区标签可以在分区条目的 header 中定义。

这个方法与文件系统标签很相似,但是即使分区上的文件系统发生更改,分区标签也不会受到影响。

$ 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 或 基于 ncurse 的版本 cgdisk。它们都可通过 gptfdisk 软件包获取。请见 Partitioning (简体中文)#分区工具
  • 根据规范,GPT 分区标签最多可以有 72 字符长。

通过分区 uuid

注意: 此方法仅涉及具有 GUID 分区表的磁盘。

就像 GPT 分区标签,在 GPT 磁盘上,GPT 分区 UUID 在分区条目中定义。

MBT 不支持分区 UUID,但是 Linux[5] 和软件使用 libblkid[6] (例如 udev[7]) 能够为 MBR 分区生成伪分区 UUID。其格式为 SSSSSSSS-PP,SSSSSSSS 是一个零填充的 32 位 MBR 磁盘签名,而 PP 则是一个十六进制形式的零填充分区号。和一般的 GPT 分区的分区 UUID 不同,MBR 的伪分区 UUID 会在分区改变时改变。

动态目录与其它方法相似,就像 文件系统 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


设备的分区 UUID 可以用 lsblk 获得:

$ lsblk -dno PARTUUID /dev/sda1
d0d0d110-0a71-4ed6-936a-304969ea36af


或使用 blkid:

# blkid -s PARTUUID -o value /dev/sda1
d0d0d110-0a71-4ed6-936a-304969ea36af

使用 Udev 静态设备名

参考 设置静态设备名

使用持久名称

有多种应用可以配置为使用持久名称。下面列出了一些配置的例子:

fstab

请见主文章: fstab (简体中文)#文件系统标识

内核参数

要在内核参数中使用持久化名称,需要满足下列先决条件。在遵循安装指南的标准安装中,需满足两个条件:

root 文件系统的位置在内核命令行中是通过参数 root 传递的。内核命令行是通过引导加载程序配置的,请见 内核参数#配置。要想修改为持久化设备名,只需修改用于指定块设备的参数,例如 rootresume,而其它参数则保持不变。支持多种命名方案:

在这个以 Arch Linux 为 root 文件系统标签的例子中展示了使用标签的持久化设备名 和 LABEL= 格式。

roo="LABEL=Arch Linux"

在这个以 0a3407de-014b-458b-b5c1-848e92a327a3 为 root 文件系统 UUID 的例子中展示了使用 uuid 的持久化设备名 和 UUID= 格式。

root=UUID=0a3407de-014b-458b-b5c1-848e92a327a3

在这个以 wwn-0x60015ee0000b237f-part2 为 root 分区 id 的例子中展示了使用磁盘 id 的持久化设备名 和 /dev 路径格式。

root=/dev/disk/by-id/wwn-0x60015ee0000b237f-part2

在这个以 98a81274-10f7-40db-872a-03df048df366 为 root 分区的分区 UUID 的例子中展示了使用 GPT 分区 UUID 的持久化设备名 和 PARTUUID= 格式。

root=PARTUUID=98a81274-10f7-40db-872a-03df048df366

在这个以 GNU/Linux 为 root 分区的分区标签的例子中展示了使用 GPT 分区标签的持久化设备名 和 PARTLABEL= 格式。

root="PARTLABEL=GNU/Linux"