
vinum 卷管理
目录
1. 概要
无论磁盘类型如何,总存在潜在问题。磁盘可能太小、太慢或太不可靠,无法满足系统的需求。虽然磁盘越来越大,但数据存储需求也在不断增长。通常需要一个比磁盘容量更大的文件系统。人们已经提出了各种解决方案并进行了实施。
一种方法是使用多个磁盘,有时是冗余磁盘。除了支持硬件独立磁盘冗余阵列 RAID 系统的各种卡和控制器外,FreeBSD 基础系统还包括 vinum 卷管理,这是一种块设备驱动程序,它实现虚拟磁盘驱动器并解决这三个问题。 vinum 提供比传统磁盘存储更高的灵活性和性能,并实现 RAID
-0、RAID
-1 和 RAID
-5 模型,既可以单独使用,也可以组合使用。
本章概述了传统磁盘存储中存在的潜在问题,并介绍了 vinum 卷管理。
从 FreeBSD 5 开始,vinum 已被重写以适应 GEOM 架构,同时保留了原始理念、术语和磁盘上的元数据。此重写称为 gvinum(表示 GEOM vinum)。虽然本章使用术语 vinum,但所有命令调用都应使用 |
2. 访问瓶颈
现代系统经常需要以高度并发的方式访问数据。例如,大型 FTP 或 HTTP 服务器可以维护数千个并发会话,并具有到外部世界的多个 100 Mbit/s 连接,远远超过大多数磁盘的持续传输速率。
目前的磁盘驱动器可以以高达 70 MB/s 的速率顺序传输数据,但这个值在一个环境中意义不大,在这个环境中,许多独立进程访问一个驱动器,并且它们可能只能达到这些值的几分之一。在这种情况下,从磁盘子系统的角度看待问题更有趣。重要的参数是传输对子系统施加的负载,或者传输占用参与传输的驱动器的时间。
在任何磁盘传输中,驱动器必须首先定位磁头,等待第一个扇区经过读磁头下方,然后执行传输。这些操作可以被认为是原子的,因为中断它们没有任何意义。
考虑一个典型的约 10 kB 的传输:当前一代的高性能磁盘可以在平均 3.5 毫秒内定位磁头。最快的驱动器以 15,000 rpm 的速度旋转,因此平均旋转延迟(半圈)为 2 毫秒。在 70 MB/s 时,传输本身大约需要 150 微秒,与定位时间相比几乎可以忽略不计。在这种情况下,有效传输速率下降到略高于 1 MB/s,并且显然高度依赖于传输大小。
对这个瓶颈的传统且明显的解决方案是“更多主轴”:与其使用一个大型磁盘,不如使用几个较小的磁盘,它们的总存储空间相同。每个磁盘都能够独立地定位和传输,因此有效吞吐量增加了接近使用磁盘数量的倍数。
实际的吞吐量提高比参与的磁盘数量要小。虽然每个驱动器都能够并行传输,但无法确保请求在驱动器之间均匀分布。不可避免地,一个驱动器上的负载将高于另一个驱动器上的负载。
磁盘上的负载均匀程度很大程度上取决于数据在驱动器之间的共享方式。在以下讨论中,将磁盘存储视为大量可按编号寻址的数据扇区,就像书中的页面一样。最明显的方法是将虚拟磁盘划分为等于单个物理磁盘大小的连续扇区组,并以这种方式存储它们,就像取一本大书并将其撕成更小的部分一样。这种方法称为级联,它的优点是磁盘不需要具有任何特定的尺寸关系。当对虚拟磁盘的访问均匀分布在其地址空间时,它工作良好。当访问集中在较小的区域时,改进就不那么明显了。 级联组织 说明了在级联组织中分配存储单元的顺序。

