第 20 章 存储

如果发现翻译错误,请直接 发起PR修改

20.1. 简介

本章介绍了在 FreeBSD 中使用磁盘和存储介质的方法。这包括 SCSI 和 IDE 磁盘、CD 和 DVD 媒体、内存支持的磁盘以及 USB 存储设备。

阅读完本章后,您将了解:

  • 如何向 FreeBSD 系统添加额外的硬盘。

  • 如何在 FreeBSD 上扩大磁盘分区的大小。

  • 如何配置 FreeBSD 以使用 USB 存储设备。

  • 如何在 FreeBSD 系统上使用 CD 和 DVD 媒体。

  • 如何使用 FreeBSD 下可用的备份程序。

  • 如何设置内存磁盘。

  • 文件系统快照是什么以及如何高效使用它们。

  • 如何使用配额限制磁盘空间使用。

  • 如何加密磁盘和交换空间以防止攻击者的攻击。

  • 如何配置高可用存储网络。

在阅读本章之前,您应该:

20.2. 添加磁盘

本节描述了如何将一个新的 SATA 硬盘添加到目前只有一个驱动器的计算机中。首先,关闭计算机,并按照计算机、控制器和硬盘制造商的说明将硬盘安装到计算机中。重新启动系统并成为 root 用户。

检查 /var/run/dmesg.boot 确保新的磁盘被找到。在这个例子中,新添加的 SATA 驱动器将会显示为 ada1

对于这个示例,将在新磁盘上创建一个单独的大分区。优先使用 GPT 分区方案,而不是较旧且功能较少的 MBR 方案。

如果要添加的磁盘不是空白的,则可以使用 gpart delete 命令删除旧的分区信息。有关详细信息,请参阅 gpart(8)

创建了分区方案,然后添加了一个单独的分区。为了提高在具有更大硬件块大小的新磁盘上的性能,该分区被对齐到每个一兆字节边界。

# gpart create -s GPT ada1
# gpart add -t freebsd-ufs -a 1M ada1

根据使用情况,可能需要创建几个较小的分区。有关创建小于整个磁盘的分区的选项,请参阅 gpart(8)

可以使用 gpart show 命令查看磁盘分区信息:

% gpart show ada1
=>        34  1465146988  ada1  GPT  (699G)
          34        2014        - free -  (1.0M)
        2048  1465143296     1  freebsd-ufs  (699G)
  1465145344        1678        - free -  (839K)

在新磁盘的新分区上创建了一个文件系统:

# newfs -U /dev/ada1p1

一个空目录被创建为 mountpoint,用于在原始磁盘的文件系统中挂载新的磁盘:

# mkdir /newdisk

最后,将一个条目添加到 /etc/fstab 文件中,以便新的磁盘在启动时自动挂载:

/dev/ada1p1	/newdisk	ufs	rw	2	2

新的磁盘可以手动挂载,无需重新启动系统:

# mount /newdisk

20.3. 调整和扩展磁盘大小

磁盘的容量可以增加而不影响已有的数据。这在虚拟机中经常发生,当虚拟磁盘太小而需要扩大时。有时候,磁盘镜像被写入到 USB 存储设备中,但没有使用完整的容量。在这里,我们将描述如何调整或 增加 磁盘内容以利用增加的容量。

通过检查 /var/run/dmesg.boot 来确定要调整大小的磁盘的设备名称。在这个例子中,系统中只有一个 SATA 磁盘,所以该驱动器将显示为 ada0 。

列出磁盘上的分区以查看当前配置:

# gpart show ada0
=>      34  83886013  ada0  GPT  (48G) [CORRUPT]
        34       128     1  freebsd-boot  (64k)
       162  79691648     2  freebsd-ufs  (38G)
  79691810   4194236     3  freebsd-swap  (2G)
  83886046         1        - free -  (512B)

如果磁盘使用 GPT 分区方案进行格式化,可能会显示为 损坏(corrupted),因为 GPT 备份分区表不再位于驱动器的末尾。使用 gpart 修复备份分区表。

# gpart recover ada0
ada0 recovered

现在,磁盘上的额外空间可供新分区使用,或者可以扩展现有分区:

# gpart show ada0
=>       34  102399933  ada0  GPT  (48G)
         34        128     1  freebsd-boot  (64k)
        162   79691648     2  freebsd-ufs  (38G)
   79691810    4194236     3  freebsd-swap  (2G)
   83886046   18513921        - free -  (8.8G)

分区只能调整为连续的空闲空间。在这里,磁盘上的最后一个分区是交换分区,但需要调整大小的是第二个分区。交换分区只包含临时数据,因此可以安全地卸载、删除,然后在调整第二个分区大小后重新创建第三个分区。

禁用交换分区:

# swapoff /dev/ada0p3

从磁盘 ada0 中删除由 -i 标志指定的第三个分区。

# gpart delete -i 3 ada0
ada0p3 deleted
# gpart show ada0
=>       34  102399933  ada0  GPT  (48G)
         34        128     1  freebsd-boot  (64k)
        162   79691648     2  freebsd-ufs  (38G)
   79691810   22708157        - free -  (10G)

在修改挂载文件系统的分区表时存在数据丢失的风险。最好在从 Live CD-ROM 或 USB 设备运行时,对未挂载的文件系统执行以下步骤。然而,如果绝对必要,可以在禁用 GEOM 安全功能后调整挂载的文件系统的大小:

# sysctl kern.geom.debugflags=16

调整分区大小,留出空间以重新创建所需大小的交换分区。使用 -i 指定要调整大小的分区,使用 -s 指定新的所需大小。可选地,使用 -a 控制分区的对齐方式。这仅修改分区的大小。分区中的文件系统将在单独的步骤中扩展。

# gpart resize -i 2 -s 47G -a 4k ada0
ada0p2 resized
# gpart show ada0
=>       34  102399933  ada0  GPT  (48G)
         34        128     1  freebsd-boot  (64k)
        162   98566144     2  freebsd-ufs  (47G)
   98566306    3833661        - free -  (1.8G)

重新创建交换分区并激活它。如果没有使用 -s 指定大小,则使用所有剩余空间。

# gpart add -t freebsd-swap -a 4k ada0
ada0p3 added
# gpart show ada0
=>       34  102399933  ada0  GPT  (48G)
         34        128     1  freebsd-boot  (64k)
        162   98566144     2  freebsd-ufs  (47G)
   98566306    3833661     3  freebsd-swap  (1.8G)
# swapon /dev/ada0p3

将 UFS 文件系统扩展到重新调整大小的分区的新容量。

