第 21 章。GEOM:模块化磁盘转换框架

21.1。概要

在 FreeBSD 中,GEOM 框架允许通过使用提供程序或 /dev 中的磁盘设备来访问和控制类,例如主引导记录和 BSD 标签。通过支持各种软件 RAID 配置,GEOM 透明地为操作系统和操作系统实用程序提供访问。

本章介绍在 FreeBSD 的 GEOM 框架下磁盘的使用。这包括使用该框架进行配置的主要 RAID 控制实用程序。本章并非 RAID 配置的权威指南,仅讨论 GEOM 支持的 RAID 分类。

阅读完本章后,您将了解

  • GEOM 提供了哪些类型的 RAID 支持。

  • 如何使用基本实用程序配置、维护和操作各种 RAID 级别。

  • 如何通过 GEOM 镜像、条带化、加密和远程连接磁盘设备。

  • 如何对连接到 GEOM 框架的磁盘进行故障排除。

在阅读本章之前,您应该

21.2. RAID0 - 条带化

条带化将多个磁盘驱动器组合成一个卷。条带化可以通过硬件 RAID 控制器来执行。GEOM 磁盘子系统提供了对磁盘条带化的软件支持,也称为 RAID0,无需 RAID 磁盘控制器。

在 RAID0 中,数据被分成块,并写入阵列中的所有驱动器。如下图所示,RAID0 可以同时将 64k 写入阵列中的四个磁盘,而不是等待系统将 256k 写入一个磁盘,从而提供更高的 I/O 性能。通过使用多个磁盘控制器可以进一步增强此性能。

Disk Striping Illustration

RAID0 条带中的每个磁盘必须大小相同,因为 I/O 请求交错以并行读取或写入多个磁盘。

RAID0 **不**提供任何冗余。这意味着如果阵列中的一个磁盘发生故障,所有磁盘上的数据都将丢失。如果数据很重要,请实施备份策略,定期将备份保存到远程系统或设备。

在 FreeBSD 系统上使用商品磁盘创建基于软件的 GEOM RAID0 的过程如下。创建条带后,请参阅 gstripe(8),以获取有关如何控制现有条带的更多信息。

步骤:创建未格式化的 ATA 磁盘条带

  1. 加载 geom_stripe.ko 模块

    # kldload geom_stripe
  2. 确保存在合适的挂载点。如果此卷将成为根分区,则暂时使用另一个挂载点,例如 /mnt

  3. 确定将要条带化的磁盘的设备名称,并创建新的条带设备。例如,要对两个未使用的未分区 ATA 磁盘进行条带化,其设备名称为 /dev/ad2/dev/ad3

    # gstripe label -v st0 /dev/ad2 /dev/ad3
    Metadata value stored on /dev/ad2.
    Metadata value stored on /dev/ad3.
    Done.
  4. 在新的卷上写入标准标签(也称为分区表)并安装默认引导代码

    # bsdlabel -wB /dev/stripe/st0
  5. 此过程除了 st0 之外,还应在 /dev/stripe 中创建其他两个设备。这些包括 st0ast0c。此时,可以使用 newfsst0a 上创建 UFS 文件系统

    # newfs -U /dev/stripe/st0a

    屏幕上将显示许多数字,几秒钟后,过程将完成。卷已创建并已准备好挂载。

  6. 手动挂载创建的磁盘条带

    # mount /dev/stripe/st0a /mnt
  7. 要在引导过程中自动挂载此条带化文件系统,请将卷信息放在 /etc/fstab 中。在此示例中,创建了一个名为 stripe 的永久挂载点

    # mkdir /stripe
    # echo "/dev/stripe/st0a /stripe ufs rw 2 2" \
    >> /etc/fstab
  8. 还必须通过在 /boot/loader.conf 中添加一行来在系统初始化期间自动加载 geom_stripe.ko 模块

    # echo 'geom_stripe_load="YES"' >> /boot/loader.conf

21.3. RAID1 - 镜像

RAID1 或 *镜像* 是将相同数据写入多个磁盘驱动器的方法。镜像通常用于防止由于驱动器故障导致的数据丢失。镜像中的每个驱动器都包含数据的相同副本。当单个驱动器发生故障时,镜像继续工作,提供仍在运行的驱动器中的数据。计算机继续运行,管理员有时间更换故障驱动器而不会中断用户。

这两个常见情况在这些示例中进行了说明。第一个示例从两个新驱动器创建镜像,并将其用作现有单个驱动器的替代品。第二个示例在单个新驱动器上创建镜像,将旧驱动器的数据复制到其中,然后将旧驱动器插入镜像。虽然此过程稍微复杂一些,但它只需要一个新驱动器。

传统上,镜像中的两个驱动器在型号和容量方面是相同的,但 gmirror(8) 不需要这样做。使用不同驱动器创建的镜像的容量将等于镜像中最小驱动器的容量。较大驱动器上的额外空间将不会使用。稍后插入镜像的驱动器必须至少具有与镜像中最小驱动器相同的容量。

此处显示的镜像过程是非破坏性的,但与任何主要的磁盘操作一样,请首先进行完整备份。

虽然在这些过程中使用 dump(8) 来复制文件系统,但它不适用于具有软更新日志记录的文件系统。有关检测和禁用软更新日志记录的信息,请参阅 tunefs(8)

21.3.1. 元数据问题