图 1. 级联组织
另一种映射方法是将地址空间划分为更小、大小相等的组件,并按顺序将它们存储在不同的设备上。例如,前 256 个扇区可以存储在第一个磁盘上,接下来的 256 个扇区存储在下一个磁盘上,以此类推。在填满最后一个磁盘后,重复该过程,直到磁盘已满。这种映射称为条带化或 RAID-0。
RAID
提供了各种形式的容错功能,虽然 RAID-0 有点误导,因为它没有提供冗余。条带化需要更多努力才能定位数据,并且它可能会导致额外的 I/O 负载,因为传输分布在多个磁盘上,但它也可以提供更稳定的磁盘负载。 条带化组织 说明了在条带化组织中分配存储单元的顺序。

图 2. 条带化组织
3. 数据完整性
磁盘的最后一个问题是它们不可靠。虽然可靠性在过去几年中大幅提高,但磁盘驱动器仍然是服务器中最有可能出现故障的核心组件。如果它们确实出现故障,结果可能很灾难性,更换故障的磁盘驱动器并恢复数据会导致服务器停机。
解决此问题的一种方法是镜像或 RAID-1
,它在不同的物理硬件上保留数据的两个副本。对卷的任何写入都会写入两个磁盘;可以从任意一个磁盘读取,因此,如果一个驱动器发生故障,数据仍然可以在另一个驱动器上获得。
镜像有两个问题
它需要的磁盘存储空间是无冗余解决方案的两倍。
写入必须执行到两个驱动器,因此它们占用的是非镜像卷的两倍带宽。读取不会受到性能损害,甚至可能更快。
另一种解决方案是奇偶校验,在 RAID
级别 2、3、4 和 5 中实现。其中,RAID-5
最有趣。如 vinum 中所实现,它是一种条带化组织的变体,它将每个条带的一个块专门用于奇偶校验另一个块。如 vinum 所实现,一个 RAID-5
plex 类似于一个条带化 plex,除了它通过在每个条带中包含一个奇偶校验块来实现 RAID-5
。根据 RAID-5
的要求,此奇偶校验块的位置从一个条带更改为下一个条带。数据块中的数字表示相对块号。