# growfs /dev/ada0p2
Device is mounted read-write; resizing will result in temporary write suspension for /.
It's strongly recommended to make a backup before growing the file system.
OK to grow file system on /dev/ada0p2, mounted on /, from 38GB to 47GB? [Yes/No] Yes
super-block backups (for fsck -b #) at:
 80781312, 82063552, 83345792, 84628032, 85910272, 87192512, 88474752,
 89756992, 91039232, 92321472, 93603712, 94885952, 96168192, 97450432

如果文件系统是 ZFS ,则通过运行带有 -e 选项的 online 子命令来触发调整大小:

# zpool online -e zroot /dev/ada0p2

分区和其上的文件系统现在已经调整大小,以利用新可用的磁盘空间。

20.4. USB 存储设备

许多外部存储解决方案,如硬盘、USB 闪存驱动器以及 CD 和 DVD 刻录机,使用通用串行总线(USB)。FreeBSD 支持 USB 1.x、2.0 和 3.0 设备。

USB 3.0 支持不兼容一些硬件,包括 Haswell(Lynx Point)芯片组。如果 FreeBSD 启动时出现 failed with error 19 的消息,请在系统 BIOS 中禁用 xHCI/USB3。

对 USB 存储设备的支持已经集成到 GENERIC 内核中。对于自定义内核,请确保以下行在内核配置文件中存在:

device scbus	# SCSI bus (required for ATA/SCSI)
device da	# Direct Access (disks)
device pass	# Passthrough device (direct ATA/SCSI access)
device uhci	# provides USB 1.x support
device ohci	# provides USB 1.x support
device ehci	# provides USB 2.0 support
device xhci	# provides USB 3.0 support
device usb	# USB Bus (required)
device umass	# Disks/Mass storage - Requires scbus and da
device cd	# needed for CD and DVD burners

FreeBSD 使用 umass(4) 驱动程序,该驱动程序使用 SCSI 子系统来访问 USB 存储设备。由于系统将任何 USB 设备视为 SCSI 设备,如果 USB 设备是 CD 或 DVD 刻录机,请在自定义内核配置文件中 不要 包含 device atapicam

本节的其余部分演示了如何验证 FreeBSD 是否识别 USB 存储设备以及如何配置设备以便使用。

20.4.1. 设备配置

为了测试 USB 配置,请插入 USB 设备。使用 dmesg 命令确认驱动器是否出现在系统消息缓冲区中。它应该看起来像这样:

umass0: <STECH Simple Drive, class 0/0, rev 2.00/1.04, addr 3> on usbus0
umass0:  SCSI over Bulk-Only; quirks = 0x0100
umass0:4:0:-1: Attached to scbus4
da0 at umass-sim0 bus 0 scbus4 target 0 lun 0
da0: <STECH Simple Drive 1.04> Fixed Direct Access SCSI-4 device
da0: Serial Number WD-WXE508CAN263
da0: 40.000MB/s transfers
da0: 152627MB (312581808 512 byte sectors: 255H 63S/T 19457C)
da0: quirks=0x2<NO_6_BYTE>

品牌、设备节点(da0)、速度和大小将根据设备而异。

由于 USB 设备被视为 SCSI 设备,可以使用 camcontrol 命令列出连接到系统的 USB 存储设备:

# camcontrol devlist
<STECH Simple Drive 1.04>          at scbus4 target 0 lun 0 (pass3,da0)

另外,可以使用 usbconfig 命令列出设备。有关该命令的更多信息,请参阅 usbconfig(8)

# usbconfig
ugen0.3: <Simple Drive STECH> at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (2mA)

如果设备尚未格式化,请参考 添加磁盘 中的说明,了解如何对 USB 驱动器进行格式化和创建分区的操作。如果驱动器已经带有文件系统,可以使用 “挂载和卸载文件系统” 中的指示,由 root 用户进行挂载。

从安全角度来看,不应该认为通过启用 vfs.usermount 来允许不受信任的用户挂载任意媒体是安全的。大多数文件系统并不具备防范恶意设备的能力。

为了使设备能够以普通用户的身份挂载,一种解决方案是使用 pw(8) 将设备的所有用户都添加到 operator 组中。接下来,通过将以下行添加到 /etc/devfs.rules 来确保 operator 能够读写设备:

[localrules=5]
add path 'da*' mode 0660 group operator

如果系统中还安装了内部 SCSI 硬盘,请将第二行更改如下:

add path 'da[3-9]*' mode 0660 group operator

这将排除前三个 SCSI 磁盘(da0da2)不属于 operator 组。将 3 替换为内部 SCSI 磁盘的数量。有关此文件的更多信息,请参阅 devfs.rules(5)

接下来,在 /etc/rc.conf 文件中启用规则集:

devfs_system_ruleset="localrules"

然后,通过将以下行添加到 /etc/sysctl.conf,指示系统允许普通用户挂载文件系统:

vfs.usermount=1

由于此设置仅在下次重新启动后生效,请使用 sysctl 立即设置此变量:

# sysctl vfs.usermount=1
vfs.usermount: 0 -> 1

最后一步是创建一个目录,用于挂载文件系统。这个目录需要由将要挂载文件系统的用户拥有。一种方法是让 root 用户创建一个由该用户拥有的子目录,例如 /mnt/username 。在下面的示例中,将 username 替换为用户的登录名,将 usergroup 替换为用户的主要组名:

# mkdir /mnt/username
# chown username:usergroup /mnt/username

假设插入了一个 USB 闪存驱动器,并出现了一个设备 /dev/da0s1。如果该设备使用 FAT 文件系统格式化,用户可以使用以下命令挂载它:

% mount -t msdosfs -o -m=644,-M=755 /dev/da0s1 /mnt/username

在设备被拔出之前,必须首先卸载设备:

% umount /mnt/username

设备移除后,系统消息缓冲区将显示类似以下的消息:

umass0: at uhub3, port 2, addr 3 (disconnected)
da0 at umass-sim0 bus 0 scbus4 target 0 lun 0
da0: <STECH Simple Drive 1.04> s/n WD-WXE508CAN263          detached
(da0:umass-sim0:0:0:0): Periph destroyed

20.4.2. 自动挂载可移动介质

取消注释 /etc/auto_master 中的这行代码可以自动挂载 USB 设备:

/media		-media		-nosuid

然后将以下行添加到 /etc/devd.conf 文件中:

notify 100 {
	match "system" "GEOM";
	match "subsystem" "DEV";
	action "/usr/sbin/automount -c";
};

如果 autofs(5)devd(8) 已经在运行,请重新加载配置。

# service automount restart
# service devd restart

autofs(5) 可以通过将以下行添加到 /etc/rc.conf 来设置在启动时启动:

autofs_enable="YES"

autofs(5) 要求启用 devd(8),默认情况下它是启用的。

立即启动服务:

# service automount start
# service automountd start
# service autounmountd start
# service devd start

每个可以自动挂载的文件系统都会在 /media/ 中以目录的形式显示。该目录的名称与文件系统的标签相同。如果标签缺失,则目录的名称与设备节点相同。

文件系统在第一次访问时透明地挂载,并在一段时间的不活动后卸载。自动挂载的驱动器也可以手动卸载:

# automount -fu

这种机制通常用于存储卡和 USB 存储设备。它可以与任何块设备一起使用,包括光驱或 iSCSI 逻辑单元。

20.5. 创建和使用 CD 媒体

紧凑型光盘(CD)介质具有一些与传统磁盘不同的特点。它们被设计成可以连续读取,无需在轨道之间移动磁头造成延迟。虽然 CD 介质确实有轨道,但这些轨道指的是要连续读取的数据部分,而不是磁盘的物理属性。ISO 9660 文件系统是为处理这些差异而设计的。

FreeBSD Ports Collection 提供了几个用于刻录和复制音频和数据 CD 的实用工具。本章演示了几个命令行实用程序的使用方法。如果需要带有图形界面的 CD 刻录软件,请考虑安装 sysutils/xcdroastsysutils/k3b 包或 ports。

20.5.1. 支持的设备

GENERIC 内核提供了对 SCSI、USB 和 ATAPICD 读写器的支持。如果使用自定义内核,则需要在内核配置文件中根据设备类型添加相应的选项。

对于 SCSI 刻录机,请确保以下选项存在:

device scbus	# SCSI bus (required for ATA/SCSI)
device da	# Direct Access (disks)
device pass	# Passthrough device (direct ATA/SCSI access)
device cd	# needed for CD and DVD burners

对于一个 USB 刻录机,确保以下选项存在:

device scbus	# SCSI bus (required for ATA/SCSI)
device da	# Direct Access (disks)
device pass	# Passthrough device (direct ATA/SCSI access)
device cd	# needed for CD and DVD burners
device uhci	# provides USB 1.x support
device ohci	# provides USB 1.x support
device ehci	# provides USB 2.0 support
device xhci	# provides USB 3.0 support
device usb	# USB Bus (required)
device umass	# Disks/Mass storage - Requires scbus and da

对于一个 ATAPI 刻录机,请确保以下选项存在:

device ata	# Legacy ATA/SATA controllers
device scbus	# SCSI bus (required for ATA/SCSI)
device pass	# Passthrough device (direct ATA/SCSI access)
device cd	# needed for CD and DVD burners

在 FreeBSD 10.x 之前的版本中,如果刻录机是 ATAPI 设备,则还需要在内核配置文件中添加此行:

device atapicam

或者,可以通过在 /boot/loader.conf 中添加以下行来在启动时加载此驱动程序:

atapicam_load="YES"

这将需要系统重新启动,因为这个驱动程序只能在启动时加载。

要验证 FreeBSD 是否识别设备,请运行 dmesg 命令并查找设备的条目。在 10.x 之前的系统中,输出的第一行中设备名称将是 acd0,而不是 cd0

% dmesg | grep cd
cd0 at ahcich1 bus 0 scbus1 target 0 lun 0
cd0: <HL-DT-ST DVDRAM GU70N LT20> Removable CD-ROM SCSI-0 device
cd0: Serial Number M3OD3S34152
cd0: 150.000MB/s transfers (SATA 1.x, UDMA6, ATAPI 12bytes, PIO 8192bytes)
cd0: Attempt to query device size failed: NOT READY, Medium not present - tray closed

20.5.2. 刻录光盘

在 FreeBSD 中,可以使用 cdrecord 来刻录光盘。这个命令是通过 sysutils/cdrtools 包或端口安装的。

虽然 cdrecord 有很多选项,但基本用法很简单。只需指定要刻录的 ISO 文件的名称,如果系统有多个刻录设备,则还需指定要使用的设备的名称:

# cdrecord dev=device imagefile.iso

要确定刻录机的设备名称,请使用 -scanbus 命令,可能会产生如下结果:

# cdrecord -scanbus
ProDVD-ProBD-Clone 3.00 (amd64-unknown-freebsd10.0) Copyright (C) 1995-2010 Jörg Schilling
Using libscg version 'schily-0.9'
scsibus0:
        0,0,0     0) 'SEAGATE ' 'ST39236LW       ' '0004' Disk
        0,1,0     1) 'SEAGATE ' 'ST39173W        ' '5958' Disk
        0,2,0     2) *
        0,3,0     3) 'iomega  ' 'jaz 1GB         ' 'J.86' Removable Disk
        0,4,0     4) 'NEC     ' 'CD-ROM DRIVE:466' '1.26' Removable CD-ROM
        0,5,0     5) *
        0,6,0     6) *
        0,7,0     7) *
scsibus1:
        1,0,0   100) *
        1,1,0   101) *
        1,2,0   102) *
        1,3,0   103) *
        1,4,0   104) *
        1,5,0   105) 'YAMAHA  ' 'CRW4260         ' '1.0q' Removable CD-ROM
        1,6,0   106) 'ARTEC   ' 'AM12S           ' '1.06' Scanner
        1,7,0   107) *

找到 CD 刻录机的条目,并使用逗号分隔的三个数字作为 dev 的值。在这种情况下,Yamaha 刻录机设备是 1,5,0 ,因此指定该设备的适当输入是 dev = 1,5,0。请参考 cdrecord 的手册页面,了解其他指定该值的方法以及有关写入音轨和控制写入速度的信息。

或者,运行以下命令以获取刻录机的设备地址:

# camcontrol devlist
<MATSHITA CDRW/DVD UJDA740 1.00>   at scbus1 target 0 lun 0 (cd0,pass0)

使用 scbustargetlun 的数值。对于这个例子,1,0,0 是要使用的设备名称。

20.5.3. 将数据写入 ISO 文件系统

为了制作数据光盘,必须在将数据文件刻录到光盘之前对其进行准备。在 FreeBSD 中,安装了 mkisofssysutils/cdrtools 可以用来生成一个 ISO 9660 文件系统,该文件系统是 UNIX® 文件系统中目录树的镜像。最简单的用法是指定要创建的 ISO 文件的名称和要放入 ISO 9660 文件系统的文件路径:

# mkisofs -o imagefile.iso /path/to/tree

该命令将指定路径中的文件名映射为符合标准 ISO 9660 文件系统限制的名称,并且将排除不符合 ISO 文件系统标准的文件。

有多种选项可用于克服标准所施加的限制。特别地,-R 启用了在 UNIX® 系统中常见的 Rock Ridge 扩展,而 -J 启用了 Microsoft® 系统中使用的 Joliet 扩展。

对于仅在 FreeBSD 系统上使用的 CD,可以使用 -U 来禁用所有文件名限制。当与 -R 一起使用时,它会生成一个文件系统镜像,即使违反 ISO 9660 标准,也与指定的 FreeBSD 树完全相同。

通用用途的最后一个选项是 -b。它用于指定用于生成 “El Torito” 可引导 CD 的引导映像的位置。此选项接受一个参数,即从要写入 CD 的树的顶部到引导映像的路径。默认情况下,mkisofs 以“软盘仿真(floppy disk emulation)”模式创建 ISO 映像,因此期望引导映像的大小为 1200、1440 或 2880 KB。某些引导加载程序(如 FreeBSD 发行版媒体使用的加载程序)不使用仿真模式。在这种情况下,应使用 -no-emul-boot 选项。因此,如果 /tmp/myboot 中包含一个可引导的 FreeBSD 系统,并且引导映像位于 /tmp/myboot/boot/cdboot 中,此命令将生成 /tmp/bootable.iso

# mkisofs -R -no-emul-boot -b boot/cdboot -o /tmp/bootable.iso /tmp/myboot

生成的 ISO 镜像可以通过以下方式挂载为内存磁盘:

# mdconfig -a -t vnode -f /tmp/bootable.iso -u 0
# mount -t cd9660 /dev/md0 /mnt

然后可以验证 /mnt/tmp/myboot 是相同的。

有许多其他选项可用于细调 mkisofs 的行为。有关详细信息,请参阅 mkisofs(8)

可以将数据光盘复制到一个与使用 mkisofs 创建的镜像文件在功能上等效的镜像文件中。要做到这一点,使用 dd 命令,将设备名称作为输入文件,将要创建的 ISO 文件的名称作为输出文件:

# dd if=/dev/cd0 of=file.iso bs=2048

生成的图像文件可以按照 刻录光盘 中描述的方式刻录到 CD 上。

20.5.4. 使用数据光盘

一旦 ISO 文件被刻录到光盘上,可以通过指定文件系统类型、包含光盘的设备名称和已存在的挂载点来挂载。

# mount -t cd9660 /dev/cd0 /mnt