许多磁盘系统在每个磁盘的末尾存储元数据。在将磁盘重新用于镜像之前,应擦除旧的元数据。大多数问题是由两种特定类型的剩余元数据引起的:GPT 分区表和先前镜像的旧元数据。

可以使用 gpart(8) 擦除 GPT 元数据。此示例从磁盘 ada8 中擦除主 GPT 分区表和备份 GPT 分区表

# gpart destroy -F ada8

可以使用 gmirror(8) 从活动镜像中删除磁盘并一步擦除元数据。在此,示例磁盘 ada8 从活动镜像 gm4 中删除

# gmirror remove gm4 ada8

如果镜像未运行,但磁盘上仍然存在旧的镜像元数据,请使用 gmirror clear 删除它

# gmirror clear ada8

gmirror(8) 在磁盘末尾存储一个块的元数据。由于 GPT 分区方案也在磁盘末尾存储元数据,因此不建议使用 gmirror(8) 镜像整个 GPT 磁盘。此处使用 MBR 分区,因为它仅在磁盘的开头存储分区表,并且不会与镜像元数据冲突。

21.3.2. 使用两个新磁盘创建镜像

在此示例中,FreeBSD 已安装在单个磁盘 ada0 上。两个新磁盘 ada1ada2 已连接到系统。将在这两个磁盘上创建一个新的镜像,并将其用于替换旧的单个磁盘。

必须将 geom_mirror.ko 内核模块构建到内核中或在引导时或运行时加载。现在手动加载内核模块

# gmirror load

使用两个新驱动器创建镜像

# gmirror label -v gm0 /dev/ada1 /dev/ada2

gm0 是分配给新镜像的用户选择的设备名称。启动镜像后,此设备名称将显示在 /dev/mirror/ 中。

现在可以使用 gpart(8) 在镜像上创建 MBR 和 bsdlabel 分区表。此示例使用传统的文件系统布局,其中包含用于 /、swap、/var/tmp/usr 的分区。单个 / 和 swap 分区也可以工作。

镜像上的分区不必与现有磁盘上的分区大小相同,但必须足够大以容纳已存在于 ada0 上的所有数据。

# gpart create -s MBR mirror/gm0
# gpart add -t freebsd -a 4k mirror/gm0
# gpart show mirror/gm0
=>       63  156301423  mirror/gm0  MBR  (74G)
         63         63                    - free -  (31k)
        126  156301299                 1  freebsd  (74G)
  156301425         61                    - free -  (30k)
# gpart create -s BSD mirror/gm0s1
# gpart add -t freebsd-ufs  -a 4k -s 2g mirror/gm0s1
# gpart add -t freebsd-swap -a 4k -s 4g mirror/gm0s1
# gpart add -t freebsd-ufs  -a 4k -s 2g mirror/gm0s1
# gpart add -t freebsd-ufs  -a 4k -s 1g mirror/gm0s1
# gpart add -t freebsd-ufs  -a 4k mirror/gm0s1
# gpart show mirror/gm0s1
=>        0  156301299  mirror/gm0s1  BSD  (74G)
          0          2                      - free -  (1.0k)
          2    4194304                   1  freebsd-ufs  (2.0G)
    4194306    8388608                   2  freebsd-swap (4.0G)
   12582914    4194304                   4  freebsd-ufs  (2.0G)
   16777218    2097152                   5  freebsd-ufs  (1.0G)
   18874370  137426928                   6  freebsd-ufs  (65G)
  156301298          1                      - free -  (512B)

通过在 MBR 和 bsdlabel 中安装引导代码并设置活动切片,使镜像可引导。

# gpart bootcode -b /boot/mbr mirror/gm0
# gpart set -a active -i 1 mirror/gm0
# gpart bootcode -b /boot/boot mirror/gm0s1

格式化新镜像上的文件系统,启用软更新。

# newfs -U /dev/mirror/gm0s1a
# newfs -U /dev/mirror/gm0s1d
# newfs -U /dev/mirror/gm0s1e
# newfs -U /dev/mirror/gm0s1f

现在可以使用 dump(8)restore(8) 将原始 ada0 磁盘上的文件系统复制到镜像上。

# mount /dev/mirror/gm0s1a /mnt
# dump -C16 -b64 -0aL -f - / | (cd /mnt && restore -rf -)
# mount /dev/mirror/gm0s1d /mnt/var
# mount /dev/mirror/gm0s1e /mnt/tmp
# mount /dev/mirror/gm0s1f /mnt/usr
# dump -C16 -b64 -0aL -f - /var | (cd /mnt/var && restore -rf -)
# dump -C16 -b64 -0aL -f - /tmp | (cd /mnt/tmp && restore -rf -)
# dump -C16 -b64 -0aL -f - /usr | (cd /mnt/usr && restore -rf -)

编辑 /mnt/etc/fstab 以指向新的镜像文件系统

# Device		Mountpoint	FStype	Options	Dump	Pass#
/dev/mirror/gm0s1a	/		ufs	rw	1	1
/dev/mirror/gm0s1b	none		swap	sw	0	0
/dev/mirror/gm0s1d	/var		ufs	rw	2	2
/dev/mirror/gm0s1e	/tmp		ufs	rw	2	2
/dev/mirror/gm0s1f	/usr		ufs	rw	2	2

如果 geom_mirror.ko 内核模块未构建到内核中,则编辑 /mnt/boot/loader.conf 以在引导时加载模块

geom_mirror_load="YES"

