19.9 使用 Vinum 作为根文件系统

  如果文件系统使用完全镜像的 Vinum 配置, 有时也会希望根文件系统也作了镜像。 这种配置要比镜像其它文件系统麻烦一些, 因为:

  下面几节中, 术语 “根卷” 标识包含根文件系统的 Vinum 卷。 把这个卷命名为 "root" 可能是个不错的主意, 不过从技术上说, 并不严格地要求这样做。 不过, 接下来的命令例子都使用这个名字。

19.9.1 及早启动 Vinum 以适应对根文件系统的要求

  有许多关于它的尺度:

19.9.2 让基于 Vinum 的卷在引导时可以访问

  因为目前的 FreeBSD 引导程序只有 7.5 KB 的代码, 并且已经承担了从 UFS 文件系统中读取文件 (例如 /boot/loader) 的重任, 因此完全没有办法再让它去分析 Vinum 配置数据中的 Vinum 结构, 并找到引导卷本身的信息。 因此, 需要一些技巧来为引导代码提供标准的 "a" 分区, 而它则包含了根文件系统。

  要让这些得以实现, 根卷需要满足下面的条件:

  需要说明的是, 使用多个 plex, 每个 plex 都复制一份根文件系统的副本, 是需要而且是可行的。 然而, 引导过程只能使用这些副本中的一个来引导系统, 直到内核最终自行挂接根文件系统为止。 这些 plex 中的每个子盘, 在这之后会有它们自己的 "a" 分区, 以表达每一个可以引导的设备。 每一个 "a" 分区, 尽管并不需要和其它包含根卷的 plex 处于各自驱动器的同一位置。 但是, 这样创建 Vinum 卷使得镜像卷相互对称, 从而能够避免了混淆。

  为了创建每一个根卷的 "a" 分区, 需要完成下面的操作:

  1. 使用下面的命令来了解根卷成员子盘的位置 (从设备开始的偏移量) 和尺寸:

    # gvinum l -rv root
    

    需要注意的是, Vinum 偏移量和尺寸的单位是字节。 它们必须是 512 的整数倍, 才能得到 bsdlabel 命令所需的块号。

  2. 在每一个根卷成员设备上, 执行命令:

    # bsdlabel -e devname
    

    这其中, 对于没有 slice (也就是 fdisk) 表的磁盘, devname 必须是磁盘的名字 (例如 da0), 或者是 slice 的名字 (例如 ad0s1)。

    如果设备上已经有了 "a" 分区 (比如说, 包含 Vinum 之前的根文件系统), 则应改为其它的名字, 以便继续访问 (如果需要的话), 但它并不会继续用于启动系统。 注意, 活动的分区 (类似正挂接的根文件系统) 不能被改名, 因此, 要完成这项工作, 必须从 “Fixit” 盘启动, 或者分两步操作, 并 (在镜像情形中) 首先操作那些非引导盘。

    然后, 设备上 Vinum 分区的偏移 (如果有的话) 必须加到这个设备上根卷对应的子盘上。 其结果值, 将成为新的 "a" 分区的 "offset" 值。 这个分区的 "size" 值, 可以根据前面的配置计算得出。 "fstype" 应该是 4.2BSD"fsize""bsize", 以及 "cpg" 值, 则应与文件系统的实际情况匹配, 尽管在配置 Vinum 时并不重要。

    这样, 新的 "a" 分区, 将创建并覆盖这一设备上的 Vinum 分区的范围。 注意, bsdlabel 只有在 Vinum 分区的 fstype 被标记为 "vinum" 时, 才允许这样做。

  3. 这就成了! 所有的 "a" 分区现在都已存在, 而且是根卷的一份副本。 强烈建议您再次验证其结果, 方法是:

    # fsck -n /dev/devnamea
    

  务必注意, 所有包含控制信息的文件, 都必须放到 Vinum 卷上的根文件系统。 在启动新的 Vinum 根卷时, 它们可能和实际在用的根文件系统不匹配。 因此, /etc/fstab/boot/loader.conf 这两个文件需要特别地注意。

  在下次重启时, 引导程序需要从新的基于 Vinum 的根文件系统中获取适当的控制信息, 并据此工作。 在内核初始化过程的结尾部分, 在所有的设备都被宣示之后, 如果显示了下面的信息, 则表示配置成功:

Mounting root from ufs:/dev/gvinum/root

19.9.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)
   

  需要注意的值是 135680, 也就是偏移量 (相对于 /dev/da0h 分区)。 这相当于 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", 以及设备中这一分区 (或 slice) 的偏移量之和。 这是一种典型的配置, 它能够避免在 第 19.9.4.3 节 中介绍的问题。 此外, 我们也看到整个 "a" 分区完全处于设备上包含了 Vinum 数据的 "h" 分区之中。

  注意, 在上面的配置中, 整个设备都是 Vinum 专用的, 而且没有留下 Vinum 之前的根分区, 因为它永久性地成为了新建的 Vinum 配置中的一个子盘。

19.9.4 故障排除

  如果遇到了问题, 则需要从中恢复的办法。 下面列出了一些常见的缺陷, 及其解决方法。