由于 mount 假设文件系统的类型是 ufs,如果在挂载数据光盘时没有包含 -t cd9660,将会出现 Incorrect super block 错误。

虽然任何数据 CD 都可以通过这种方式挂载,但带有特定 ISO 9660 扩展的光盘可能会表现出奇怪的行为。例如,Joliet 光盘将所有文件名存储为两个字节的 Unicode 字符。如果一些非英文字符显示为问号,请使用 -C 参数指定本地字符集。有关更多信息,请参考 mount_cd9660(8)

为了使用 -C 选项进行字符转换,内核需要加载 cd9660_iconv.ko 模块。可以通过将以下行添加到 loader.conf 来实现:

cd9660_iconv_load="YES"

然后重新启动机器,或通过使用 kldload 命令直接加载模块。

在尝试挂载数据光盘时,有时会显示 设备未配置(Device not configured)。这通常意味着光驱没有检测到托盘中的光盘,或者该驱动器在总线上不可见。光驱可能需要几秒钟的时间来检测媒体,请耐心等待。

有时候,SCSICD 驱动器可能会被忽略,因为它没有足够的时间来回应总线复位。为了解决这个问题,可以创建一个自定义内核,增加默认的 SCSI 延迟。将以下选项添加到自定义内核配置文件中,并按照 “构建和安装自定义内核” 中的说明重新构建内核。

options SCSI_DELAY=15000

这将在启动过程中告诉 SCSI 总线暂停 15 秒,以便给 CD 驱动器尽可能多的机会来响应总线复位。

可以直接将文件刻录到光盘上,而无需创建 ISO 9660 文件系统。这被称为刻录原始数据光盘,有些人出于备份目的这样做。

这种类型的光盘不能像普通数据光盘一样挂载。为了获取烧录到这种光盘上的数据,必须从原始设备节点读取数据。例如,以下命令将从第二个光盘设备中提取一个压缩的 tar 文件到当前工作目录:

# tar xzvf /dev/cd1

为了挂载数据光盘,数据必须使用 mkisofs 进行写入。

20.5.5. 复制音频 CDs

要复制音频 CD,需要从 CD 中提取音频数据到一系列文件中,然后将这些文件写入空白 CD。

步骤:复制音频 CD 描述了如何复制和刻录音频 CD。如果 FreeBSD 版本小于 10.0 且设备为 ATAPI,必须首先使用 支持的设备 中的说明加载 atapicam 模块。

步骤:复制音频 CD
  1. sysutils/cdrtools 包或 port 安装了 cdda2wav。此命令可用于提取所有音轨,每个音轨都会被写入当前工作目录中的单独的 WAV 文件中:

    % cdda2wav -vall -B -Owav

    如果系统上只有一个 CD 设备,则不需要指定设备名称。请参考 cdda2wav 手册页面,了解如何指定设备以及了解此命令的其他可用选项。

  2. 使用 cdrecord 命令来写入 .wav 文件:

    % cdrecord -v dev=2,0 -dao -useinfo  *.wav

    请确保按照 刻录光盘 中描述的方式适当设置 2,0

20.6. 创建和使用 DVD 媒体

与 CD 相比,DVD 是下一代光学媒体存储技术。DVD 可以容纳比任何 CD 更多的数据,并且是视频出版的标准。

可为可记录的 DVD 定义五种物理可记录格式:

  • DVD-R:这是第一个可用的 DVD 可记录格式。DVD-R 标准由 DVD 论坛定义。这种格式只能写入一次。

  • DVD-RW:这是 DVD-R 标准的可重写版本。一个 DVD-RW 可以重写约 1000 次。

  • DVD-RAM:这是一种可重写的格式,可以看作是可移动硬盘。然而,这种介质与大多数 DVD-ROM 驱动器和 DVD 视频播放器不兼容,因为只有少数 DVD 刻录机支持 DVD-RAM 格式。有关 DVD-RAM 使用的更多信息,请参阅 使用 DVD-RAM

  • DVD+RW :这是由 DVD+RW 联盟 定义的可重写格式。DVD+RW 可以重写约 1000 次。

  • DVD+R:这种格式是 DVD+RW 格式的一次写入变体。

一张单层可记录的 DVD 可以容纳高达 4,700,000,000 字节,实际上相当于 4.38 GB 或 4485 MB,因为 1 千字节等于 1024 字节。

必须区分物理介质和应用程序。例如,DVD-Video 是一种特定的文件布局,可以写入任何可记录的 DVD 物理介质,如 DVD-R、DVD+R 或 DVD-RW。在选择介质之前,请确保刻录机和 DVD-Video 播放器与所考虑的介质兼容。

20.6.1. 配置

要进行 DVD 录制,请使用 growisofs(1) 命令。该命令是 sysutils/dvd+rw-tools 工具包的一部分,支持所有 DVD 媒体类型。

这些工具使用 SCSI 子系统来访问设备,因此必须加载或静态编译 ATAPI/CAM support 到内核中。如果刻录机使用 USB 接口,则不需要此支持。有关 USB 设备配置的更多详细信息,请参阅 USB 存储设备

还必须为 ATAPI 设备启用 DMA 访问,方法是在 /boot/loader.conf 中添加以下行:

hw.ata.atapi_dma="1"

在尝试使用 dvd+rw-tools 之前,请参考 硬件兼容性说明

对于图形用户界面,请考虑使用 sysutils/k3b,它提供了一个用户友好的界面来使用 growisofs(1) 和许多其他刻录工具。

20.6.2. 刻录数据 DVD

由于 growisofs(1)mkisofs 的前端,它将调用 mkisofs(8) 来创建文件系统布局并在 DVD 上执行写入操作。这意味着在刻录过程之前不需要创建数据的镜像。

要将位于 /path/to/data 的数据刻录到 DVD+R 或 DVD-R 上,请使用以下命令:

# growisofs -dvd-compat -Z /dev/cd0 -J -R /path/to/data

在这个例子中,-J -R 被传递给 mkisofs(8) 以创建一个带有 Joliet 和 Rock Ridge 扩展的 ISO 9660 文件系统。更多详细信息请参考 mkisofs(8)

对于初始会话录制,-Z 用于单个和多个会话。将 /dev/cd0 替换为 DVD 设备的名称。使用 -dvd-compat 表示光盘将被关闭,并且录制将无法追加。这还应该提供更好的与 DVD-ROM 驱动器的媒体兼容性。

要烧录预制的镜像,比如 imagefile.iso,请使用以下命令:

# growisofs -dvd-compat -Z /dev/cd0=imagefile.iso

应该检测并根据使用的媒体和驱动器自动设置写入速度。要强制设置写入速度,请使用 -speed=。有关示例用法,请参考 growisofs(1)

为了支持大于 4.38GB 的工作文件,必须通过在 mkisofs(8) 和所有相关程序(如 growisofs(1) )中传递 -udf -iso-level 3 来创建一个 UDF/ISO-9660 混合文件系统。只有在创建 ISO 映像文件或直接将文件写入磁盘时才需要这样做。由于以这种方式创建的磁盘必须以 mount_udf(8) 的 UDF 文件系统方式挂载,因此它只能在支持 UDF 的操作系统上使用。否则,它将看起来像包含损坏文件。

要创建这种类型的 ISO 文件:

% mkisofs -R -J -udf -iso-level 3 -o imagefile.iso /path/to/data

直接将文件刻录到光盘:

# growisofs -dvd-compat -udf -iso-level 3 -Z /dev/cd0 -J -R /path/to/data

当 ISO 镜像已经包含大文件时,growisofs(1) 在将该镜像刻录到光盘上时不需要额外的选项。

请确保使用最新版本的 sysutils/cdrtools,其中包含 mkisofs(8),因为旧版本可能不支持大文件。如果最新版本无法工作,请安装 sysutils/cdrtools-devel 并阅读其 mkisofs(8)

20.6.3. 刻录 DVD 视频

DVD-Video 是基于 ISO 9660 和微型 UDF(M-UDF)规范的特定文件布局。由于 DVD-Video 呈现了特定的数据结构层次,因此需要使用特定的程序,如 multimedia/dvdauthor 来制作 DVD。

如果已经存在 DVD-Video 文件系统的镜像,可以像其他镜像一样进行刻录。如果使用了 dvdauthor 制作了 DVD,并且结果保存在 /path/to/video 中,应使用以下命令来刻录 DVD-Video:

# growisofs -Z /dev/cd0 -dvd-video /path/to/video

-dvd-video 被传递给 mkisofs(8),用于指示它创建一个 DVD-Video 文件系统布局。此选项隐含了 -dvd-compat growisofs(1) 选项。

20.6.4. 使用 DVD+RW

与 CD-RW 不同,未使用过的 DVD+RW 需要在首次使用前进行格式化。强烈建议使用 growisofs(1) 在适当时自动处理此操作。然而,也可以使用 dvd+rw-format 来格式化 DVD+RW:

# dvd+rw-format /dev/cd0

只需执行此操作一次,并记住只有全新的 DVD+RW 光盘需要进行格式化。一旦格式化完成,DVD+RW 光盘可以像往常一样进行刻录。

要烧录一个全新的文件系统,而不仅仅是将一些数据追加到 DVD+RW 上,媒体不需要先进行擦除。相反,可以像这样覆盖之前的记录:

# growisofs -Z /dev/cd0 -J -R /path/to/newdata

DVD+RW 格式支持在之前的记录上追加数据。这个操作包括将新的会话合并到现有的会话中,因为它不被视为多会话写入。growisofs(1) 将会 增长 媒体上存在的 ISO 9660 文件系统。

例如,要将数据追加到 DVD+RW 上,请使用以下方法:

# growisofs -M /dev/cd0 -J -R /path/to/nextdata

在进行下一次写入时,应使用与烧录初始会话时相同的 mkisofs[8] 选项。

使用 -dvd-compat 选项可以提高与 DVD-ROM 驱动器的媒体兼容性。当使用 DVD+RW 时,此选项不会阻止添加数据。

要清空媒体,请使用以下方法:

# growisofs -Z /dev/cd0=/dev/zero

20.6.5. 使用 DVD-RW

DVD-RW 支持两种光盘格式:增量顺序和受限覆写。默认情况下,DVD-RW 光盘采用顺序格式。

一个全新的 DVD-RW 可以直接写入而无需进行格式化。然而,一个已经使用过的顺序格式的 DVD-RW 在写入新的初始会话之前需要进行擦除。

要以顺序模式擦除 DVD-RW:

# dvd+rw-format -blank=full /dev/cd0

使用 -blank=full 进行完全擦除在 1 倍速的媒体上大约需要一个小时。如果要在 Disk-At-Once (DAO)模式下记录 DVD-RW,则可以使用 -blank 进行快速擦除。要以 DAO 模式刻录 DVD-RW,请使用以下命令:

# growisofs -use-the-force-luke=dao -Z /dev/cd0=imagefile.iso

由于 growisofs(1) 会自动尝试检测快速擦除的介质并启用 DAO 写入,因此不需要使用 -use-the-force-luke=dao 参数。