重新引导系统以测试新镜像并验证所有数据是否已复制。BIOS 将镜像视为两个独立的驱动器,而不是镜像。由于驱动器相同,因此选择哪个驱动器引导并不重要。

如果引导时出现问题,请参阅 故障排除。关闭电源并断开原始 ada0 磁盘的连接,使其可以作为脱机备份保留。

在使用过程中,镜像的行为将与原始单个驱动器完全相同。

21.3.3. 使用现有驱动器创建镜像

在此示例中,FreeBSD 已安装在单个磁盘 ada0 上。一个新磁盘 ada1 已连接到系统。将在新磁盘上创建一个单磁盘镜像,将现有系统复制到其中,然后将旧磁盘插入镜像。需要执行此稍微复杂的过程,因为 gmirror 需要在每个磁盘的末尾放置一个 512 字节的元数据块,而现有的 ada0 通常已分配了所有空间。

加载 geom_mirror.ko 内核模块

# gmirror load

使用 diskinfo 检查原始磁盘的介质大小

# diskinfo -v ada0 | head -n3
/dev/ada0
        512             # sectorsize
        1000204821504   # mediasize in bytes (931G)

在新磁盘上创建镜像。为了确保镜像容量不超过原始 ada0 驱动器,使用 gnop(8) 创建相同大小的伪驱动器。此驱动器不存储任何数据,仅用于限制镜像的大小。当 gmirror(8) 创建镜像时,它将容量限制为 gzero.nop 的大小,即使新的 ada1 驱动器有更多空间也是如此。请注意,第二行中的 *1000204821504* 等于上面 diskinfo 显示的 ada0 的介质大小。

# geom zero load
# gnop create -s 1000204821504 gzero
# gmirror label -v gm0 gzero.nop ada1
# gmirror forget gm0

由于 gzero.nop 不存储任何数据,因此镜像不会将其视为已连接。镜像被告知“忘记”未连接的组件,从而删除对 gzero.nop 的引用。结果是包含单个磁盘 ada1 的镜像设备。

创建 gm0 后,查看 ada0 上的分区表。此输出来自 1 TB 驱动器。如果驱动器末尾有一些未分配的空间,则可以将内容直接从 ada0 复制到新镜像。

但是,如果输出显示磁盘上的所有空间都已分配,如下所示,则磁盘末尾没有可用于 512 字节镜像元数据的空间。

# gpart show ada0
=>        63  1953525105        ada0  MBR  (931G)
          63  1953525105           1  freebsd  [active]  (931G)

在这种情况下,必须编辑分区表以将 mirror/gm0 上的容量减少一个扇区。稍后将解释此过程。

无论哪种情况,都应首先使用 gpart backupgpart restore 复制主磁盘上的分区表。

# gpart backup ada0 > table.ada0
# gpart backup ada0s1 > table.ada0s1

这些命令创建两个文件,table.ada0table.ada0s1。此示例来自一个 1 TB 的驱动器

# cat table.ada0
MBR 4
1 freebsd         63 1953525105   [active]
# cat table.ada0s1
BSD 8
1  freebsd-ufs          0    4194304
2 freebsd-swap    4194304   33554432
4  freebsd-ufs   37748736   50331648
5  freebsd-ufs   88080384   41943040
6  freebsd-ufs  130023424  838860800
7  freebsd-ufs  968884224  984640881

如果磁盘末尾没有显示可用空间,则必须将切片和最后一个分区的尺寸都减少一个扇区。编辑这两个文件,将切片和最后一个分区的尺寸都减少一个扇区。这些是每个列表中的最后一个数字。

# cat table.ada0
MBR 4
1 freebsd         63 1953525104   [active]
# cat table.ada0s1
BSD 8
1  freebsd-ufs          0    4194304
2 freebsd-swap    4194304   33554432
4  freebsd-ufs   37748736   50331648
5  freebsd-ufs   88080384   41943040
6  freebsd-ufs  130023424  838860800
7  freebsd-ufs  968884224  984640880

如果磁盘末尾至少有一个扇区未分配,则可以使用这两个文件而不进行修改。

现在将分区表恢复到 mirror/gm0

# gpart restore mirror/gm0 < table.ada0
# gpart restore mirror/gm0s1 < table.ada0s1

使用 gpart show 检查分区表。此示例对 / 使用 gm0s1a,对 /var 使用 gm0s1d,对 /usr 使用 gm0s1e,对 /data1 使用 gm0s1f,对 /data2 使用 gm0s1g

# gpart show mirror/gm0
=>        63  1953525104  mirror/gm0  MBR  (931G)
          63  1953525042           1  freebsd  [active]  (931G)
  1953525105          62              - free -  (31k)

# gpart show mirror/gm0s1
=>         0  1953525042  mirror/gm0s1  BSD  (931G)
           0     2097152             1  freebsd-ufs  (1.0G)
     2097152    16777216             2  freebsd-swap  (8.0G)
    18874368    41943040             4  freebsd-ufs  (20G)
    60817408    20971520             5  freebsd-ufs  (10G)
    81788928   629145600             6  freebsd-ufs  (300G)
   710934528  1242590514             7  freebsd-ufs  (592G)
  1953525042          63                - free -  (31k)

切片和最后一个分区都必须在磁盘末尾至少有一个空闲块。

在这些新分区上创建文件系统。分区数量将有所不同,以匹配原始磁盘 ada0

# newfs -U /dev/mirror/gm0s1a
# newfs -U /dev/mirror/gm0s1d
# newfs -U /dev/mirror/gm0s1e
# newfs -U /dev/mirror/gm0s1f
# newfs -U /dev/mirror/gm0s1g