19.9.4.1 系统的引导程序加载了, 但无法启动

  如果由于某种原因系统不再继续启动, 引导程序可以在 10-秒 倒计时的时候, 按 space 键来停止。 加载器变量 (例如 vinum.autostart) 可以通过使用 show 命令来查看, 并使用 setunset 命令来设置。

  如果遇到的问题是由于 Vinum 的内核模块没有列入预加载的列表, 而没有正确加载, 则简单使用 load geom_vinum 会有所帮助。

  此后, 可以使用 boot -as 来继续启动过程。 选项 -as 会要求内核询问所挂接的根文件系统 (-a), 并使引导过程在单用户模式停止 (-s), 此时根文件系统是以只读方式挂接的。 这样, 即使只挂接了多 plex 卷中的一个 plex, 也不会引致 plex 之间数据不一致的问题。

  当提示输入要挂接的根文件系统时, 可以输入任何一个包含根文件系统的设备。 如果正确地配置了 /etc/fstab, 则默认的应该是类似 ufs:/dev/gvinum/root。 一般可以使用类似 ufs:da0d 这样的设备来代替它, 因为它通常包括了 Vinum 之前的根文件系统。 需要注意的是, 如果在这里输入了 "a" 分区, 则它可能表达的实际上是 Vinum 根设备的一个子盘, 而在镜像式配置中, 这只会挂接镜像的根设备中的一个。 如果之后将这个文件系统以读写方式挂接, 则需要从 Vinum 根卷中删去其他的 plex, 否则这些卷中可能会包含不一致的数据。

19.9.4.2 只加载了主引导程序

  如果 /boot/loader 加载失败, 而主引导程序加载正常 (在启动时, 屏幕最左边一列有一个旋转的线), 则可以尝试在此时中断主引导程序的过程, 方法是按 space 键。 这将在引导的第二阶段暂停, 具体可以参见 第 12.3.2 节。 此时, 可以尝试从另一个分区, 例如原先包含根文件系统, 并不再叫作 "a" 的那个分区, 启动。

19.9.4.3 无法启动, 引导程序发生 panic

  这种情况一般是由于 Vinum 安装过程中破坏了引导程序造成的。 不幸的是, Vinum 目前只在分区开始的地方保留了 4 KB 的空间, 之后就开始写 Vinum 头信息了。 然而, 目前第一阶段和第二阶段的引导程序, 加上 bsdlabel 嵌入的内容则需要 8 KB。 因此, 如果 Vinum 分区从偏移量 0 开始, 而这个 slice 或磁盘能够启动, 则 Vinum 的安装将毁掉引导程序。

  类似地, 如果从上述情形中恢复, 例如, 从 “Fixit” 盘启动, 并通过 bsdlabel -B 按照 第 12.3.2 节 中介绍的方法来恢复引导程序, 则引导程序会覆盖掉 Vinum 头, 这样 Vinum 也就找不到它的磁盘了。 尽管这并不会真的毁掉 Vinum 的配置数据, 或者 Vinum 卷上的数据, 并且可以通过输入一模一样的 Vinum 配置数据来恢复, 但从这种状况中完全恢复是非常困难的。 要真正解决问题, 必须将整个 Vinum 分区向后移动至少 4 KB, 以便使 Vinum 头和系统的引导程序不再冲突。

19.9.5 与 FreeBSD 4.X 的区别

  在 FreeBSD 4.X 中, 由于缺少那些让 Vinum 自动扫描所有磁盘所需的内部函数, 而检测根设备的内部 ID 的代码不够智能, 以至于无法自动处理类似 /dev/vinum/root 这样的名字。 因此, 会有一些小差异。

  必须明确地告诉 Vinum 要扫描哪些磁盘, 方法是在 /boot/loader.conf 中加入:

vinum.drives="/dev/da0 /dev/da1"

  所有可能包含 Vinum 数据的盘在这里都应提及。 基本原则是, 宁多毋缺。 此外, 也无需明确指定 slice 或分区, 因为 Vinum 在指定的驱动器上的所有 slice 和分区上扫描 Vinum 头。

  由于用以分析根文件系统名字, 并产生设备 ID (major/minor 编号) 的程序, 只能够处理 “传统的” 类似 /dev/ad0s1a 这样的设备名, 因此它们不可能处理类似 /dev/vinum/root 这样的根卷名。 因此, Vinum 本身需要预先配置内核的一些内部参数, 以便在初始化时能够保持根设备的 ID。 这可以通过加载器变量 vinum.root 来配置, 对应的 /boot/loader.conf 设置是:

vinum.root="root"

  现在, 当内核初始化过程尝试找到要挂接的 root 设备时, 它将能看到是否已经有某个内核模块预先初始化了所需要的内核参数。 这种情况下, 并且 所指定的根设备和来自加载器的根设备 (也就是我们的 "vinum" ) 的 major 编号相符, 则就是用预先分配的设备 ID, 而不是自己去找一个。 这样, 在通常的自动启动过程中, 它就能够继续挂接 Vinum 根卷来作为根文件系统了。

  但是, 当指定了 boot -a 来要求在启动时手工选择根设备时, 仍然是无法自动地分析 Vinum 卷名的。 如果输入的设备名与 Vinum 设备不匹配, 则 major 编号的不匹配会使这个过程采用普通的分析过程, 这样, 输入 ufs:da0d 就能够正常工作了。 注意, 一旦这个过程失败, 则再输入 ufs:vinum/root 将不能正常工作, 因为它无法再被解析了。 唯一的解决办法是, 重新启动并从头开始 (在 “askroot” 提示处, 可以省略 /dev/。)

本文档和其它文档可从这里下载:ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题,请先阅读文档,如不能解决再联系<[email protected]>.
关于本文档的问题请发信联系 <[email protected]>.