对于任何 DVD-RW,应该使用受限覆盖模式,而不是默认的增量顺序模式,因为受限覆盖模式更加灵活。

要在顺序 DVD-RW 上写入数据,使用与其他 DVD 格式相同的指令:

# growisofs -Z /dev/cd0 -J -R /path/to/data

要将一些数据追加到先前的录制中,请使用 -M 参数和 growisofs(1) 命令。然而,如果在增量顺序模式下在 DVD-RW 上追加数据,将会在光盘上创建一个新的会话,结果将是一个多会话光盘。

在受限覆写格式的 DVD-RW 上,不需要在开始新的初始会话之前将其擦除。相反,可以使用 -Z 来覆盖光盘。还可以使用 -M 来扩展已写入光盘上的现有 ISO 9660 文件系统。结果将是一个单会话的 DVD。

要将 DVD-RW 格式化为受限覆写格式,必须使用以下命令:

# dvd+rw-format /dev/cd0

要切换回顺序格式,请使用:

# dvd+rw-format -blank=full /dev/cd0

20.6.6. 多会话

很少有 DVD-ROM 驱动器支持多会话 DVD,并且大多数情况下只能读取第一个会话。 DVD+R、DVD-R 和 DVD-RW 以顺序格式可以接受多个会话。对于 DVD+RW 和 DVD-RW 受限覆写格式,不存在多个会话的概念。

在使用 DVD+R、DVD-R 或 DVD-RW 顺序格式的初始非关闭会话后,使用以下命令将在光盘上添加一个新的会话:

# growisofs -M /dev/cd0 -J -R /path/to/nextdata

在使用此命令时,如果使用 DVD+RW 或 DVD-RW 处于受限覆写模式,将会在将新会话合并到现有会话时追加数据。结果将是一个单会话光盘。使用此方法在这些类型的介质上进行初始写入后添加数据。

由于在每个会话之间使用了一些空间来标记会话的结束和开始,因此应该添加大量数据的会话以优化媒体空间。 DVD+R 的会话数量限制为 154 个, DVD-R 约为 2000 个,DVD + R 双层为 127 个。

20.6.7. 更多信息请参考

要获取有关 DVD 的更多信息,请在指定的驱动器中使用 dvd+rw-mediainfo /dev/cd0 命令,同时光盘在其中。

有关 dvd+rw-tools 的更多信息可以在 growisofs(1) 中找到,在 dvd+rw-tools 网站 上找到,并且在 cdwrite 邮件列表 的存档中也可以找到。

创建与使用 dvd+rw-tools 相关的问题报告时,始终包括 dvd+rw-mediainfo 的输出。

20.6.8. 使用 DVD-RAM

DVD-RAM 写入器可以使用 SCSI 或 ATAPI 接口。对于 ATAPI 设备,必须通过在 /boot/loader.conf 中添加以下行来启用 DMA 访问:

hw.ata.atapi_dma="1"

DVD-RAM 可以被视为可移动硬盘。与任何其他硬盘一样, DVD-RAM 在使用之前必须进行格式化。在这个例子中,整个磁盘空间将使用标准的 UFS2 文件系统进行格式化:

# dd if=/dev/zero of=/dev/acd0 bs=2k count=1
# bsdlabel -Bw acd0
# newfs /dev/acd0

DVD 设备 acd0 必须根据配置进行更改。

一旦 DVD-RAM 被格式化,它可以被挂载为普通硬盘:

# mount /dev/acd0 /mnt

一旦挂载,DVD-RAM 将可读可写。

20.7. 创建和使用软盘

本节介绍了如何在 FreeBSD 中格式化 3.5 英寸软盘。

步骤:格式化软盘的步骤

在使用软盘之前,需要进行低级格式化。通常由供应商完成,但格式化是检查介质完整性的好方法。在 FreeBSD 上进行软盘的低级格式化,可以使用 fdformat(1) 命令。在使用此实用程序时,请注意任何错误消息,因为它们可以帮助确定软盘是好的还是坏的。

  1. 要格式化软盘,请将一个新的 3.5 英寸软盘插入第一个软盘驱动器,并输入以下命令:

    # /usr/sbin/fdformat -f 1440 /dev/fd0
  2. 在低级格式化磁盘之后,根据系统需要创建磁盘标签,以确定磁盘的大小和几何结构。支持的几何结构值在 /etc/disktab 中列出。

    要编写磁盘标签,请使用 bsdlabel(8)

    # /sbin/bsdlabel -B -w /dev/fd0 fd1440
  3. 软盘现在可以进行高级格式化,并选择文件系统。软盘的文件系统可以是 UFS 或 FAT,其中 FAT 通常是软盘的更好选择。

    要使用 FAT 格式化软盘,请执行以下操作:

    # /sbin/newfs_msdos /dev/fd0

磁盘现在已经准备好供使用。要使用软盘,请使用 mount_msdosfs(8) 命令进行挂载。也可以从 Ports Collection 安装和使用 emulators/mtools

20.8. 使用 NTFS 磁盘

本节介绍了如何在 FreeBSD 中挂载 NTFS 磁盘。

NTFS(新技术文件系统)是由微软开发的专有日志文件系统。多年来,它一直是微软 Windows 操作系统的默认文件系统。FreeBSD 可以使用 FUSE 文件系统挂载 NTFS 卷。这些文件系统是作为用户空间程序实现的,它们通过一个明确定义的接口与 fusefs(5) 内核模块进行交互。

过程:挂载 NTFS 磁盘的步骤

  1. 在使用 FUSE 文件系统之前,我们需要加载 fusefs(5) 内核模块:

    # kldload fusefs

    使用 sysrc(8) 命令在启动时加载模块:

    # sysrc kld_list+=fusefs
  2. 按照示例中的方式(参见 使用 pkg 进行二进制包管理)或者从 ports(参见 使用 Ports Collection)安装实际的 NTFS 文件系统。

    # pkg install fusefs-ntfs
  3. 最后,我们需要创建一个目录,用于挂载文件系统:

    # mkdir /mnt/usb
  4. 假设插入了一个 USB 磁盘。可以使用 gpart(8) 命令查看磁盘分区信息。

    # gpart show da0
    =>	  63  1953525105  da0 MBR   (932G)
    	  63  1953525105    1 ntfs  (932G)
  5. 我们可以使用以下命令挂载磁盘:

    # ntfs-3g /dev/da0s1 /mnt/usb/

    磁盘现已准备就绪,可以使用。

  6. 此外,还可以将条目添加到 /etc/fstab 文件中:

    /dev/da0s1  /mnt/usb	ntfs mountprog=/usr/local/bin/ntfs-3g,noauto,rw  0 0

    现在可以使用以下命令挂载磁盘:

    # mount /mnt/usb
  7. 可以使用以下命令卸载磁盘:

    # umount /mnt/usb/

20.9. 备份基础知识

实施备份计划是至关重要的,以便能够从磁盘故障、意外文件删除、随机文件损坏或完全机器破坏(包括现场备份的破坏)中恢复。

备份类型和计划将根据数据的重要性、文件恢复所需的粒度以及可接受的停机时间而有所不同。一些可能的备份技术包括:

  • 整个系统的归档备份存储在永久的、离线的介质上。这种方式可以提供对上述所有问题的保护,但是恢复速度慢且不方便,特别是对于非特权用户来说。

  • 文件系统快照,用于恢复已删除的文件或文件的先前版本。

  • 使用计划 net/rsync,将整个文件系统或磁盘的副本与网络上的另一个系统进行同步。

  • 硬件或软件 RAID,可以在磁盘故障时最小化或避免停机时间。

通常,会使用多种备份技术的组合。例如,可以创建一个定期计划,自动进行每周一次的完整系统备份,并将其存储在离线位置,并通过每小时的 ZFS 快照来补充此备份。此外,在进行文件编辑或删除之前,还可以对单个目录或文件进行手动备份。

本节介绍了一些可用于在 FreeBSD 系统上创建和管理备份的实用工具。

20.9.1. 文件系统备份

传统的 UNIX® 文件系统备份程序是 dump(8),用于创建备份,和 restore(8),用于恢复备份。这些工具在文件系统创建的文件、链接和目录的抽象层之下的磁盘块级别上工作。与其他备份软件不同,dump 备份整个文件系统,无法备份部分文件系统或跨多个文件系统的目录树的一部分。dump 不是写入文件和目录,而是写入组成文件和目录的原始数据块。

如果在根目录上使用 dump 命令,它将不会备份 /home/usr 或许多其他目录,因为这些通常是其他文件系统的挂载点或指向这些文件系统的符号链接。

当用于恢复数据时,默认情况下,restore 将临时文件存储在 /tmp/ 中。如果使用具有较小 /tmp 的恢复磁盘,请将 TMPDIR 设置为具有更多可用空间的目录,以确保恢复成功。

在使用 dump 命令时,请注意一些来自 AT&T UNIX® 6 版本(约 1975 年)早期的怪异行为。默认参数假设备份是备份到 9 轨磁带,而不是备份到其他类型的介质或者今天可用的高密度磁带。这些默认值必须在命令行上进行覆盖。

可以通过网络将文件系统备份到另一个系统或连接到另一台计算机的磁带驱动器上。虽然可以使用 rdump(8)rrestore(8) 工具来实现此目的,但它们被认为不安全。

相反,可以使用 dumprestore 以更安全的方式通过 SSH 连接进行操作。此示例创建了一个对 /usr 目录进行完整压缩备份的文件,并通过 SSH 连接将备份文件发送到指定的主机。

例 1. 通过 ssh 使用 dump 命令
# /sbin/dump -0uan -f - /usr | gzip -2 | ssh -c blowfish \
          [email protected] dd of=/mybigfiles/dump-usr-l0.gz

这个示例设置 RSH,以便通过 SSH 连接将备份写入远程系统上的磁带驱动器:

例 2. 使用 RSH 设置通过 ssh 使用 dump 命令
# env RSH=/usr/bin/ssh /sbin/dump -0uan -f [email protected]:/dev/sa0 /usr

20.9.2. 目录备份

可以根据需要使用几个内置实用程序来备份和恢复指定的文件和目录。

备份目录中所有文件的一个好选择是 tar(1)。这个实用程序可以追溯到 AT&T UNIX® 的第 6 版,并且默认情况下假定对本地磁带设备进行递归备份。可以使用开关来指定备份文件的名称。

这个例子创建了一个压缩的备份文件,将当前目录的内容保存到 /tmp/mybackup.tgz 文件中。在创建备份文件时,请确保备份文件不要保存在被备份的目录中。

例 3. 使用 tar 备份当前目录
# tar czvf /tmp/mybackup.tgz .

要恢复整个备份,请进入要恢复的目录并指定备份的名称。请注意,这将覆盖恢复目录中的任何更新版本的文件。如果不确定,请恢复到一个临时目录或指定要恢复的备份中的文件名称。

例 4. 使用 tar 命令恢复当前目录
# tar xzvf /tmp/mybackup.tgz