图 3.
RAID
-5 组织与镜像相比,RAID-5
的优点是需要的存储空间明显更少。读取访问类似于条带化组织,但写入访问明显更慢,约为读取性能的 25%。如果一个驱动器发生故障,阵列可以继续在降级模式下运行,其中从剩余的可访问驱动器之一读取继续正常进行,但从故障驱动器读取会根据所有剩余驱动器上的相应块重新计算。
4. vinum 对象
为了解决这些问题,vinum 实现了一个四级对象层次结构
最明显的对象是虚拟磁盘,称为卷。卷与 UNIX® 磁盘驱动器具有基本相同的属性,尽管有一些细微的差别。首先,它们没有大小限制。
卷由plex 组成,每个 plex 代表一个卷的总地址空间。层次结构中的这一级提供冗余。将 plex 视为镜像阵列中的单个磁盘,每个磁盘都包含相同的数据。
由于 vinum 存在于 UNIX® 磁盘存储框架内,因此可以将 UNIX® 分区用作多磁盘 plex 的构建块。实际上,这太不灵活了,因为 UNIX® 磁盘只能具有有限数量的分区。相反,vinum 将单个 UNIX® 分区(驱动器)细分为称为子磁盘的连续区域,这些区域用作 plex 的构建块。
子磁盘驻留在 vinum驱动器上,目前是 UNIX® 分区。 vinum 驱动器可以包含任意数量的子磁盘。除了驱动器开头用于存储配置和状态信息的小区域外,整个驱动器都可用作数据存储。
以下部分介绍了这些对象如何提供 vinum 所需的功能。
4.2. 冗余数据存储
vinum 通过将多个 plex 附加到卷来实现镜像。每个 plex 是卷中数据的表示。卷可以包含 1 到 8 个 plex。
虽然 plex 表示卷的完整数据,但表示的一部分可能在物理上缺失,无论是通过设计(通过不为 plex 的部分定义子磁盘)还是通过意外(由于驱动器故障)。只要至少有一个 plex 可以提供卷的完整地址范围的数据,该卷就完全正常工作。
4.3. 哪个 Plex 组织?
vinum 在 plex 级别的实现级联和条带化。
级联 plex 依次使用每个子磁盘的地址空间。级联 plex 最灵活,因为它们可以包含任意数量的子磁盘,并且子磁盘可以具有不同的长度。可以通过添加其他子磁盘来扩展 plex。它们需要的 CPU 时间比带状 plex 少,尽管 CPU 负担的差异不可衡量。另一方面,它们最容易受到热点的影响,其中一个磁盘非常活跃而其他磁盘处于空闲状态。
带状 plex 在每个子磁盘上对数据进行条带化。所有子磁盘必须大小相同,并且至少必须有两个子磁盘才能将其与级联 plex 区分开来。带状 plex 的最大优势是减少了热点。通过选择最佳大小的条带(约 256 kB),可以在组件驱动器上均匀分配负载。通过添加新的子磁盘来扩展 plex 非常复杂,以至于 vinum 没有实现它。
vinum Plex 组织 总结了每种 plex 组织的优缺点。
Plex 类型 | 最小子磁盘 | 可以添加子磁盘 | 必须大小相等 | 应用程序 |
---|---|---|---|---|
级联 | 1 | 是 | 否 | 具有最大放置灵活性和中等性能的大数据存储 |
条带化 | 2 | 否 | 是 | 高性能,与高并发访问相结合 |
5. 一些示例
vinum 维护一个配置数据库,该数据库描述了单个系统已知的对象。最初,用户使用 gvinum(8) 从一个或多个配置文件创建配置数据库。 vinum 在其控制下的每个磁盘设备上存储其配置数据库的副本。该数据库在每次状态更改时都会更新,以便重新启动能够准确地恢复每个 vinum 对象的状态。
5.1. 配置文件
配置文件描述了各个 vinum 对象。一个简单卷的定义可能是
drive a device /dev/da3h volume myvol plex org concat sd length 512m drive a
该文件描述了四个 vinum 对象
驱动器行描述了磁盘分区(驱动器)及其相对于底层硬件的位置。它被赋予符号名称a。符号名称与设备名称的分离允许将磁盘从一个位置移动到另一个位置,而不会造成混淆。
卷行描述了一个卷。唯一必需的属性是名称,在本例中为myvol。
plex 行定义了一个 plex。唯一必需的参数是组织,在本例中为concat。没有名称是必要的,因为系统会自动从卷名生成一个名称,方法是添加后缀.px,其中x 是卷中 plex 的编号。因此,此 plex 将被称为myvol.p0。
sd 行描述了一个子磁盘。最小规格是存储它的驱动器的名称和子磁盘的长度。没有名称是必要的,因为系统会自动分配从 plex 名称派生的名称,方法是添加后缀.sx,其中x 是 plex 中子磁盘的编号。因此,vinum 为此子磁盘赋予名称myvol.p0.s0。
处理完此文件后,gvinum(8) 将生成以下输出
# gvinum -> create config1 Configuration summary Drives: 1 (4 configured) Volumes: 1 (4 configured) Plexes: 1 (8 configured) Subdisks: 1 (16 configured) D a State: up Device /dev/da3h Avail: 2061/2573 MB (80%) V myvol State: up Plexes: 1 Size: 512 MB P myvol.p0 C State: up Subdisks: 1 Size: 512 MB S myvol.p0.s0 State: up PO: 0 B Size: 512 MB
此输出显示了 gvinum(8) 的简要列表格式。它在 一个简单的 vinum 卷 中以图形方式表示。