通过在 MBR 和 bsdlabel 中安装引导代码并设置活动切片,使镜像可引导。

# gpart bootcode -b /boot/mbr mirror/gm0
# gpart set -a active -i 1 mirror/gm0
# gpart bootcode -b /boot/boot mirror/gm0s1

调整 /etc/fstab 以在镜像上使用新分区。首先通过将其复制到 /etc/fstab.orig 来备份此文件。

# cp /etc/fstab /etc/fstab.orig

编辑 /etc/fstab,将 /dev/ada0 替换为 mirror/gm0

# Device		Mountpoint	FStype	Options	Dump	Pass#
/dev/mirror/gm0s1a	/		ufs	rw	1	1
/dev/mirror/gm0s1b	none		swap	sw	0	0
/dev/mirror/gm0s1d	/var		ufs	rw	2	2
/dev/mirror/gm0s1e	/usr		ufs	rw	2	2
/dev/mirror/gm0s1f	/data1		ufs	rw	2	2
/dev/mirror/gm0s1g	/data2		ufs	rw	2	2

如果 geom_mirror.ko 内核模块尚未构建到内核中,请编辑 /boot/loader.conf 以在启动时加载它

geom_mirror_load="YES"

现在可以使用 dump(8)restore(8) 将原始磁盘上的文件系统复制到镜像上。使用 dump -L 转储的每个文件系统都会首先创建一个快照,这可能需要一些时间。

# mount /dev/mirror/gm0s1a /mnt
# dump -C16 -b64 -0aL -f - /    | (cd /mnt && restore -rf -)
# mount /dev/mirror/gm0s1d /mnt/var
# mount /dev/mirror/gm0s1e /mnt/usr
# mount /dev/mirror/gm0s1f /mnt/data1
# mount /dev/mirror/gm0s1g /mnt/data2
# dump -C16 -b64 -0aL -f - /usr | (cd /mnt/usr && restore -rf -)
# dump -C16 -b64 -0aL -f - /var | (cd /mnt/var && restore -rf -)
# dump -C16 -b64 -0aL -f - /data1 | (cd /mnt/data1 && restore -rf -)
# dump -C16 -b64 -0aL -f - /data2 | (cd /mnt/data2 && restore -rf -)

重新启动系统,从 ada1 启动。如果一切正常,系统将从 mirror/gm0 启动,该镜像现在包含与 ada0 之前相同的数据。如果启动时出现问题,请参阅 故障排除

此时,镜像仍仅由单个 ada1 磁盘组成。

mirror/gm0 成功启动后,最后一步是将 ada0 插入镜像。

ada0 插入镜像时,其以前的内容将被镜像中的数据覆盖。在将 ada0 添加到镜像之前,请确保 mirror/gm0 的内容与 ada0 相同。如果之前通过 dump(8)restore(8) 复制的内容与 ada0 上的内容不相同,请将 /etc/fstab 恢复为挂载 ada0 上的文件系统,重新启动并重新开始整个过程。

# gmirror insert gm0 ada0
GEOM_MIRROR: Device gm0: rebuilding provider ada0

两个磁盘之间的同步将立即开始。使用 gmirror status 查看进度。

# gmirror status
      Name    Status  Components
mirror/gm0  DEGRADED  ada1 (ACTIVE)
                      ada0 (SYNCHRONIZING, 64%)

一段时间后,同步将完成。

GEOM_MIRROR: Device gm0: rebuilding provider ada0 finished.
# gmirror status
      Name    Status  Components
mirror/gm0  COMPLETE  ada1 (ACTIVE)
                      ada0 (ACTIVE)

mirror/gm0 现在包含两个磁盘 ada0ada1,并且内容会自动彼此同步。在使用中,mirror/gm0 的行为将与原始的单个驱动器完全相同。

21.3.4. 故障排除

如果系统不再启动,可能需要更改 BIOS 设置以从新的镜像驱动器之一启动。任何镜像驱动器都可以用于启动,因为它们包含相同的数据。

如果启动在此消息处停止,则镜像设备存在问题

Mounting from ufs:/dev/mirror/gm0s1a failed with error 19.

Loader variables:
  vfs.root.mountfrom=ufs:/dev/mirror/gm0s1a
  vfs.root.mountfrom.options=rw

Manual root filesystem specification:
  <fstype>:<device> [options]
      Mount <device> using filesystem <fstype>
      and with the specified (optional) option list.

    e.g. ufs:/dev/da0s1a
        zfs:tank
        cd9660:/dev/acd0 ro
          (which is equivalent to: mount -t cd9660 -o ro /dev/acd0 /)

  ?               List valid disk boot devices
  .               Yield 1 second (for background tasks)
  <empty line>    Abort manual input

mountroot>

忘记在 /boot/loader.conf 中加载 geom_mirror.ko 模块会导致此问题。要解决此问题,请从 FreeBSD 安装介质启动,并在第一个提示符处选择 Shell。然后加载镜像模块并挂载镜像设备

# gmirror load
# mount /dev/mirror/gm0s1a /mnt

编辑 /mnt/boot/loader.conf,添加一行以加载镜像模块

geom_mirror_load="YES"

保存文件并重新启动。