有数十个可用的开关,这些开关在 tar(1) 中有描述。该实用程序还支持使用排除模式来指定在备份指定目录或从备份中恢复文件时不应包括哪些文件。

要使用指定的文件和目录列表创建备份,cpio(1) 是一个不错的选择。与 tar 不同,cpio 不知道如何遍历目录树,必须提供备份文件的列表。

例如,可以使用 lsfind 创建文件列表。此示例创建了当前目录的递归列表,然后将其通过管道传输给 cpio,以创建一个名为 /tmp/mybackup.cpio 的输出备份文件。

例 5. 使用 lscpio 来对当前目录进行递归备份
# ls -R | cpio -ovF /tmp/mybackup.cpio

一种备份工具,试图结合 tarcpio 提供的功能是 pax(1)。多年来,各个版本的 tarcpio 变得稍微不兼容。 POSIX® 创建了 pax,它尝试读取和写入许多不同的 cpiotar 格式,以及自己的新格式。

前面示例的 pax 等效方式如下:

例 6. 使用 pax 备份当前目录
# pax -wf /tmp/mybackup.pax .

20.9.3. 使用数据磁带进行备份

尽管磁带技术不断发展,但现代备份系统往往将离线备份与本地可移动介质相结合。FreeBSD 支持使用 SCSI 的任何磁带驱动器,如 LTO 或 DAT。对于 SATA 和 USB 磁带驱动器的支持有限。

对于 SCSI 磁带设备,FreeBSD 使用 sa(4) 驱动程序和 /dev/sa0/dev/nsa0/dev/esa0 设备。物理设备名称是 /dev/sa0。当使用 /dev/nsa0 时,备份应用程序在写入文件后不会倒回磁带,这允许将多个文件写入磁带。使用 /dev/esa0 在设备关闭后弹出磁带。

在 FreeBSD 中,mt 用于控制磁带驱动器的操作,例如在磁带上寻找文件或向磁带写入磁带控制标记。例如,在写入新文件之前,可以通过跳过前三个文件来保留磁带上的文件。

# mt -f /dev/nsa0 fsf 3

该实用程序支持许多操作。有关详细信息,请参阅 mt(1)

使用 tar 将单个文件写入磁带,需要指定磁带设备的名称和要备份的文件:

# tar cvf /dev/sa0 file

将文件从磁带上的 tar 归档恢复到当前目录:

# tar xvf /dev/sa0

要备份 UFS 文件系统,请使用 dump 命令。以下示例备份了 /usr 目录,备份完成后不会倒回磁带:

# dump -0aL -b64 -f /dev/nsa0 /usr

要从磁带上的 dump 文件交互式地恢复文件到当前目录:

# restore -i -f /dev/nsa0

20.9.4. 第三方备份工具

FreeBSD Ports Collection 提供了许多第三方工具,可以用于安排备份的创建、简化磁带备份,并使备份更加方便。其中许多应用程序是基于客户端/服务器的,可以用于自动化单个系统或网络中所有计算机的备份。

常用的工具包括 Amanda、Bacula、rsync 和 duplicity。

20.9.5. 紧急恢复

除了定期备份外,建议在紧急应急计划中执行以下步骤。

创建以下命令的输出的打印副本:

  • gpart show

  • more /etc/fstab

  • dmesg

将这份打印件和安装介质的副本存放在安全的地方。如果需要进行紧急恢复操作,启动安装介质并选择 Live CD 以访问救援 Shell。这个救援模式可以用来查看系统的当前状态,如果需要的话,还可以重新格式化磁盘并从备份中恢复数据。

接下来,测试救援 shell 和备份。记录下操作步骤,并将这些记录与介质、打印件和备份一起存储。这些记录可以防止在紧急恢复过程中因压力而意外破坏备份。

为了增加安全性,将最新的备份存储在与计算机和磁盘驱动器相隔一定距离的远程位置。

20.10. 内存磁盘

除了物理磁盘外,FreeBSD 还支持创建和使用内存磁盘。内存磁盘的一个可能用途是在不先将其刻录到 CD 或 DVD 上,然后挂载 CD/DVD 媒体的情况下访问 ISO 文件系统的内容。

在 FreeBSD 中,md(4) 驱动程序用于提供对内存磁盘的支持。GENERIC 内核包含了这个驱动程序。当使用自定义内核配置文件时,请确保包含以下行:

device md

20.10.1. 附加和分离现有镜像

要挂载现有的文件系统镜像,使用 mdconfig 命令指定 ISO 文件的名称和一个空闲的设备号。然后,使用该设备号将其挂载到现有的挂载点上。一旦挂载成功,ISO 中的文件将会出现在挂载点上。以下示例将 diskimage.iso 附加到内存设备 /dev/md0,然后将该内存设备挂载到 /mnt

# mdconfig -f diskimage.iso -u 0
# mount -t cd9660 /dev/md0 /mnt

请注意,使用 -t cd9660 来挂载 ISO 格式的文件。如果没有使用 -u 指定设备号,mdconfig 将自动分配一个未使用的内存设备,并输出分配的单元号的名称,例如 md4。有关此命令及其选项的更多详细信息,请参阅 mdconfig(8)

当内存磁盘不再使用时,应该将其资源释放回系统。首先,卸载文件系统,然后使用 mdconfig 将磁盘从系统中分离并释放其资源。继续本示例:

# umount /mnt
# mdconfig -d -u 0

要确定系统是否仍连接有任何内存磁盘,请输入 mdconfig -l

20.10.2. 创建一个基于文件或内存的内存磁盘

FreeBSD 还支持内存磁盘,其中存储空间可以从硬盘或内存区域分配。第一种方法通常称为基于文件的文件系统,第二种方法称为基于内存的文件系统。可以使用 mdconfig 创建这两种类型的磁盘。

要创建一个新的基于内存的文件系统,需要指定 swap 类型和要创建的内存磁盘的大小。然后,像通常一样,对内存磁盘进行文件系统格式化和挂载。以下示例在单位 1 上创建了一个大小为 5M 的内存磁盘。然后,在挂载之前,该内存磁盘将被格式化为 UFS 文件系统:

# mdconfig -a -t swap -s 5m -u 1
# newfs -U md1
/dev/md1: 5.0MB (10240 sectors) block size 16384, fragment size 2048
        using 4 cylinder groups of 1.27MB, 81 blks, 192 inodes.
        with soft updates