图 4. 一个简单的 vinum 卷
此图以及后面的图表示一个卷,其中包含 plex,而 plex 又包含子磁盘。在本例中,该卷包含一个 plex,而 plex 包含一个子磁盘。
此特定卷与传统的磁盘分区没有特定优势。它包含单个 plex,因此它不是冗余的。该 plex 包含单个子磁盘,因此存储分配与传统的磁盘分区没有区别。以下部分将说明各种更有趣的配置方法。
5.2. 提高弹性:镜像
可以通过镜像来提高卷的弹性。在布局镜像卷时,务必确保每个 plex 的子磁盘位于不同的驱动器上,以便驱动器故障不会使两个 plex 都停止工作。以下配置镜像了一个卷
drive b device /dev/da4h volume mirror plex org concat sd length 512m drive a plex org concat sd length 512m drive b
在本例中,不需要再次指定驱动器a 的定义,因为 vinum 会跟踪其配置数据库中的所有对象。处理完此定义后,配置将如下所示
Drives: 2 (4 configured) Volumes: 2 (4 configured) Plexes: 3 (8 configured) Subdisks: 3 (16 configured) D a State: up Device /dev/da3h Avail: 1549/2573 MB (60%) D b State: up Device /dev/da4h Avail: 2061/2573 MB (80%) V myvol State: up Plexes: 1 Size: 512 MB V mirror State: up Plexes: 2 Size: 512 MB P myvol.p0 C State: up Subdisks: 1 Size: 512 MB P mirror.p0 C State: up Subdisks: 1 Size: 512 MB P mirror.p1 C State: initializing Subdisks: 1 Size: 512 MB S myvol.p0.s0 State: up PO: 0 B Size: 512 MB S mirror.p0.s0 State: up PO: 0 B Size: 512 MB S mirror.p1.s0 State: empty PO: 0 B Size: 512 MB
一个镜像的 vinum 卷 显示了该结构的图形表示。

图 5. 一个镜像的 vinum 卷
在本例中,每个 plex 包含完整的 512 MB 地址空间。与前面的示例一样,每个 plex 只包含一个子磁盘。
5.3. 优化性能
前面的示例中的镜像卷比非镜像卷更能抵抗故障,但它的性能较低,因为对卷的每次写入都需要对两个驱动器进行写入,从而占用更大的总磁盘带宽比例。性能考虑需要采用不同的方法:不是镜像,而是将数据条带化到尽可能多的磁盘驱动器上。以下配置显示了一个在四个磁盘驱动器上进行条带化的 plex 卷
drive c device /dev/da5h drive d device /dev/da6h volume stripe plex org striped 512k sd length 128m drive a sd length 128m drive b sd length 128m drive c sd length 128m drive d
与之前一样,不需要定义 vinum 已经知道的驱动器。处理完此定义后,配置将如下所示
Drives: 4 (4 configured) Volumes: 3 (4 configured) Plexes: 4 (8 configured) Subdisks: 7 (16 configured) D a State: up Device /dev/da3h Avail: 1421/2573 MB (55%) D b State: up Device /dev/da4h Avail: 1933/2573 MB (75%) D c State: up Device /dev/da5h Avail: 2445/2573 MB (95%) D d State: up Device /dev/da6h Avail: 2445/2573 MB (95%) V myvol State: up Plexes: 1 Size: 512 MB V mirror State: up Plexes: 2 Size: 512 MB V striped State: up Plexes: 1 Size: 512 MB P myvol.p0 C State: up Subdisks: 1 Size: 512 MB P mirror.p0 C State: up Subdisks: 1 Size: 512 MB P mirror.p1 C State: initializing Subdisks: 1 Size: 512 MB P striped.p1 State: up Subdisks: 1 Size: 512 MB S myvol.p0.s0 State: up PO: 0 B Size: 512 MB S mirror.p0.s0 State: up PO: 0 B Size: 512 MB S mirror.p1.s0 State: empty PO: 0 B Size: 512 MB S striped.p0.s0 State: up PO: 0 B Size: 128 MB S striped.p0.s1 State: up PO: 512 kB Size: 128 MB S striped.p0.s2 State: up PO: 1024 kB Size: 128 MB S striped.p0.s3 State: up PO: 1536 kB Size: 128 MB

图 6. 一个带状 vinum 卷
此卷在 一个带状 vinum 卷 中表示。条带的深浅表示 plex 地址空间中的位置,最浅的条带排在最前面,最深的条带排在最后。
5.4. 弹性和性能
volume raid10 plex org striped 512k sd length 102480k drive a sd length 102480k drive b sd length 102480k drive c sd length 102480k drive d sd length 102480k drive e plex org striped 512k sd length 102480k drive c sd length 102480k drive d sd length 102480k drive e sd length 102480k drive a sd length 102480k drive b
第二个 plex 的子磁盘比第一个 plex 的子磁盘偏移了两个驱动器。这有助于确保即使传输经过两个驱动器,写入也不会进入相同的子磁盘。
一个镜像的 表示了此卷的结构。