导致 error 19 的其他问题需要更多努力才能解决。尽管系统应该从 ada0 启动,但如果 /etc/fstab 不正确,则会显示另一个提示以选择 shell。在启动加载程序提示符处输入 ufs:/dev/ada0s1a 并按 Enter。撤消 /etc/fstab 中的编辑,然后挂载原始磁盘 (ada0) 而不是镜像上的文件系统。重新启动系统并重试此过程。

Enter full pathname of shell or RETURN for /bin/sh:
# cp /etc/fstab.orig /etc/fstab
# reboot

21.3.5. 从磁盘故障中恢复

磁盘镜像的好处在于,单个磁盘发生故障不会导致镜像丢失任何数据。在上面的示例中,如果 ada0 发生故障,镜像将继续工作,并提供来自剩余工作驱动器 ada1 的数据。

要更换故障驱动器,请关闭系统并使用容量相同或更大的新驱动器物理更换故障驱动器。制造商在以千兆字节为单位对驱动器进行评级时使用了一些任意值,唯一真正确定方法是比较 diskinfo -v 显示的扇区总数。容量大于镜像的驱动器可以使用,尽管新驱动器上的额外空间将不会被使用。

计算机重新启动后,镜像将以“降级”模式运行,只有一个驱动器。镜像被告知要忘记当前未连接的驱动器

# gmirror forget gm0

使用 元数据问题 中的说明清除更换磁盘上的任何旧元数据。然后将更换磁盘(此示例为 ada4)插入镜像

# gmirror insert gm0 /dev/ada4

将新驱动器插入镜像时,将开始重新同步。将镜像数据复制到新驱动器的此过程可能需要一段时间。在复制期间,镜像的性能将大大降低,因此最好在计算机需求较低时插入新驱动器。

可以使用 gmirror status 监控进度,该命令显示正在同步的驱动器以及完成百分比。在重新同步期间,状态将为 DEGRADED,并在进程完成后更改为 COMPLETE

21.4. RAID3 - 带专用奇偶校验的字节级条带化

RAID3 是一种将多个磁盘驱动器组合成单个卷并带有专用奇偶校验磁盘的方法。在 RAID3 系统中,数据被分成多个字节,这些字节被写入阵列中的所有驱动器(一个充当专用奇偶校验磁盘的驱动器除外)。这意味着从 RAID3 实现读取磁盘会访问阵列中的所有磁盘。通过使用多个磁盘控制器可以提高性能。RAID3 阵列提供 1 个驱动器的容错,同时提供 1 - 1/n 倍于阵列中所有驱动器总容量的容量,其中 n 是阵列中硬盘驱动器的数量。这种配置主要适用于存储较大型数据,例如多媒体文件。

构建 RAID3 阵列至少需要 3 个物理硬盘驱动器。每个磁盘必须具有相同的大小,因为 I/O 请求是交错的,以便并行读取或写入多个磁盘。此外,由于 RAID3 的性质,驱动器数量必须等于 3、5、9、17 等,或 2^n + 1。

本节演示如何在 FreeBSD 系统上创建软件 RAID3。

虽然理论上可以在 FreeBSD 上从 RAID3 阵列启动,但这种配置并不常见,也不建议使用。

21.4.1. 创建专用 RAID3 阵列

在 FreeBSD 中,对 RAID3 的支持由 graid3(8) GEOM 类实现。在 FreeBSD 上创建专用 RAID3 阵列需要执行以下步骤。

  1. 首先,通过发出以下命令之一加载 geom_raid3.ko 内核模块

    # graid3 load

    # kldload geom_raid3
  2. 确保存在合适的挂载点。此命令创建一个新目录用作挂载点

    # mkdir /multimedia
  3. 确定将添加到阵列中的磁盘的设备名称,并创建新的 RAID3 设备。列出的最后一个设备将充当专用奇偶校验磁盘。此示例使用三个未分区的 ATA 驱动器:ada1ada2 用于数据,ada3 用于奇偶校验。

    # graid3 label -v gr0 /dev/ada1 /dev/ada2 /dev/ada3
    Metadata value stored on /dev/ada1.
    Metadata value stored on /dev/ada2.
    Metadata value stored on /dev/ada3.
    Done.
  4. 对新创建的 gr0 设备进行分区,并在其上放置一个 UFS 文件系统

    # gpart create -s GPT /dev/raid3/gr0
    # gpart add -t freebsd-ufs /dev/raid3/gr0
    # newfs -j /dev/raid3/gr0p1

    许多数字将出现在屏幕上,经过一段时间后,该过程将完成。卷已创建并已准备好挂载

    # mount /dev/raid3/gr0p1 /multimedia/

    RAID3 阵列现在可以使用了。

需要额外的配置才能在系统重新启动后保留此设置。

  1. 必须在挂载阵列之前加载 geom_raid3.ko 模块。为了在系统初始化期间自动加载内核模块,请将以下行添加到 /boot/loader.conf

    geom_raid3_load="YES"
  2. 为了在系统启动过程中自动挂载阵列的文件系统,必须将以下卷信息添加到 /etc/fstab

    /dev/raid3/gr0p1	/multimedia	ufs	rw	2	2

21.5. 软件 RAID 设备

某些主板和扩展卡添加了一些简单的硬件,通常只是一个 ROM,允许计算机从 RAID 阵列启动。启动后,对 RAID 阵列的访问由计算机主处理器上运行的软件处理。这种“硬件辅助软件 RAID”提供了不依赖于任何特定操作系统的 RAID 阵列,并且即使在加载操作系统之前也能正常工作。