super-block backups (for fsck -b #) at:
 160, 2752, 5344, 7936
# mount /dev/md1 /mnt
# df /mnt
Filesystem 1K-blocks Used Avail Capacity  Mounted on
/dev/md1        4718    4  4338     0%    /mnt

要创建一个新的基于文件的内存磁盘,首先需要分配一个磁盘区域来使用。以下示例创建一个名为 newimage 的空白 5MB 文件:

# dd if=/dev/zero of=newimage bs=1k count=5k
5120+0 records in
5120+0 records out

接下来,将该文件附加到一个内存磁盘上,为内存磁盘标记名称并使用 UFS 文件系统进行格式化,挂载内存磁盘,并验证文件支持的磁盘的大小。

# mdconfig -f newimage -u 0
# bsdlabel -w md0 auto
# newfs -U md0a
/dev/md0a: 5.0MB (10224 sectors) block size 16384, fragment size 2048
        using 4 cylinder groups of 1.25MB, 80 blks, 192 inodes.
super-block backups (for fsck -b #) at:
 160, 2720, 5280, 7840
# mount /dev/md0a /mnt
# df /mnt
Filesystem 1K-blocks Used Avail Capacity  Mounted on
/dev/md0a       4710    4  4330     0%    /mnt

使用 mdconfig 命令创建一个基于文件或内存的文件系统需要多个命令。FreeBSD 还提供了 mdmfs 命令,它可以自动配置一个内存磁盘,使用 UFS 文件系统进行格式化,并挂载它。例如,在使用 dd 命令创建了名为 newimage 的文件后,下面这个命令相当于运行上面显示的 bsdlabelnewfsmount 命令:

# mdmfs -F newimage -s 5m md0 /mnt

要使用 mdmfs 创建一个新的基于内存的内存磁盘,只需使用以下命令:

# mdmfs -s 5m md1 /mnt

如果未指定设备号,mdmfs 将自动选择一个未使用的内存设备。有关 mdmfs 的更多详细信息,请参阅 mdmfs(8)

20.11. 文件系统快照

FreeBSD 提供了一个与 Soft Updates 配合使用的功能:文件系统快照。

UFS 快照允许用户创建指定文件系统的镜像,并将其视为文件。快照文件必须在执行操作的文件系统中创建,并且用户每个文件系统最多可以创建 20 个快照。 活动快照在超级块中记录,因此它们在卸载和重新挂载操作以及系统重新启动时是持久的。当不再需要快照时,可以使用 rm(1) 命令将其删除。 尽管可以以任何顺序删除快照,但可能无法获取所有已释放块的使用空间,因为另一个快照可能会占用一些已释放的块。

在创建快照文件后,mksnap_ffs(8) 会设置不可更改的 snapshot 文件标志。unlink(1) 对于快照文件有一个例外,因为它允许将其删除。

使用 mount(8) 创建快照。要将 /var 的快照放置在文件 /var/snapshot/snap 中,请使用以下命令:

# mount -u -o snapshot /var/snapshot/snap /var

或者,使用 mksnap_ffs(8) 命令来创建快照:

# mksnap_ffs /var /var/snapshot/snap

可以使用 find(1) 命令在文件系统上找到快照文件,例如 /var

# find /var -flags snapshot

一旦创建了快照,它可以有多种用途:

  • 一些管理员会使用快照文件进行备份,因为快照可以传输到光盘或磁带上。

  • 文件系统完整性检查器 fsck(8) 可以在快照上运行。假设文件系统在挂载时是干净的,这应该始终提供一个干净且不变的结果。

  • 在快照上运行 dump(8) 将生成一个与文件系统和快照的时间戳一致的转储文件。dump(8) 还可以使用 -L 选项一次性拍摄快照、创建转储镜像并删除快照。

  • 快照可以作为文件系统的冻结镜像进行挂载。要使用 mount(8) 挂载 /var/snapshot/snap 快照,请运行:

    # mdconfig -a -t vnode -o readonly -f /var/snapshot/snap -u 4
    # mount -r /dev/md4 /mnt

冻结的文件 /var 现在可以通过 /mnt 访问。一开始,所有内容都将保持与创建快照时相同的状态。唯一的例外是,任何早期的快照将显示为长度为零的文件。要卸载快照,请使用:

# umount /mnt
# mdconfig -d -u 4

有关 softupdates 和文件系统快照的更多信息,包括技术论文,请访问 Marshall Kirk McKusick’s 的网站:http://www.mckusick.com/[http://www.mckusick.com/]。

20.12. 磁盘配额

磁盘配额可以用于限制用户或用户组在每个文件系统上分配的磁盘空间或文件数量。这可以防止某个用户或用户组占用所有可用的磁盘空间。

本节介绍了如何配置 UFS 文件系统的磁盘配额。要在 ZFS 文件系统上配置配额,请参考 “数据集、用户和组配额”

20.12.1. 启用磁盘配额

要确定 FreeBSD 内核是否支持磁盘配额,请执行以下操作:

% sysctl kern.features.ufs_quota
kern.features.ufs_quota: 1

在这个例子中,1 表示支持配额。如果值是 0,请将以下行添加到自定义内核配置文件中,并按照 配置 FreeBSD 内核 中的说明重新构建内核。

options QUOTA

接下来,在 /etc/rc.conf 中启用磁盘配额:

quota_enable="YES"

通常在启动时,使用 quotacheck(8) 检查每个文件系统的配额完整性。该程序确保配额数据库中的数据正确反映文件系统上的数据。这是一个耗时的过程,会显著影响系统启动所需的时间。要跳过此步骤,请将此变量添加到 /etc/rc.conf 中:

check_quotas="NO"

最后,编辑 /etc/fstab 文件以按文件系统启用磁盘配额。要在文件系统上启用每个用户的配额,请在 /etc/fstab 文件中的文件系统条目的选项字段中添加 userquota。例如:

/dev/da1s2g   /home    ufs rw,userquota 1 2

要启用组配额,请使用 groupquota。要同时启用用户和组配额,请使用逗号分隔选项:

/dev/da1s2g    /home    ufs rw,userquota,groupquota 1 2

默认情况下,配额文件存储在文件系统的根目录中,文件名为 quota.userquota.group。有关更多信息,请参阅 fstab(5)。不建议指定配额文件的替代位置。

配置完成后,重新启动系统,/etc/rc 将自动运行适当的命令,为 /etc/fstab 中启用的所有配额创建初始配额文件。

在正常的操作过程中,通常不需要手动运行 quotacheck(8)quotaon(8)quotaoff(8)。然而,应该阅读这些手册页以熟悉它们的操作。

20.12.2. 设置配额限制

要验证配额是否已启用,请运行以下命令:

# quota -v

对于每个启用了配额的文件系统,应该有一个关于磁盘使用情况和当前配额限制的一行摘要。

系统现在可以使用 edquota 来分配配额限制。

有几种选项可用于限制用户或组分配的磁盘空间量以及他们可以创建的文件数量。分配可以基于磁盘空间(块配额)、文件数量(inode 配额)或两者的组合进行限制。每个限制进一步分为两个类别:硬限制和软限制。

硬限制不能超过。一旦用户达到硬限制,该用户在该文件系统上将无法再进行进一步的分配。例如,如果用户在文件系统上的硬限制是 500 kbytes ,并且当前正在使用 490 kbytes,那么用户只能再分配额外的 10 kbytes。尝试分配额外的 11 kbytes 将失败。

软限制可以在有限的时间内超过,这被称为宽限期,默认为一周。如果用户超过限制的时间超过宽限期,软限制将变为硬限制,不再允许进一步的分配。当用户再次低于软限制时,宽限期将被重置。

在下面的示例中,正在编辑 test 账户的配额。当调用 edquota 时,会打开由 EDITOR 指定的编辑器,以便编辑配额限制。默认编辑器设置为 vi。

# edquota -u test
Quotas for user test:
/usr: kbytes in use: 65, limits (soft = 50, hard = 75)
        inodes in use: 7, limits (soft = 50, hard = 60)
/usr/var: kbytes in use: 0, limits (soft = 50, hard = 75)
        inodes in use: 0, limits (soft = 50, hard = 60)

通常,每个启用了配额的文件系统通常有两行。一行表示块限制,另一行表示 inode 限制。更改值以修改配额限制。例如,要将 /usr 的块限制提高到软限制 500 和硬限制 600,请按照以下方式更改该行中的值:

/usr: kbytes in use: 65, limits (soft = 500, hard = 600)

新的配额限制在退出编辑器后生效。

有时候,对一系列用户设置配额限制是可取的。首先,将所需的配额限制分配给一个用户。然后,使用 -p 选项将该配额复制到指定范围的用户 ID(UID)。以下命令将复制 UID 为 10,00019,999 的用户的配额限制:

# edquota -p test 10000-19999

有关更多信息,请参考 edquota(8)

20.12.3. 检查配额限制和磁盘使用情况

要检查单个用户或组的配额和磁盘使用情况,请使用 quota(1)。用户只能查看自己的配额和所属组的配额。只有超级用户才能查看所有用户和组的配额。要获取启用了配额的文件系统的所有配额和磁盘使用情况的摘要,请使用 repquota(8)

通常情况下,用户没有使用任何磁盘空间的文件系统在 quota 命令的输出中不会显示,即使用户对该文件系统有配额限制。使用 -v 选项可以显示这些文件系统。以下是一个用户在两个文件系统上设置了配额限制时,使用 quota -v 命令的示例输出。

Disk quotas for user test (uid 1002):
     Filesystem  usage    quota   limit   grace   files   quota   limit   grace
           /usr      65*     50      75   5days       7      50      60
       /usr/var       0      50      75               0      50      60

在这个例子中,用户当前超过了在 /usr 目录下的 50 kbytes 的软限制,超出了 15 kbytes,并且还剩下 5 天的宽限期。星号 * 表示用户当前超过了配额限制。

20.12.4. NFS 上的配额限制

配额由 NFS 服务器上的配额子系统强制执行。rpc.rquotad(8) 守护进程将配额信息提供给 NFS 客户端上的 quota 命令,使得这些机器上的用户可以查看他们的配额统计信息。

在 NFS 服务器上,通过从 /etc/inetd.conf 文件中的这一行中删除 # 来启用 rpc.rquotad

rquotad/1      dgram rpc/udp wait root /usr/libexec/rpc.rquotad rpc.rquotad

然后,重新启动 inetd

# service inetd restart

20.13. 加密磁盘分区

FreeBSD 提供了出色的在线保护措施,防止未经授权的数据访问。文件权限和强制访问控制(MAC)可以在操作系统处于活动状态且计算机已经启动时,防止未经授权的用户访问数据。然而,如果攻击者可以物理访问计算机并将计算机的硬盘移动到另一个系统以复制和分析数据,操作系统强制执行的权限就变得无关紧要了。

无论攻击者如何获得硬盘或关闭电脑,FreeBSD 中内置的基于 GEOM 的加密子系统能够保护计算机文件系统上的数据,即使是对于拥有大量资源和高度动机的攻击者也是如此。与加密单个文件的加密方法不同,内置的 gbdegeli 实用程序可以用于透明地加密整个文件系统。明文永远不会接触到硬盘的盘片。

本章介绍了如何在 FreeBSD 上创建加密文件系统。首先使用 gbde 演示了该过程,然后使用 geli 演示了相同的示例。

20.13.1. 使用 gbde 进行磁盘加密

gbde(4) 设施的目标是为攻击者提供一个巨大的挑战,以防止其获取冷存储设备的内容。然而,如果计算机在运行时被入侵并且存储设备被主动连接,或者攻击者拥有有效的密码短语,那么它对存储设备的内容提供不了任何保护。因此,在系统运行时提供物理安全性并保护加密机制使用的密码短语非常重要。

该设施提供了几个屏障来保护存储在每个磁盘扇区中的数据。它使用 128 位 AES 在 CBC 模式下对磁盘扇区的内容进行加密。磁盘上的每个扇区都使用不同的 AES 密钥进行加密。有关加密设计的更多信息,包括如何从用户提供的密码短语派生扇区密钥,请参阅 gbde(4)

FreeBSD 提供了一个用于 gbde 的内核模块,可以使用以下命令加载:

# kldload geom_bde

如果使用自定义内核配置文件,请确保其中包含以下行:

options GEOM_BDE

下面的示例演示了向系统添加新的硬盘,该硬盘将容纳一个加密分区,并将其挂载为 /private

过程:使用 gbde 加密分区
  1. 添加新的硬盘

    按照 添加磁盘 中所述的方法将新驱动器安装到系统中。对于本示例,已添加了一个新的硬盘分区,表示为 /dev/ad4s1c,而 /dev/ad0s1* 表示现有的标准 FreeBSD 分区。

    # ls /dev/ad*
    /dev/ad0        /dev/ad0s1b     /dev/ad0s1e     /dev/ad4s1
    /dev/ad0s1      /dev/ad0s1c     /dev/ad0s1f     /dev/ad4s1c
    /dev/ad0s1a     /dev/ad0s1d     /dev/ad4
  2. 创建一个目录来存放 gbde 锁文件。

    # mkdir /etc/gbde

    gbde 锁定文件包含了 gbde 访问加密分区所需的信息。如果没有访问锁定文件的权限,gbde 将无法解密加密分区中的数据,除非进行大量的手动干预,而该软件不支持此操作。每个加密分区都使用一个单独的锁定文件。

  3. 初始化 gbde 分区

    在使用之前,必须初始化 gbde 分区。这个初始化只需要执行一次。该命令将打开默认编辑器,以便在模板中设置各种配置选项。对于与 UFS 文件系统一起使用,请将 sector_size 设置为 2048:

    # gbde init /dev/ad4s1c -i -L /etc/gbde/ad4s1c.lock
    # $FreeBSD: src/sbin/gbde/template.txt,v 1.1.36.1 2009/08/03 08:13:06 kensmith Exp $
    #
    # Sector size is the smallest unit of data which can be read or written.
    # Making it too small decreases performance and decreases available space.
    # Making it too large may prevent filesystems from working.  512 is the
    # minimum and always safe.  For UFS, use the fragment size
    #
    sector_size	=	2048
    [...]

    编辑保存后,用户将被要求两次输入用于保护数据的密码短语。两次输入的密码短语必须相同。Gbde 保护数据的能力完全取决于密码短语的质量。有关如何选择既安全又容易记住的密码短语的提示,请参阅 http://world.std.com/~reinhold/diceware.htm

    这个初始化操作创建了一个用于 gbde 分区的锁文件。在这个例子中,它被存储为 /etc/gbde/ad4s1c.lock 。锁文件必须以 ".lock" 结尾,以便被 /etc/rc.d/gbde 启动脚本正确地检测到。

    必须将锁定文件与任何加密分区的内容一起备份。如果没有锁定文件,合法的所有者将无法访问加密分区上的数据。

  4. 将加密分区附加到内核上

    # gbde attach /dev/ad4s1c -l /etc/gbde/ad4s1c.lock

    这个命令会提示输入在加密分区初始化过程中选择的密码。新的加密设备将出现在 /dev 中,命名为 /dev/device_name.bde

    # ls /dev/ad*
    /dev/ad0        /dev/ad0s1b     /dev/ad0s1e     /dev/ad4s1
    /dev/ad0s1      /dev/ad0s1c     /dev/ad0s1f     /dev/ad4s1c
    /dev/ad0s1a     /dev/ad0s1d     /dev/ad4        /dev/ad4s1c.bde
  5. 在加密设备上创建文件系统

    一旦加密设备已经连接到内核,就可以在设备上创建文件系统。这个示例创建了一个启用了软更新的 UFS 文件系统。请确保指定具有 *.bde 扩展名的分区:

    # newfs -U /dev/ad4s1c.bde
  6. 挂载加密分区

    创建一个挂载点并挂载加密文件系统:

    # mkdir /private
    # mount /dev/ad4s1c.bde /private
  7. 验证加密文件系统是否可用

    加密文件系统现在应该可见并可供使用:

    % df -H
    Filesystem        Size   Used  Avail Capacity  Mounted on
    /dev/ad0s1a      1037M    72M   883M     8%    /
    /devfs            1.0K   1.0K     0B   100%    /dev
    /dev/ad0s1f       8.1G    55K   7.5G     0%    /home
    /dev/ad0s1e      1037M   1.1M   953M     0%    /tmp
    /dev/ad0s1d       6.1G   1.9G   3.7G    35%    /usr
    /dev/ad4s1c.bde   150G   4.1K   138G     0%    /private

每次启动后,必须手动重新连接加密文件系统到内核,检查错误并挂载,然后才能使用这些文件系统。要配置这些步骤,请将以下行添加到 /etc/rc.conf 文件中:

gbde_autoattach_all="YES"
gbde_devices="ad4s1c"
gbde_lockdir="/etc/gbde"

这要求在启动时在控制台输入密码短语。输入正确的密码短语后,加密分区将自动挂载。还有其他可用的 gbde 启动选项,可以在 rc.conf(5) 中找到并列出。

sysinstall 与 gbde 加密设备不兼容。在启动 sysinstall 之前,必须将所有的 *.bde 设备从内核中分离,否则在设备的初始探测过程中,sysinstall 会崩溃。要分离示例中使用的加密设备,请使用以下命令:

# gbde detach /dev/ad4s1c

20.13.2. 使用 geli 进行磁盘加密

可以使用 geli 来使用另一种加密 GEOM 类。这个控制工具添加了一些功能,并使用了不同的加密方案来进行加密工作。它提供以下功能:

  • 当可用时,利用 crypto(9) 框架并自动使用加密硬件。

  • 支持多种加密算法,如 AES、Blowfish 和 3DES。

  • 允许对根分区进行加密。在系统启动期间,将要求输入用于访问加密根分区的密码短语。

  • 允许使用两个独立的键。

  • 它之所以快速,是因为它执行简单的扇区级加密。

  • 允许备份和恢复主密钥。如果用户销毁了他们的密钥,仍然可以通过从备份中恢复密钥来访问数据。

  • 允许磁盘使用随机的一次性密钥进行连接,这对于交换分区和临时文件系统非常有用。

更多功能和使用示例可以在 geli(8) 中找到。

下面的示例描述了如何生成一个密钥文件,该文件将作为加密提供者在 /private 下挂载的主密钥的一部分。密钥文件将提供一些用于加密主密钥的随机数据。主密钥还将受到密码短语的保护。提供者的扇区大小将为 4kB 。该示例描述了如何连接到 geli 提供者,创建一个文件系统,挂载它,使用它,并最终如何卸载它。

过程:使用 geli 加密分区
  1. 加载 geli 支持

    支持 geli 的功能作为可加载的内核模块提供。要配置系统在启动时自动加载该模块,请将以下行添加到 /boot/loader.conf 文件中:

    geom_eli_load="YES"

    现在加载内核模块:

    # kldload geom_eli

    对于自定义内核,请确保内核配置文件包含以下行:

    options GEOM_ELI
    device crypto
  2. 生成主密钥

    以下命令生成一个主密钥,所有数据都将使用该密钥进行加密。该密钥是不可更改的。与直接使用该密钥不同,它会被一个或多个用户密钥加密。用户密钥由来自文件 /root/da2.key 的可选随机字节或者口令组成。在这种情况下,密钥文件的数据源是 /dev/random。此命令还将提供者 (/dev/da2.eli) 的扇区大小配置为 4kB ,以提高性能。

    # dd if=/dev/random of=/root/da2.key bs=64 count=1
    # geli init -K /root/da2.key -s 4096 /dev/da2
    Enter new passphrase:
    Reenter new passphrase:

    不强制同时使用密码短语和密钥文件,因为可以单独使用其中一种方法来保护主密钥。

    如果密钥文件以"-"表示,则使用标准输入。例如,以下命令将生成三个密钥文件:

    # cat keyfile1 keyfile2 keyfile3 | geli init -K - /dev/da2
  3. 将生成的密钥与提供者关联。

    要附加提供者,请指定密钥文件、磁盘名称和密码短语:

    # geli attach -k /root/da2.key /dev/da2
    Enter passphrase:

    这将创建一个带有 .eli 扩展名的新设备:

    # ls /dev/da2*
    /dev/da2  /dev/da2.eli
  4. 创建新的文件系统

    接下来,使用 UFS 文件系统对设备进行格式化,并将其挂载到现有的挂载点上:

    # dd if=/dev/random of=/dev/da2.eli bs=1m
    # newfs /dev/da2.eli
    # mount /dev/da2.eli /private

    加密文件系统现在可以使用了。

    # df -H
    Filesystem     Size   Used  Avail Capacity  Mounted on
    /dev/ad0s1a    248M    89M   139M    38%    /
    /devfs         1.0K   1.0K     0B   100%    /dev
    /dev/ad0s1f    7.7G   2.3G   4.9G    32%    /usr
    /dev/ad0s1d    989M   1.5M   909M     0%    /tmp
    /dev/ad0s1e    3.9G   1.3G   2.3G    35%    /var
    /dev/da2.eli   150G   4.1K   138G     0%    /private

一旦加密分区的工作完成,并且不再需要 /private 分区,为了安全起见,应该将设备放入冷存储中,即卸载并从内核中分离 geli 加密分区:

# umount /private
# geli detach da2.eli

为了简化启动时 geli 加密设备的挂载,提供了一个 rc.d 脚本。对于这个示例,请将以下行添加到 /etc/rc.conf 文件中:

geli_devices="da2"
geli_da2_flags="-k /root/da2.key"

这将 /dev/da2 配置为具有 /root/da2.key 作为主密钥的 geli 提供程序。系统将在关闭系统之前自动从内核中分离该提供程序。在启动过程中,脚本将在连接提供程序之前提示输入密码。在密码提示之前和之后可能会显示其他内核消息。如果启动过程似乎停滞不前,请仔细查找其他消息中的密码提示。一旦输入正确的密码,提供程序将被连接。然后文件系统通常会被挂载,通过 /etc/fstab 中的条目进行。有关如何配置文件系统在启动时挂载的说明,请参阅“挂载和卸载文件系统”

20.14. 加密交换分区

像磁盘分区的加密一样,交换空间的加密用于保护敏感信息。考虑一个处理密码的应用程序。只要这些密码保留在物理内存中,它们不会被写入磁盘,并且在重新启动后会被清除。然而,如果 FreeBSD 开始交换内存页面以释放空间,密码可能会以未加密的形式写入磁盘。对交换空间进行加密可以解决这种情况。

本节演示如何使用 gbde(8)geli(8) 加密配置交换分区。假设 /dev/ada0s1b 是交换分区。

20.14.1. 配置加密交换空间

默认情况下,交换分区不会被加密,应在继续之前清除其中的任何敏感数据。要用随机垃圾覆盖当前的交换分区,请执行以下命令:

# dd if=/dev/random of=/dev/ada0s1b bs=1m

要使用 gbde(8) 加密交换分区,请在 /etc/fstab 中的交换行上添加 .bde 后缀。

# Device		Mountpoint	FStype	Options		Dump	Pass#
/dev/ada0s1b.bde	none		swap	sw		0	0

要使用 geli(8) 来加密交换分区,可以使用 .eli 后缀:

# Device		Mountpoint	FStype	Options		Dump	Pass#
/dev/ada0s1b.eli	none		swap	sw		0	0

默认情况下,geli(8) 使用 128 位密钥长度的 AES 算法。通常情况下,默认设置就足够了。如果需要的话,可以在 /etc/fstab 中的选项字段中更改这些默认值。可能的标志有:

aalgo

数据完整性验证算法用于确保加密数据没有被篡改。请参阅 geli(8) 以获取支持的算法列表。

ealgo

用于保护数据的加密算法。请参阅 geli(8) 以获取支持的算法列表。

keylen

用于加密算法的密钥长度。请参阅 geli(8) 以了解每个加密算法支持的密钥长度。

sectorsize

在加密之前,块数据的大小会被分割。较大的扇区大小可以提高性能,但会增加存储开销。推荐的大小是 4096 字节。

这个示例配置了一个使用 Blowfish 算法的加密交换分区,密钥长度为 128 位,扇区大小为 4 千字节。

# Device		Mountpoint	FStype	Options				Dump	Pass#
/dev/ada0s1b.eli	none		swap	sw,ealgo=blowfish,keylen=128,sectorsize=4096	0	0

20.14.2. 加密交换验证

系统重新启动后,可以使用 swapinfo 命令来验证加密交换空间的正常运行。

如果正在使用 gbde(8)

% swapinfo
Device          1K-blocks     Used    Avail Capacity
/dev/ada0s1b.bde   542720        0   542720     0

如果正在使用 geli(8)

% swapinfo
Device          1K-blocks     Used    Avail Capacity
/dev/ada0s1b.eli   542720        0   542720     0

20.15. 高可用存储(Highly Available Storage,HAST)

高可用性是严肃的商业应用程序的主要要求之一,而高可用性存储是这种环境中的关键组成部分。在 FreeBSD 中,高可用性存储(HAST)框架允许通过 TCP/IP 网络在多个物理分离的机器上透明地存储相同的数据。HAST 可以理解为基于网络的 RAID1(镜像),类似于在 GNU/Linux 平台上使用的 DRBD® 存储系统。结合 FreeBSD 的其他高可用性功能(如 CARP),HAST 使得构建一个抵抗硬件故障的高可用性存储集群成为可能。

以下是 HAST 的主要特点:

  • 可用于掩盖本地硬盘的 I/O 错误。

  • 它与 FreeBSD 支持的任何文件系统兼容,与文件系统无关。

  • 只有在节点宕机期间被修改的块才会进行同步,从而实现高效快速的重新同步。

  • 可以在已部署的环境中使用,以增加额外的冗余性。

  • 与 CARP、Heartbeat 或其他工具一起,它可以用于构建强大和耐用的存储系统。

阅读本节后,您将了解:

  • HAST 是什么,它是如何工作的,以及它提供了哪些功能。

  • 如何在 FreeBSD 上设置和使用 HAST 。

  • 如何集成 CARP 和 devd(8) 以构建一个强大的存储系统。

在阅读本节之前,您应该:

HAST 项目由 FreeBSD 基金会赞助,得到了 http://www.omc.net/http://www.transip.nl/ 的支持。

20.15.1. HAST 操作

HAST 提供了两台物理机之间的同步块级复制:主节点 和_ 备节点_。这两台机器一起被称为一个集群。

由于 HAST 以主-备配置工作,所以在任何给定的时间内只允许集群中的一个节点处于活动状态。主节点,也称为“活动节点”,负责处理所有对 HAST 管理设备的 I/O 请求。备节点会自动从主节点同步。

HAST 系统的物理组件包括主节点上的本地磁盘和远程次节点上的磁盘。

HAST 在块级别上同步操作,对文件系统和应用程序透明。 HAST 在 /dev/hast/ 目录下提供常规的 GEOM 提供程序,供其他工具或应用程序使用。使用 HAST 提供的设备和原始磁盘或分区之间没有区别。

每个写入、删除或刷新操作都会通过 TCP/IP 同时发送到本地磁盘和远程磁盘。每个读取操作都会从本地磁盘提供,除非本地磁盘不是最新的或发生了 I/O 错误。在这种情况下,读取操作会被发送到辅助节点。

HAST 试图提供快速的故障恢复。因此,在节点故障后减少同步时间非常重要。为了提供快速同步,HAST 管理一个磁盘上的脏扩展位图,并且只在定期同步期间同步这些扩展,初始同步除外。

处理同步的方法有很多种。HAST 实现了几种复制模式来处理不同的同步方法:

  • memsync:当本地写操作完成并且远程节点确认数据到达之后,但在实际存储数据之前,该模式将报告写操作已完成。在发送确认之后,远程节点上的数据将直接存储。该模式旨在减少延迟,但仍提供良好的可靠性。该模式是默认模式。

  • fullsync:当本地写操作和远程写操作都完成时,该模式将报告写操作已完成。这是最安全但也是最慢的复制模式。

  • async:此模式在本地写操作完成时报告写操作完成。这是最快速和最危险的复制模式。只有在复制到远程节点时延迟过高以至于其他模式无法使用时才应使用此模式。

20.15.2. HAST 配置

HAST 框架由几个组件组成:

  • hastd(8) 守护进程提供数据同步功能。当启动这个守护进程时,它会自动加载 geom_gate.ko 模块。

  • 用户空间管理实用程序,hastctl(8)

  • hast.conf(5) 配置文件。在启动 hastd 之前,此文件必须存在。

如果用户希望静态地在内核中内置 GEOM_GATE 支持,应该将以下行添加到自定义内核配置文件中,然后按照 配置 FreeBSD 内核 中的说明重新构建内核。

options	GEOM_GATE

以下示例描述了如何使用 HAST 在两个节点之间配置主备操作来复制数据。节点将被称为 hasta,IP 地址为 172.16.0.1,以及 hastb,IP 地址为 172.16.0.2。两个节点都将有一个专用硬盘 /dev/ad6,大小相同,用于 HAST 操作。HAST 池,有时也称为资源或 GEOM 提供者,在 /dev/hast/ 中将被称为 test

HAST 的配置是通过使用 /etc/hast.conf 文件完成的。这个文件在两个节点上应该是相同的。最简单的配置如下:

resource test {
	on hasta {
		local /dev/ad6
		remote 172.16.0.2
	}
	on hastb {
		local /dev/ad6
		remote 172.16.0.1
	}
}

有关更高级的配置,请参考 hast.conf(5)

如果主机是可解析的,并且在 /etc/hosts 或本地 DNS 中定义了,也可以在 remote 语句中使用主机名。

一旦配置在两个节点上存在,就可以创建 HAST 池。在两个节点上运行以下命令,将初始元数据放置在本地磁盘上并启动 hastd(8)

# hastctl create test
# service hastd onestart

无法使用 GEOM 提供程序与现有文件系统一起使用,也无法将现有存储转换为 HAST 管理的池。此过程需要在提供程序上存储一些元数据,而现有提供程序上没有足够的空间可用。

HAST 节点的 primarysecondary 角色由管理员或像 Heartbeat 这样的软件使用 hastctl(8) 选择。在主节点上,执行以下命令:

# hastctl role primary test

在辅助节点上运行以下命令,hastb

# hastctl role secondary test

在每个节点上运行 hastctl 来验证结果:

# hastctl status test

检查输出中的 status 行。如果它显示为 degraded,则配置文件存在问题。每个节点上应该显示为 complete,表示节点之间的同步已经开始。当 hastctl status 报告 0 字节的 dirty extents 时,同步完成。

下一步是在 GEOM 提供程序上创建文件系统并挂载它。这必须在 primary 节点上完成。根据硬盘的大小,创建文件系统可能需要几分钟的时间。此示例在 /dev/hast/test 上创建了一个 UFS 文件系统。

# newfs -U /dev/hast/test
# mkdir /hast/test
# mount /dev/hast/test /hast/test

一旦 HAST 框架正确配置完成,最后一步是确保在系统启动时自动启动 HAST。将以下行添加到 /etc/rc.conf 文件中:

hastd_enable="YES"

20.15.2.1. 故障转移配置

这个示例的目标是构建一个强大的存储系统,能够抵抗任何给定节点的故障。如果主节点发生故障,备用节点将无缝接管,检查和挂载文件系统,并继续工作,不会丢失任何一位数据。

为了完成这个任务,使用 Common Address Redundancy Protocol (CARP) 来提供 IP 层的自动故障转移。CARP 允许同一网络段上的多个主机共享一个 IP 地址。根据 “通用地址冗余协议(CARP)” 中提供的文档,在集群的两个节点上设置 CARP 。在这个例子中,每个节点都有自己的管理 IP 地址和一个共享的 IP 地址为 172.16.0.254。集群的主要 HAST 节点必须是主要的 CARP 节点。

在前一节中创建的 HAST 池现在已经准备好导出到网络上的其他主机。可以通过 NFS 或 Samba 将其导出,使用共享的 IP 地址 172.16.0.254。唯一尚未解决的问题是主节点故障时的自动故障转移。

当 CARP 接口上下线时,FreeBSD 操作系统会生成一个 devd(8) 事件,这样就可以监视 CARP 接口的状态变化。CARP 接口的状态变化表示其中一个节点失败或重新上线。这些状态变化事件使得可以运行一个脚本来自动处理 HAST 故障切换。

要捕获 CARP 接口上的状态变化,请在每个节点的 /etc/devd.conf 配置文件中添加以下配置:

notify 30 {
	match "system" "IFNET";
	match "subsystem" "carp0";
	match "type" "LINK_UP";
	action "/usr/local/sbin/carp-hast-switch primary";
};

notify 30 {
	match "system" "IFNET";
	match "subsystem" "carp0";
	match "type" "LINK_DOWN";
	action "/usr/local/sbin/carp-hast-switch secondary";
};

如果系统运行的是 FreeBSD 10 或更高版本,请将 carp0 替换为 CARP 配置接口的名称。

在两个节点上重新启动 devd(8),以使新配置生效:

# service devd restart

当指定的接口状态发生上升或下降变化时,系统会生成一个通知,允许 devd(8) 子系统运行指定的自动故障转移脚本 /usr/local/sbin/carp-hast-switch。有关此配置的进一步说明,请参考 devd.conf(5)

这是一个自动故障转移脚本的示例:

#!/bin/sh

# Original script by Freddie Cash <[email protected]>
# Modified by Michael W. Lucas <[email protected]>
# and Viktor Petersson <[email protected]>

# The names of the HAST resources, as listed in /etc/hast.conf
resources="test"

# delay in mounting HAST resource after becoming primary
# make your best guess
delay=3

# logging
log="local0.debug"
name="carp-hast"

# end of user configurable stuff

case "$1" in
	primary)
		logger -p $log -t $name "Switching to primary provider for ${resources}."
		sleep ${delay}

		# Wait for any "hastd secondary" processes to stop
		for disk in ${resources}; do
			while $( pgrep -lf "hastd: ${disk} \(secondary\)" > /dev/null 2>&1 ); do
				sleep 1
			done

			# Switch role for each disk
			hastctl role primary ${disk}
			if [ $? -ne 0 ]; then
				logger -p $log -t $name "Unable to change role to primary for resource ${disk}."
				exit 1
			fi
		done

		# Wait for the /dev/hast/* devices to appear
		for disk in ${resources}; do
			for I in $( jot 60 ); do
				[ -c "/dev/hast/${disk}" ] && break
				sleep 0.5
			done

			if [ ! -c "/dev/hast/${disk}" ]; then
				logger -p $log -t $name "GEOM provider /dev/hast/${disk} did not appear."
				exit 1
			fi
		done

		logger -p $log -t $name "Role for HAST resources ${resources} switched to primary."

		logger -p $log -t $name "Mounting disks."
		for disk in ${resources}; do
			mkdir -p /hast/${disk}
			fsck -p -y -t ufs /dev/hast/${disk}
			mount /dev/hast/${disk} /hast/${disk}
		done

	;;

	secondary)
		logger -p $log -t $name "Switching to secondary provider for ${resources}."

		# Switch roles for the HAST resources
		for disk in ${resources}; do
			if ! mount | grep -q "^/dev/hast/${disk} on "
			then
			else
				umount -f /hast/${disk}
			fi
			sleep $delay
			hastctl role secondary ${disk} 2>&1
			if [ $? -ne 0 ]; then
				logger -p $log -t $name "Unable to switch role to secondary for resource ${disk}."
				exit 1
			fi
			logger -p $log -t $name "Role switched to secondary for resource ${disk}."
		done
	;;