图 7. 一个镜像的、带状的 vinum 卷
6. 对象命名
vinum 为 plex 和子磁盘分配默认名称,尽管它们可以被覆盖。覆盖默认名称不建议,因为它不会带来显著的优势,而且会导致混淆。
名称可以包含任何非空白字符,但建议将其限制为字母、数字和下划线字符。卷、plex 和子磁盘的名称最长可达 64 个字符,驱动器的名称最长可达 32 个字符。
vinum 对象在层次结构 /dev/gvinum 中分配设备节点。上面的配置将导致 vinum 创建以下设备节点
每个卷的设备条目。这些是 vinum 使用的主要设备。上面的配置将包括设备 /dev/gvinum/myvol、/dev/gvinum/mirror、/dev/gvinum/striped、/dev/gvinum/raid5 和 /dev/gvinum/raid10。
所有卷都直接在 /dev/gvinum/ 下获得条目。
目录 /dev/gvinum/plex 和 /dev/gvinum/sd 分别包含每个 plex 和每个子磁盘的设备节点。
例如,考虑以下配置文件
drive drive1 device /dev/sd1h drive drive2 device /dev/sd2h drive drive3 device /dev/sd3h drive drive4 device /dev/sd4h volume s64 setupstate plex org striped 64k sd length 100m drive drive1 sd length 100m drive drive2 sd length 100m drive drive3 sd length 100m drive drive4
处理完此文件后,gvinum(8) 在 /dev/gvinum 中创建以下结构
drwxr-xr-x 2 root wheel 512 Apr 13 16:46 plex crwxr-xr-- 1 root wheel 91, 2 Apr 13 16:46 s64 drwxr-xr-x 2 root wheel 512 Apr 13 16:46 sd /dev/vinum/plex: total 0 crwxr-xr-- 1 root wheel 25, 0x10000002 Apr 13 16:46 s64.p0 /dev/vinum/sd: total 0 crwxr-xr-- 1 root wheel 91, 0x20000002 Apr 13 16:46 s64.p0.s0 crwxr-xr-- 1 root wheel 91, 0x20100002 Apr 13 16:46 s64.p0.s1 crwxr-xr-- 1 root wheel 91, 0x20200002 Apr 13 16:46 s64.p0.s2 crwxr-xr-- 1 root wheel 91, 0x20300002 Apr 13 16:46 s64.p0.s3
虽然建议不要为 plex 和子磁盘分配特定名称,但必须命名 vinum 驱动器。这使得将驱动器移动到不同的位置,并仍然能够自动识别它成为可能。驱动器名称最长可达 32 个字符。
6.1. 创建文件系统
卷对系统而言与磁盘相同,只有一个例外。与 UNIX® 驱动器不同,vinum 不会对卷进行分区,因此卷不包含分区表。这要求修改某些磁盘实用程序,特别是 newfs(8),以便它不会尝试将 vinum 卷名的最后一个字母解释为分区标识符。例如,磁盘驱动器可能具有 /dev/ad0a 或 /dev/da2h 这样的名称。这些名称分别表示第一个 (0) IDE 磁盘 (ad) 上的第一个分区 (a) 以及第三个 (2) SCSI 磁盘 (da) 上的第八个分区 (h)。相比之下,vinum 卷可能被称为 /dev/gvinum/concat,它与分区名称没有关系。
要在此卷上创建文件系统,请使用 newfs(8)
# newfs /dev/gvinum/concat
7. 配置 vinum
GENERIC 内核不包含 vinum。可以构建一个包含 vinum 的自定义内核,但不建议这样做。启动 vinum 的标准方法是作为内核模块。不需要 kldload(8),因为当 gvinum(8) 启动时,它会检查模块是否已加载,如果未加载,它会自动加载该模块。
7.1. 启动
vinum 将配置信息存储在磁盘切片上,其形式与配置文件中的形式基本相同。从配置数据库读取时,vinum 会识别出一些在配置文件中不允许使用的关键字。例如,磁盘配置可能包含以下文本
volume myvol state up volume bigraid state down plex name myvol.p0 state up org concat vol myvol plex name myvol.p1 state up org concat vol myvol plex name myvol.p2 state init org striped 512b vol myvol plex name bigraid.p0 state initializing org raid5 512b vol bigraid sd name myvol.p0.s0 drive a plex myvol.p0 state up len 1048576b driveoffset 265b plexoffset 0b sd name myvol.p0.s1 drive b plex myvol.p0 state up len 1048576b driveoffset 265b plexoffset 1048576b sd name myvol.p1.s0 drive c plex myvol.p1 state up len 1048576b driveoffset 265b plexoffset 0b sd name myvol.p1.s1 drive d plex myvol.p1 state up len 1048576b driveoffset 265b plexoffset 1048576b sd name myvol.p2.s0 drive a plex myvol.p2 state init len 524288b driveoffset 1048841b plexoffset 0b sd name myvol.p2.s1 drive b plex myvol.p2 state init len 524288b driveoffset 1048841b plexoffset 524288b sd name myvol.p2.s2 drive c plex myvol.p2 state init len 524288b driveoffset 1048841b plexoffset 1048576b sd name myvol.p2.s3 drive d plex myvol.p2 state init len 524288b driveoffset 1048841b plexoffset 1572864b sd name bigraid.p0.s0 drive a plex bigraid.p0 state initializing len 4194304b driveoff set 1573129b plexoffset 0b sd name bigraid.p0.s1 drive b plex bigraid.p0 state initializing len 4194304b driveoff set 1573129b plexoffset 4194304b sd name bigraid.p0.s2 drive c plex bigraid.p0 state initializing len 4194304b driveoff set 1573129b plexoffset 8388608b sd name bigraid.p0.s3 drive d plex bigraid.p0 state initializing len 4194304b driveoff set 1573129b plexoffset 12582912b sd name bigraid.p0.s4 drive e plex bigraid.p0 state initializing len 4194304b driveoff set 1573129b plexoffset 16777216b
这里明显的区别在于显式位置信息和命名的存在,这两种信息都是允许的,但并不鼓励使用,以及关于状态的信息。 vinum 不会在配置信息中存储有关驱动器的信息。它通过扫描已配置的磁盘驱动器来查找带有 vinum 标签的分区来找到驱动器。这使得 vinum 能够正确识别驱动器,即使它们被分配了不同的 UNIX® 驱动器 ID。
7.1.1. 自动启动
Gvinum 一旦内核模块加载,就会通过 loader.conf(5) 自动启动。要让 Gvinum 模块在启动时加载,请在 /boot/loader.conf 中添加 geom_vinum_load="YES"
。
当 vinum 通过 gvinum start
启动时,vinum 会从某个 vinum 驱动器中读取配置数据库。在正常情况下,每个驱动器都包含配置数据库的相同副本,因此读取哪个驱动器并不重要。然而,在发生崩溃后,vinum 必须确定哪个驱动器最近更新,并从该驱动器中读取配置。然后,它会根据需要从旧的驱动器中更新配置。
8. 使用 vinum 作为根文件系统
对于使用 vinum 完整镜像文件系统的机器来说,镜像根文件系统也是很理想的。设置这种配置比镜像任意文件系统要复杂,因为
根文件系统必须在引导过程的早期可用,因此 vinum 基础设施必须在此之前可用。
包含根文件系统的卷还包含系统引导程序和内核。这些必须使用主机系统的本地实用程序(如 BIOS)读取,这些实用程序通常无法学习 vinum 的详细信息。
在以下部分中,术语“根卷”通常用于描述包含根文件系统的 vinum 卷。
8.1. 在根文件系统可用之前启动 vinum
vinum 必须在系统启动的早期可用,因为 loader(8) 必须能够在启动内核之前加载 vinum 内核模块。这可以通过在 /boot/loader.conf 中添加以下行来实现
geom_vinum_load="YES"
8.2. 使基于 vinum 的根卷可供引导程序访问
当前的 FreeBSD 引导程序只有 7.5 KB 的代码,它不理解内部的 vinum 结构。这意味着它无法解析 vinum 配置数据或找出引导卷的元素。因此,需要一些变通方法来为引导代码提供标准 a
分区的错觉,该分区包含根文件系统。
为了使这成为可能,根卷必须满足以下要求
根卷不能是条带或
RAID
-5。根卷每个复本中不能包含多个串联子磁盘。
请注意,使用多个复本是可取的,也是可能的,每个复本包含根文件系统的副本。引导过程将只使用一个副本来查找引导程序和所有引导文件,直到内核挂载根文件系统。这些复本中的每个子磁盘都需要自己的 a
分区错觉,才能使相应的设备可引导。这些模拟的 a
分区是否位于其设备中的相同偏移量(与包含根卷复本的其他设备相比)并不严格要求。但是,以这种方式创建 vinum 卷可能是件好事,这样生成的镜像设备将是对称的,以避免混淆。
要为包含根卷一部分的每个设备设置这些 a
分区,需要以下操作
需要使用以下命令检查此设备的子磁盘(它是根卷的一部分)的位置、相对于设备开头的偏移量和大小
# gvinum l -rv root
vinum 的偏移量和大小以字节为单位。它们必须除以 512 以获得
bsdlabel
将使用的块号。对参与根卷的每个设备运行此命令
# bsdlabel -e devname
devname 必须是磁盘的名称,例如没有切片表磁盘的 da0,或切片的名称,例如 ad0s1。
如果设备上已经存在来自引导 vinum 根文件系统的
a
分区,则应将其重命名为其他名称,以便它仍然可访问(以防万一),但默认情况下不再用于引导系统。当前已挂载的根文件系统无法重命名,因此必须在从“Fixit”媒体引导时执行此操作,或者在两步过程中执行,在两步过程中,首先操作当前未引导的镜像中的磁盘。必须将此设备上 vinum 分区的偏移量(如果有)添加到此设备上相应根卷子磁盘的偏移量。结果值将成为新
a
分区的offset
值。此分区的size
值可以从上面的计算中直接获得。fstype
应该为4.2BSD
。fsize
、bsize
和cpg
值应选择与实际文件系统匹配,尽管它们在这个环境中并不重要。这样,将建立一个新的
a
分区,它与此设备上的 vinum 分区重叠。只有当 vinum 分区已使用vinum
fstype 正确标记时,bsdlabel
才允许这种重叠。现在,在每个包含根卷副本的设备上都存在一个模拟的
a
分区。强烈建议使用类似以下命令来验证结果# fsck -n /dev/devnamea
应该记住,所有包含控制信息的都必须相对于 vinum 卷中的根文件系统,在设置新的 vinum 根卷时,这可能与当前活动的根文件系统不匹配。因此,特别是 /etc/fstab 和 /boot/loader.conf 需要处理。
在下次重启时,引导程序应该从新的基于 vinum 的根文件系统中找出适当的控制信息,并相应地执行操作。在内核初始化过程结束时,在所有设备都已宣布后,显示此设置成功的主要通知将类似以下消息
Mounting root from ufs:/dev/gvinum/root
8.3. 基于 vinum 的根设置示例
在设置完 vinum 根卷后,gvinum l -rv root
的输出可能如下所示
...
Subdisk root.p0.s0:
Size: 125829120 bytes (120 MB)
State: up
Plex root.p0 at offset 0 (0 B)
Drive disk0 (/dev/da0h) at offset 135680 (132 kB)
Subdisk root.p1.s0:
Size: 125829120 bytes (120 MB)
State: up
Plex root.p1 at offset 0 (0 B)
Drive disk1 (/dev/da1h) at offset 135680 (132 kB)
需要注意的值是相对于分区 /dev/da0h 的偏移量 135680
。这在 `bsdlabel’ 术语中转换为 265 个 512 字节的磁盘块。同样,这个根卷的大小为 245760 个 512 字节的块。包含此根卷第二个副本的 /dev/da1h 具有对称的设置。
这些设备的 bsdlabel 可能如下所示
...
8 partitions:
# size offset fstype [fsize bsize bps/cpg]
a: 245760 281 4.2BSD 2048 16384 0 # (Cyl. 0*- 15*)
c: 71771688 0 unused 0 0 # (Cyl. 0 - 4467*)
h: 71771672 16 vinum # (Cyl. 0*- 4467*)
可以观察到,模拟的 a
分区的 size
参数与上面概述的值匹配,而 offset
参数是 vinum 分区 h
内的偏移量与该分区在设备或切片内的偏移量的总和。这是避免 无法引导 中描述的问题所需的典型设置。整个 a
分区完全位于包含此设备所有 vinum 数据的 h
分区内。
在上面的示例中,整个设备专门用于 vinum,并且没有剩余的引导 vinum 根分区。
8.4. 故障排除
以下列表包含一些已知的陷阱和解决方案。
8.4.1. 系统引导程序加载,但系统未引导
如果由于任何原因系统无法继续引导,则可以通过在 10 秒警告时按 space 来中断引导程序。可以通过键入 show
来检查加载程序变量 vinum.autostart
,并使用 set
或 unset
来操作它。
如果 vinum 内核模块尚未包含在要自动加载的模块列表中,请键入 load geom_vinum
。
准备好后,可以通过键入 boot -as
来继续引导过程,其中 -as
请求内核询问要挂载的根文件系统 (-a
) 并使引导过程在单用户模式下停止 (-s
),在此模式下,根文件系统以只读方式挂载。这样,即使只挂载了多复本卷的其中一个复本,也不会冒复本之间数据不一致的风险。
在提示输入要挂载的根文件系统时,可以输入包含有效根文件系统的任何设备。如果 /etc/fstab 设置正确,默认应该类似于 ufs:/dev/gvinum/root
。一个典型的备选选择可能是类似于 ufs:da0d
的内容,它可能是一个包含引导 vinum 根文件系统的假设分区。如果在此处输入了别名 a
分区之一,则应注意它实际上引用了 vinum 根设备的子磁盘,因为在镜像设置中,这只会挂载镜像根设备的一部分。如果此文件系统要稍后以读写方式挂载,则必须删除 vinum 根卷的其他复本,因为否则这些复本将包含不一致的数据。
8.4.2. 只有主引导程序加载
如果 /boot/loader 无法加载,但主引导程序仍然加载(在引导过程启动后,屏幕左侧栏中仅出现一个破折号),可以尝试通过按 space 来中断主引导程序。这将使引导程序在 第二阶段 停止。可以尝试从备用分区引导,例如包含先前已从 a
移动的根文件系统的分区。
8.4.3. 无法引导,引导程序出现恐慌
如果引导程序被 vinum 安装破坏,就会出现这种情况。不幸的是,vinum 意外地在开始写入其 vinum 头部信息之前,只在分区的开头留下了 4 KB 的空间。但是,第一阶段和第二阶段的引导程序加上 bsdlabel 需要 8 KB。因此,如果 vinum 分区从打算引导的切片或磁盘内的偏移量 0 开始,则 vinum 设置将破坏引导程序。
类似地,如果上述情况已恢复,通过从“Fixit”媒体启动,并使用第二阶段中描述的bsdlabel -B
重新安装引导程序,引导程序将破坏vinum头,而vinum将不再能找到其磁盘。虽然不会实际破坏任何vinum配置数据或vinum卷中的数据,并且可以通过再次输入完全相同的vinum配置数据来恢复所有数据,但这种情况很难修复。有必要将整个vinum分区至少移动 4 KB,以使vinum头和系统引导程序不再冲突。
最后修改时间:2024 年 8 月 11 日,作者 Fernando Apesteguía