根据使用的硬件,支持多个级别的 RAID。有关完整列表,请参阅 graid(8)

graid(8) 需要 geom_raid.ko 内核模块,该模块包含在从 FreeBSD 9.1 开始的 GENERIC 内核中。如果需要,可以使用 graid load 手动加载它。

21.5.1. 创建阵列

软件 RAID 设备通常都有一个菜单,可以在计算机启动时按下特殊键进入。该菜单可用于创建和删除 RAID 阵列。graid(8) 也可以直接从命令行创建阵列。

graid label 用于创建新的阵列。此示例中使用的主板具有英特尔软件 RAID 芯片组,因此指定了英特尔的元数据格式。新阵列被赋予标签 gm0,它是镜像(RAID1),并使用驱动器 ada0ada1

将驱动器制成新阵列时,驱动器上的某些空间将被覆盖。请先备份现有数据!

# graid label Intel gm0 RAID1 ada0 ada1
GEOM_RAID: Intel-a29ea104: Array Intel-a29ea104 created.
GEOM_RAID: Intel-a29ea104: Disk ada0 state changed from NONE to ACTIVE.
GEOM_RAID: Intel-a29ea104: Subdisk gm0:0-ada0 state changed from NONE to ACTIVE.
GEOM_RAID: Intel-a29ea104: Disk ada1 state changed from NONE to ACTIVE.
GEOM_RAID: Intel-a29ea104: Subdisk gm0:1-ada1 state changed from NONE to ACTIVE.
GEOM_RAID: Intel-a29ea104: Array started.
GEOM_RAID: Intel-a29ea104: Volume gm0 state changed from STARTING to OPTIMAL.
Intel-a29ea104 created
GEOM_RAID: Intel-a29ea104: Provider raid/r0 for volume gm0 created.

状态检查显示新的镜像已准备好使用。

# graid status
   Name   Status  Components
raid/r0  OPTIMAL  ada0 (ACTIVE (ACTIVE))
                  ada1 (ACTIVE (ACTIVE))

阵列设备出现在 /dev/raid/ 中。第一个阵列称为 r0。如果存在其他阵列,则将为 r1r2 等。

某些此类设备的 BIOS 菜单可以创建名称中包含特殊字符的阵列。为了避免这些特殊字符带来的问题,阵列被赋予简单的编号名称,如 r0。要显示实际标签,例如上面示例中的 gm0,请使用 sysctl(8)

# sysctl kern.geom.raid.name_format=1

21.5.2. 多个卷

某些软件 RAID 设备支持阵列上的多个。卷的工作方式类似于分区,允许以不同的方式分割和使用物理驱动器上的空间。例如,英特尔软件 RAID 设备支持两个卷。此示例创建了一个 40 GB 的镜像,用于安全地存储操作系统,然后创建一个 20 GB 的 RAID0(条带)卷,用于快速临时存储。

# graid label -S 40G Intel gm0 RAID1 ada0 ada1
# graid add -S 20G gm0 RAID0

卷作为 /dev/raid/ 中的其他 rX 条目出现。具有两个卷的阵列将显示 r0r1

有关不同软件 RAID 设备支持的卷数,请参阅 graid(8)

21.5.3. 将单个驱动器转换为镜像

在某些特定条件下,可以将现有的单个驱动器转换为 graid(8) 阵列,而无需重新格式化。为了避免转换期间数据丢失,现有驱动器必须满足以下最低要求。

  • 驱动器必须使用 MBR 分区方案进行分区。GPT 或其他在驱动器末尾包含元数据的分区方案将被 graid(8) 元数据覆盖并损坏。

  • 驱动器末尾必须有足够的未分区且未使用的空间来容纳 graid(8) 元数据。此元数据的大小不一,但最大的占用 64 MB,因此建议至少有这么多的可用空间。

如果驱动器满足这些要求,请先进行完整备份。然后使用该驱动器创建一个单驱动器镜像。

# graid label Intel gm0 RAID1 ada0 NONE

graid(8) 元数据已写入驱动器末尾的未使用空间中。现在可以将第二个驱动器插入镜像。

# graid insert raid/r0 ada1

原始驱动器中的数据将立即开始复制到第二个驱动器。在复制完成之前,镜像将处于降级状态。

21.5.4. 将新驱动器插入阵列

可以将驱动器插入阵列,以替换已故障或丢失的驱动器。如果没有故障或丢失的驱动器,则新驱动器将成为备用驱动器。例如,将新驱动器插入工作中的双驱动器镜像会导致一个双驱动器镜像和一个备用驱动器,而不是一个三驱动器镜像。

在示例镜像阵列中,数据会立即开始复制到新插入的驱动器。新驱动器上的任何现有信息都将被覆盖。

# graid insert raid/r0 ada1
GEOM_RAID: Intel-a29ea104: Disk ada1 state changed from NONE to ACTIVE.
GEOM_RAID: Intel-a29ea104: Subdisk gm0:1-ada1 state changed from NONE to NEW.
GEOM_RAID: Intel-a29ea104: Subdisk gm0:1-ada1 state changed from NEW to REBUILD.
GEOM_RAID: Intel-a29ea104: Subdisk gm0:1-ada1 rebuild start at 0.

21.5.5. 从阵列中移除驱动器

可以永久地从阵列中移除单个驱动器并擦除其元数据。

