# 21.7.为磁盘设备添加卷标

在系统初始化期间，FreeBSD 内核会随着设备的发现而创建设备节点。这种设备探测方法会引发一些问题。例如，如果通过 USB 添加了一个新的磁盘设备，可能会导致一个闪存设备被分配为 **da0**，而原来的 **da0** 被重新分配为 **da1**。如果文件系统已经列在 **/etc/fstab** 中，这将导致挂载问题，甚至可能会阻止系统启动。

一种解决方案是按顺序链接 SCSI 设备，这样添加到 SCSI 卡上的新设备将被分配未使用的设备号。但对于可能替代主 SCSI 磁盘的 USB 设备呢？这种情况发生是因为 USB 设备通常在 SCSI 卡之前进行探测。一个解决办法是仅在系统启动后插入这些设备。另一种方法是仅使用一个 ATA 硬盘，并且永远不要在 **/etc/fstab** 中列出 SCSI 设备。

一个更好的解决方案是使用 `glabel` 为磁盘设备打标签，并在 **/etc/fstab** 中使用标签。由于 `glabel` 将标签存储在给定提供者的最后一个扇区中，因此标签在重启后会保持持久。通过使用此标签作为设备，可以确保无论通过哪个设备节点访问，文件系统始终可以挂载。

> **注意**
>
> `glabel` 可以创建临时和永久标签。只有永久标签在重启后是一致的。有关标签之间差异的更多信息，请参阅 [glabel(8)](https://man.freebsd.org/cgi/man.cgi?query=glabel\&sektion=8\&format=html)。

## 21.7.1. 标签类型与示例

永久标签可以是通用标签或文件系统标签。永久文件系统标签可以使用 [tunefs(8)](https://man.freebsd.org/cgi/man.cgi?query=tunefs\&sektion=8\&format=html) 或 [newfs(8)](https://man.freebsd.org/cgi/man.cgi?query=newfs\&sektion=8\&format=html) 创建。这些类型的标签会在 **/dev** 的子目录中创建，并根据文件系统类型命名。例如，UFS2 文件系统标签将在 **/dev/ufs** 中创建。通用永久标签可以使用 `glabel label` 创建。这些标签不特定于文件系统，会在 **/dev/label** 中创建。

临时标签会在下次重启时销毁。这些标签创建在 **/dev/label** 中，适合实验用途。可以使用 `glabel create` 创建临时标签。

要为 UFS2 文件系统创建永久标签而不销毁任何数据，请执行以下命令：

```sh
# tunefs -L home /dev/da3
```

此时应在 **/dev/ufs** 中创建一个标签，可以将其添加到 **/etc/fstab** 中：

```sh
/dev/ufs/home		/home            ufs     rw              2      2
```

> **注意**
>
> 在运行 `tunefs` 时，文件系统不能被挂载。

现在，可以挂载该文件系统：

```sh
# mount /home
```

从此以后，只要 **geom\_label.ko** 内核模块在启动时加载（通过 **/boot/loader.conf** 或启用 `GEOM_LABEL` 内核选项），设备节点的变化不会对系统产生不良影响。

文件系统也可以通过在创建文件系统时使用 `newfs` 命令的 `-L` 选项来创建默认标签。有关更多信息，请参阅 [newfs(8)](https://man.freebsd.org/cgi/man.cgi?query=newfs\&sektion=8\&format=html)。

以下命令可以用于销毁标签：

```sh
# glabel destroy home
```

以下示例展示了如何标记引导磁盘的分区。

**示例 1. 标记引导磁盘上的分区**

通过永久标记引导磁盘上的分区，即使磁盘被移动到其他控制器或转移到不同的系统，系统仍应能够继续正常启动。此示例假设使用的是单个 ATA 硬盘，并且该硬盘目前被系统识别为 **ad0**。还假设使用的是标准 FreeBSD 分区方案，其中包括 **/**、**/var**、**/usr** 和 **/tmp**，以及一个交换分区。

重启系统，在 [loader(8)](https://man.freebsd.org/cgi/man.cgi?query=loader\&sektion=8\&format=html) 提示符下，按 4 进入单用户模式。然后输入以下命令：

```sh
# glabel label rootfs /dev/ad0s1a
GEOM_LABEL: Label for provider /dev/ad0s1a is label/rootfs
# glabel label var /dev/ad0s1d
GEOM_LABEL: Label for provider /dev/ad0s1d is label/var
# glabel label usr /dev/ad0s1f
GEOM_LABEL: Label for provider /dev/ad0s1f is label/usr
# glabel label tmp /dev/ad0s1e
GEOM_LABEL: Label for provider /dev/ad0s1e is label/tmp
# glabel label swap /dev/ad0s1b
GEOM_LABEL: Label for provider /dev/ad0s1b is label/swap
# exit
```

系统将继续进入多用户模式启动。启动完成后，编辑 **/etc/fstab**，将常规设备名称替换为其各自的标签。最终的 **/etc/fstab** 文件将如下所示：

```sh
# Device                Mountpoint      FStype  Options         Dump    Pass#
/dev/label/swap         none            swap    sw              0       0
/dev/label/rootfs       /               ufs     rw              1       1
/dev/label/tmp          /tmp            ufs     rw              2       2
/dev/label/usr          /usr            ufs     rw              2       2
/dev/label/var          /var            ufs     rw              2       2
```

现在可以重新启动系统。如果一切顺利，系统将正常启动，`mount` 命令将显示：

```sh
# mount
/dev/label/rootfs on / (ufs, local)
devfs on /dev (devfs, local)
/dev/label/tmp on /tmp (ufs, local, soft-updates)
/dev/label/usr on /usr (ufs, local, soft-updates)
/dev/label/var on /var (ufs, local, soft-updates)
```

[glabel(8)](https://man.freebsd.org/cgi/man.cgi?query=glabel\&sektion=8\&format=html) 类支持基于文件系统唯一标识符（`ufsid`）的 UFS 文件系统标签。这些标签可以在 **/dev/ufsid** 中找到，并在系统启动时自动创建。可以使用 `ufsid` 标签通过 **/etc/fstab** 挂载分区。使用 `glabel status` 获取文件系统及其对应的 `ufsid` 标签列表：

```sh
% glabel status
                  Name  Status  Components
ufsid/486b6fc38d330916     N/A  ad4s1d
ufsid/486b6fc16926168e     N/A  ad4s1f
```

在上述示例中，**ad4s1d** 代表 **/var**，而 **ad4s1f** 代表 **/usr**。使用显示的 `ufsid` 值，可以使用以下条目在 **/etc/fstab** 中挂载这些分区：

```sh
/dev/ufsid/486b6fc38d330916        /var        ufs        rw        2      2
/dev/ufsid/486b6fc16926168e        /usr        ufs        rw        2      2
```

所有带有 `ufsid` 标签的分区都可以以这种方式挂载，从而消除了手动创建永久标签的需要，同时仍享受设备名称独立挂载的好处。