esac

简而言之,当一个节点成为主节点时,脚本会执行以下操作:

  • 将 HAST 池提升为另一节点上的主节点。

  • 检查 HAST 池下的文件系统。

  • 挂载存储池。

当一个节点变为次要节点时:

  • 卸载 HAST 池。

  • 将 HAST 池降级为辅助池。

这只是一个作为概念验证的示例脚本。它并不能处理所有可能的情况,并且可以根据需要进行扩展或修改,例如启动或停止所需的服务。

对于这个示例,使用了标准的 UFS 文件系统。为了减少恢复所需的时间,可以使用启用了日志的 UFS 或 ZFS 文件系统。

更详细的信息和额外的示例可以在 http://wiki.FreeBSD.org/HAST 找到。

20.15.3. 故障排除

HAST 通常应该没有问题。然而,与任何其他软件产品一样,有时候它可能无法按照预期工作。问题的根源可能不同,但经验法则是确保集群节点之间的时间同步。

在排除 HAST 问题时,应通过使用 -d 参数启动 hastd 来增加 hastd(8) 的调试级别。可以多次指定此参数以进一步增加调试级别。还可以考虑使用 -F,它会在前台启动 hastd

20.15.3.1. 从分裂脑状态中恢复

当集群的节点无法相互通信且都配置为主节点时,会发生 分裂脑(Split-brain) 现象。这是一种危险的情况,因为它允许两个节点对数据进行不兼容的更改。系统管理员必须手动纠正这个问题。

管理员必须要么决定哪个节点有更重要的更改,要么手动执行合并操作。然后,让 HAST 对具有损坏数据的节点执行完全同步。为此,请在需要重新同步的节点上执行以下命令:

# hastctl role init test
# hastctl create test
# hastctl role secondary test

上次修改时间: September 18, 2024 by fiercex