# graid remove raid/r0 ada1
GEOM_RAID: Intel-a29ea104: Disk ada1 state changed from ACTIVE to OFFLINE.
GEOM_RAID: Intel-a29ea104: Subdisk gm0:1-[unknown] state changed from ACTIVE to NONE.
GEOM_RAID: Intel-a29ea104: Volume gm0 state changed from OPTIMAL to DEGRADED.

21.5.6. 停止阵列

可以停止阵列,而无需从驱动器中移除元数据。系统启动时将重新启动阵列。

# graid stop raid/r0

21.5.7. 检查阵列状态

可以随时检查阵列状态。在将驱动器添加到上述镜像后,数据正在从原始驱动器复制到新驱动器。

# graid status
   Name    Status  Components
raid/r0  DEGRADED  ada0 (ACTIVE (ACTIVE))
                   ada1 (ACTIVE (REBUILD 28%))

某些类型的阵列,如 RAID0CONCAT,如果磁盘发生故障,则可能不会显示在状态报告中。要查看这些部分故障的阵列,请添加 -ga

# graid status -ga
          Name  Status  Components
Intel-e2d07d9a  BROKEN  ada6 (ACTIVE (ACTIVE))

21.5.8. 删除阵列

通过删除阵列中的所有卷来销毁阵列。当删除最后一个存在的卷时,阵列将停止,并且元数据将从驱动器中移除。

# graid delete raid/r0

21.5.9. 删除意外阵列

驱动器可能意外包含 graid(8) 元数据,这可能是由于先前使用或制造商测试造成的。graid(8) 将检测到这些驱动器并创建阵列,从而干扰对单个驱动器的访问。要删除不需要的元数据,请执行以下操作:

  1. 启动系统。在启动菜单中,选择 2 以进入加载程序提示符。输入

    OK set kern.geom.raid.enable=0
    OK boot

    系统将在禁用 graid(8) 的情况下启动。

  2. 备份受影响驱动器上的所有数据。

  3. 作为变通方法,可以通过添加以下内容来禁用 graid(8) 阵列检测:

    kern.geom.raid.enable=0

    /boot/loader.conf

    要永久删除受影响驱动器上的 graid(8) 元数据,请启动 FreeBSD 安装 CD-ROM 或内存棒,然后选择 Shell。使用 status 查找阵列的名称,通常为 raid/r0

    # graid status
       Name   Status  Components
    raid/r0  OPTIMAL  ada0 (ACTIVE (ACTIVE))
                      ada1 (ACTIVE (ACTIVE))

    按名称删除卷:

    # graid delete raid/r0

    如果显示多个卷,请对每个卷重复此过程。删除最后一个阵列后,该卷将被销毁。

    重新启动并验证数据,如有必要,请从备份中恢复。删除元数据后,还可以删除 /boot/loader.conf 中的 kern.geom.raid.enable=0 条目。

21.6. GEOM 网关网络

GEOM 提供了一种简单的机制,可以通过使用 GEOM 网关网络守护程序 ggated 来提供对设备(如磁盘、CD 和文件系统)的远程访问。具有设备的系统运行服务器守护程序,该守护程序处理客户端使用 ggatec 发出的请求。设备不应包含任何敏感数据,因为客户端和服务器之间的连接未加密。

与在 网络文件系统 (NFS) 中讨论的 NFS 类似,ggated 使用导出文件进行配置。此文件指定允许哪些系统访问导出的资源以及为其提供的访问级别。例如,要授予客户端 192.168.1.5 对第一个 SCSI 磁盘上的第四个分区的读写访问权限,请使用以下行创建 /etc/gg.exports

192.168.1.5 RW /dev/da0s4d

在导出设备之前,请确保它当前未挂载。然后,启动 ggated:

# ggated

可以使用多个选项来指定备用侦听端口或更改导出文件的默认位置。有关详细信息,请参阅 ggated(8)

要在客户端计算机上访问导出的设备,首先使用 ggatec 指定服务器的 IP 地址和导出设备的设备名称。如果成功,此命令将显示要挂载的 ggate 设备名称。将指定的设备名称挂载到空闲的挂载点上。此示例连接到 192.168.1.1 上的 /dev/da0s4d 分区,然后将 /dev/ggate0 挂载到 /mnt

# ggatec create -o rw 192.168.1.1 /dev/da0s4d
ggate0
# mount /dev/ggate0 /mnt

现在可以通过客户端上的 /mnt 访问服务器上的设备。有关 ggatec 的更多详细信息和一些用法示例,请参阅 ggatec(8)

如果设备当前已挂载在服务器或网络上的任何其他客户端上,则挂载将失败。如果需要同时访问网络资源,请改用 NFS。

当不再需要设备时,请使用 umount 卸载它,以便其他客户端可以使用该资源。

21.7. 为磁盘设备添加标签

在系统初始化期间,FreeBSD 内核会在找到设备时创建设备节点。这种探测设备的方法引发了一些问题。例如,如果通过 USB 添加了新的磁盘设备会怎样?闪存设备可能会被分配 da0 的设备名称,而原始的 da0 会移至 da1。如果文件系统在 /etc/fstab 中列出,这会导致挂载文件系统的问题,也可能阻止系统启动。

一种解决方案是按顺序链接 SCSI 设备,以便添加到 SCSI 卡的新设备将被分配未使用的设备编号。但是 USB 设备可能会替换主 SCSI 磁盘怎么办?发生这种情况是因为通常在 SCSI 卡之前探测 USB 设备。一种解决方案是在系统启动后才插入这些设备。另一种方法是只使用一个 ATA 驱动器,并且永远不要在 /etc/fstab 中列出 SCSI 设备。

更好的解决方案是使用 glabel 为磁盘设备添加标签,并在 /etc/fstab 中使用这些标签。由于 glabel 将标签存储在给定提供程序的最后一个扇区中,因此标签将在重新启动后保持持久。通过将此标签用作设备,无论通过哪个设备节点访问,都可以始终挂载文件系统。

glabel 可以创建临时标签和永久标签。只有永久标签在重新启动后保持一致。有关标签之间差异的更多信息,请参阅 glabel(8)

21.7.1. 标签类型和示例

永久标签可以是通用标签或文件系统标签。可以使用 tunefs(8)newfs(8) 创建永久文件系统标签。这些类型的标签在 /dev 的子目录中创建,并将根据文件系统类型命名。例如,UFS2 文件系统标签将在 /dev/ufs 中创建。可以使用 glabel label 创建通用永久标签。这些标签不是特定于文件系统的,将在 /dev/label 中创建。

临时标签会在下次重启时被销毁。这些标签创建在/dev/label中,适用于实验。可以使用glabel create创建临时标签。

要为 UFS2 文件系统创建永久标签,且不破坏任何数据,请执行以下命令

# tunefs -L home /dev/da3

现在应该在/dev/ufs中存在一个标签,可以将其添加到/etc/fstab

/dev/ufs/home		/home            ufs     rw              2      2

尝试运行tunefs时,文件系统不得处于挂载状态。

现在可以挂载文件系统了

# mount /home

从现在开始,只要geom_label.ko内核模块在启动时通过/boot/loader.conf加载或存在GEOM_LABEL内核选项,设备节点可能会发生变化,而不会对系统造成任何不良影响。

也可以使用newfs-L标志创建带有默认标签的文件系统。有关更多信息,请参阅newfs(8)

可以使用以下命令销毁标签

# glabel destroy home

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

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

通过永久标记引导磁盘上的分区,即使磁盘移动到另一个控制器或传输到不同的系统,系统也应该能够继续正常启动。在此示例中,假设使用单个 ATA 磁盘,系统当前将其识别为ad0。还假设使用标准 FreeBSD 分区方案,包括//var/usr/tmp,以及交换分区。

重新启动系统,并在loader(8)提示符下,按4以单用户模式启动。然后输入以下命令

# 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将如下所示

# 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将显示

# 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)类支持基于唯一文件系统 ID(ufsid)的 UFS 文件系统标签类型。这些标签可以在/dev/ufsid中找到,并在系统启动期间自动创建。可以使用ufsid标签通过/etc/fstab挂载分区。使用glabel status接收文件系统及其对应ufsid标签的列表

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

在上面的示例中,ad4s1d表示/var,而ad4s1f表示/usr。使用显示的ufsid值,现在可以使用/etc/fstab中的以下条目挂载这些分区

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

任何具有ufsid标签的分区都可以以这种方式挂载,从而无需手动创建永久标签,同时仍然享受设备名称独立挂载的好处。

21.8. 通过 GEOM 进行 UFS 日志记录

FreeBSD 上提供了对 UFS 文件系统日志的支持。该实现通过 GEOM 子系统提供,并使用gjournal进行配置。与其他文件系统日志记录实现不同,gjournal方法是基于块的,而不是作为文件系统的一部分实现的。它是一个 GEOM 扩展。

日志记录存储文件系统事务的日志,例如构成完整磁盘写入操作的变化,然后再将元数据和文件写入提交到磁盘。此事务日志以后可以重播以重做文件系统事务,防止文件系统不一致。

此方法提供了另一种机制来防止文件系统的数据丢失和不一致。与跟踪和执行元数据更新的软更新以及创建文件系统映像的快照不同,日志存储在专门用于此任务的磁盘空间中。为了获得更好的性能,日志可以存储在另一个磁盘上。在此配置中,应在设备之后列出日志提供程序或存储设备,以在其上启用日志记录。

GENERIC内核提供了对gjournal的支持。要在启动时自动加载geom_journal.ko内核模块,请将以下行添加到/boot/loader.conf

geom_journal_load="YES"

如果使用自定义内核,请确保以下行位于内核配置文件中

options	GEOM_JOURNAL

加载模块后,可以使用以下步骤在新文件系统上创建日志。在此示例中,da4是新的 SCSI 磁盘

# gjournal load
# gjournal label /dev/da4

这将加载模块并在/dev/da4上创建/dev/da4.journal设备节点。

现在可以在已记录的设备上创建 UFS 文件系统,然后将其挂载到现有挂载点上

# newfs -O 2 -J /dev/da4.journal
# mount /dev/da4.journal /mnt

在多个切片的情况下,将为每个单独的切片创建一个日志。例如,如果ad4s1ad4s2都是切片,则gjournal将创建ad4s1.journalad4s2.journal

也可以通过使用tunefs在当前文件系统上启用日志记录。但是,在尝试更改现有文件系统之前,始终进行备份。在大多数情况下,如果gjournal无法创建日志,它将失败,但这并不能防止由于误用tunefs而导致的数据丢失。有关这些命令的更多信息,请参阅gjournal(8)tunefs(8)

可以记录 FreeBSD 系统的引导磁盘。有关详细说明,请参阅文章在台式电脑上实现 UFS 日志记录


上次修改时间:2024 年 9 月 20 日,作者:Fernando Apesteguía