---
title: 第 19 章 存储
part: 部分 III. 系统管理
prev: books/handbook/audit
next: books/handbook/geom
---

[[disks]]
= 存储
:doctype: book
:toc: macro
:toclevels: 1
:icons: font
:sectnums:
:sectnumlevels: 6
:source-highlighter: rouge
:experimental:
:skip-front-matter:
:toc-title: 目录
:table-caption: 表
:figure-caption: 图
:example-caption: 例
:xrefstyle: basic
:relfileprefix: ../
:outfilesuffix:
:sectnumoffset: 19

ifeval::["{backend}" == "html5"]
:imagesdir: ../../../images/books/handbook/disks/
endif::[]

ifeval::["{backend}" == "pdf"]
:imagesdir: ../../../../static/images/books/handbook/disks/
endif::[]

ifeval::["{backend}" == "epub3"]
:imagesdir: ../../../../static/images/books/handbook/disks/
endif::[]

include::shared/authors.adoc[]
include::shared/releases.adoc[]
include::shared/zh-cn/mailing-lists.adoc[]
include::shared/zh-cn/teams.adoc[]
include::shared/zh-cn/urls.adoc[]

toc::[]

[[disks-synopsis]]
== 概述

这章介绍了 FreeBSD 中磁盘的使用方法。包括内存盘， 网络附属磁盘和标准的 SCSI/IDE 存储设备，以及使用 USB 的设备。

读完这章，您将了解到：

* FreeBSD 中用来描述硬盘上数据组织的术语 (partitions and slices)。
* 如何在您的系统上增加硬盘。
* 如何配置 FreeBSD 来使用 USB 存储设备。
* 如何设置虚拟文件系统，例如内存磁盘。
* 如何使用配额来限制磁盘空间的使用。
* 如何增加磁盘安全来预防功击。
* 如何刻录 CD 和 DVD 。
* 用于备份的多种存储媒介。
* 如何在 FreeBSD 上使用备份程序。
* 如何备份到软磁盘。
* 文件系统快照是什么， 以及如何有效地使用它们。

在读这章之前，您应该：

* 知道怎样去配置和安装新的 FreeBSD 内核 (crossref:kernelconfig[kernelconfig,配置FreeBSD的内核]).

[[disks-naming]]
== 设备命名

下面是在 FreeBSD 上被支持的物理存储设备和它们被分配的设备名。

[[disk-naming-physical-table]]
.物理磁盘命名规则
[cols="1,1", frame="none", options="header"]
|===
| 驱动器类型
| 驱动设备命名

|IDE 硬盘驱动器
|`ad`

|IDE CDROM 驱动器
|`acd`

|SCSI 硬盘以及 USB 大容量存储设备
|`da`

|SCSI CDROM 驱动器
|`cd`

|各类非标准 CDROM 驱动器
|用于 Mitsumi CD-ROM 的 `mcd` 以及用于 Sony CD-ROM 驱动器的 `scd`

|Floppy drives
|`fd`

|SCSI tape drives
|`sa`

|IDE tape drives
|`ast`

|Flash drives
|`fla` for DiskOnChip(R) Flash device

|RAID drives
|`aacd` for Adaptec(R) AdvancedRAID, `mlxd` and `mlyd` for Mylex(R), `amrd` for AMI MegaRAID(R), `idad` for Compaq Smart RAID, `twed` for 3ware(R) RAID.
|===

[[disks-adding]]
== 添加磁盘

下面这节将会介绍如何在一台只有一块磁盘的机器上新增一块 SCSI 磁盘。 首先 需要关掉计算机，然后按操作规程来安装驱动器，控制器和驱动程序。由于 各厂家生产的产品各不相同，具体的安装细节不在此文档介绍之内。

以 `root` 用户登录。安装完驱动后，检查一下 [.filename]#/var/run/dmesg.boot# 有没有找到新的磁盘。在我们 的例子中新增加的磁盘就是 [.filename]#da1#，我们从 [.filename]#/1# 挂上它。 (如果您正添加 IDE 驱动器， 则设备名应该是 [.filename]#ad1#)。

因为 FreeBSD 运行在 IBM-PC 兼容机上，它必须遵循 PC BIOS 分区规范。 这与传统的 BSD 分区是不同的。一个 PC 的磁盘最高只能有四个 BIOS 主分区。如果磁盘只安装 FreeBSD 您可以使用 _dedicated_ 模式。另外， FreeBSD 必须安装在 PC BIOS 支持的分区内。FreeBSD 把分区叫作 _slices_ 这可能会把人搞糊涂。您也可以在只安装 FreeBSD 的磁盘上使用 slices，也可以在安装有其它操作系统的磁盘上使用 slices。这不会影响其它操作系统的 `fdisk` 分区工具。

在 slice 方式表示下，驱动器被添加到 [.filename]#/dev/da1s1e#。 可以读作：SCSI 磁盘，编号为 1 (第二个SCSI 磁盘)， slice 1 (PC BIOS 分区 1)， 的 BSD 分区 [.filename]#e# 。在有些例子中，也可以简化为 [.filename]#/dev/da1e#。

由于 man:bsdlabel[8] 使用 32-位 的整数来表示扇区号， 因此在多数情况下它的表现力限于每个磁盘 2^32-1 个扇区， 或 2TB。 man:fdisk[8] 格式允许的起始扇区号不能高于 2^32-1， 而分区尺寸也不能超过 2^32-1， 这样一来通常情况下分区尺寸不能超过 2TB， 而磁盘尺寸则不能超过 4TB。 man:sunlabel[8] 格式的限制是每个分区 2^32-1 个扇区， 但可以有 8 个分区， 因而可以支持最大 16TB 的磁盘。 对于更大的磁盘， 可以使用 man:gpart[8] 来创建 GPT 分区。 GPT 除了支持大磁盘之外， 还不受 4 个 slice 的限制。

=== 使用 man:sysinstall[8]

[.procedure]
====
. 使用 Sysinstall
+ 
您可以使用 `sysinstall` 命令的菜单来分区和标记一个新的磁盘。 这一操作需要有 root 权限， 您可以直接使用 `root` 账户登录或者使用 `su` 命令来切换到 root 用户。运行 `sysinstall` ，然后选择 `Configure` 菜单。在 `FreeBSD Configuration Menu` 下，上下滚动， 选择 `Fdisk` 条目。
. fdisk 分区编辑器
+ 
进入 fdisk 分区编辑器后，选择 `A` ，FreeBSD 将使用全部的磁盘。当被告知 "remain cooperative with any future possible operating systems"时，回答 `YES`。使用 kbd:[W] 保存刚才的修改。现在使用 kbd:[Q] 退出 FDISK 编辑器。下面会看到有关 "主引导区" 的信息。 现在您已经在运行的系统上添加了一个磁盘， 因此应该选择 `None`。
. Disk Label 编辑器
+ 
接下来，您应该退出 sysinstall 并且再次启动它，并按照上面的步骤直接进入 `Label` 选项。进入 `磁盘标签编辑器`。 这就是您要创建的 BSD 分区。一个磁盘最多可以有 8 个分区，标记为 `a-h`。有几个分区标签有特殊的用途。 `a` 分区被用来作为根分区([.filename]#/#)。 系统磁盘（例如：从那儿启动的分区）必须有一个 `a` 分区。`b` 分区被用作交换分区，可以用很多磁盘用作交 换分区。 `c` 分区代表整个硬盘，或在 FreeBSD slice 模式下代表整个 slice。其它分区作为一般分区来使用。
+ 
sysinstall 的标签编辑器用 `e` 表示非 root 和非 swap 分区。在标签编辑器中，可以使用键入 kbd:[C] 创建一个文件系统。当提示这是否是一个 FS（文件系统）或 swap 时，选择 `FS`，然后给出一个加载点（如： [.filename]#/mnt#）。 当在 post-install 模式时添加一个磁盘， sysinstall 不会在 [.filename]#/etc/fstab# 中创建记录，所以是否指定加载点并不重要。 
+ 
现在已经准备把新标签写到磁盘上，然后创建一个文件系统，可以按下 kbd:[W]。出现任何错误都会不能创建新的分区。可以退出标签编辑 器然后重新执行 sysinstall 。
. 完成
+ 
下面一步就是编辑 [.filename]#/etc/fstab#，为您的磁盘添加一个新 记录。
====

=== 使用命令行工具

==== 使用 Slices

这步安装将允许磁盘与可能安装在您计算机上的其它操作系统一起 正确工作，而不会搞乱其它操作系统的分区。推荐使用这种方法来安装 新磁盘，除非您有更好的理由再使用 `dedicated` 模式！

[source,shell]
....
# dd if=/dev/zero of=/dev/da1 bs=1k count=1
# fdisk -BI da1 #初始化新磁盘
# bsdlabel -B -w da1s1 auto #加上标签
# bsdlabel -e da1s1 # 现在编辑您刚才创建的磁盘分区
# mkdir -p /1
# newfs /dev/da1s1e # 为您创建的每个分区重复这个操作
# mount /dev/da1s1e /1 # 挂上分区
# vi /etc/fstab # 完成之后，添加合适的记录到您的 /etc/fstab文件。
....

如果有一个 IDE 磁盘，记得要用 [.filename]#ad# 替换前面的 [.filename]#da#。

==== 专用模式

如果您并没有安装其它的操作系统，可以使用 `dedicated` 模式。记住这种模式可能会弄乱 Microsoft 的操作系统，但不会对它进行破坏。 它不识别找到的 IBM OS/2(R) 的 "appropriate" 分区。

[source,shell]
....
# dd if=/dev/zero of=/dev/da1 bs=1k count=1
# bsdlabel -Bw da1 auto
# bsdlabel -e da1				# 创建 `e' 分区
# newfs /dev/da1e
# mkdir -p /1
# vi /etc/fstab				# 为 /dev/da1e添加一个记录
# mount /1
....

另一种方法：

[source,shell]
....
# dd if=/dev/zero of=/dev/da1 count=2
# bsdlabel /dev/da1 | bsdlabel -BR da1 /dev/stdin
# newfs /dev/da1e
# mkdir -p /1
# vi /etc/fstab					# 为 /dev/da1e添加一个记录
# mount /1
....

[[raid]]
== RAID

[[raid-soft]]
=== 软件 RAID

[[ccd]]
==== 连接磁盘驱动器配置 (CCD)

选择一个大容量存储比较好的解决方案，最重要的因素是产品的速度、 性能和成本。 通常这三者不可能都满足;要获得比较快和可靠的大容量存储设备， 就比较昂贵。但如果将成本降下来，那它的速度或可靠性就会打折扣。 

在设计下面描述的系统时， 价格被选为最重要的因素， 接下来是速度和性能。 这个系统的数据传输速度基本上受限于网络。 性能也非常重要， CCD 驱动器上的所有数据都被备份到了 CD-R 盘， 可以很容易地对数据进行恢复。 

在选择一个大容量的存储解决方案时，第一步是要设计您自己的需求。 如果您的需求更偏重于速度和性能，那么您的解决方案将就不同于上面的设计。 

[[ccd-installhw]]
===== 安装硬件

除了 IDE 系统磁盘外，还有三个 Western Digital 30GB、5400 RPM 的 IDE 磁盘构成了大约 90G 的连接磁盘驱动存储空间。 理想情况是每个 IDE 硬盘都独占 IDE 控制器和数据线， 但为了尽可能降低成本， 通常并不会安装更多的控制器， 而是通过配置跳线，使每个 IDE 控制器都管理一个主盘和一个从盘。

重启动后，系统 BIOS 被配置成自动检测硬盘。FreeBSD 检测到它们：

[.programlisting]
....
ad0: 19574MB <WDC WD205BA> [39770/16/63] at ata0-master UDMA33
ad1: 29333MB <WDC WD307AA> [59598/16/63] at ata0-slave UDMA33
ad2: 29333MB <WDC WD307AA> [59598/16/63] at ata1-master UDMA33
ad3: 29333MB <WDC WD307AA> [59598/16/63] at ata1-slave UDMA33
....

[NOTE]
====
如果 FreeBSD 没有检测到它们，请确定它们的跳线是否设置 正确。大多数 IDE 磁盘有一个 "Cable Select" 跳线。这个 _不是_ 设置 master/slave 硬盘的跳线。查阅文档 信息来确定正确的跳线设置。
====

接下来考虑的是，如何创建文件系统。应该好好研究一下 man:vinum[4] (crossref:vinum[vinum-vinum,Vinum 卷管理程序])和 man:ccd[4] 两种方式，在这里我们选择 man:ccd[4] 

[[ccd-setup]]
===== 安装 CCD

man:ccd[4] 允许用户将几个相同的的磁盘通过一个逻辑文件系统 连接起来。要使用 man:ccd[4]，您需要在内核中配置 man:ccd[4] 支持选项。把这行加入到内核配置文件中，然后重建内核：

[.programlisting]
....
device   ccd
....

对 man:ccd[4] 的支持也可以内核模块的形式载入。

要安装 man:ccd[4], 首先需要使用 man:bsdlabel[8] 来编辑硬盘：

[.programlisting]
....
bsdlabel -w ad1 auto
bsdlabel -w ad2 auto
bsdlabel -w ad3 auto
....

此处将整个硬盘创建为 [.filename]#ad1c#, [.filename]#ad2c# 和 [.filename]#ad3c#。

下一步是改变 disklable 的类型。也可以使用 man:bsdlabel[8] 来编辑：

[.programlisting]
....
bsdlabel -e ad1
bsdlabel -e ad2
bsdlabel -e ad3
....

这儿在每个已经设置了 `EDITOR` 环境变量的磁盘上打开了 disklable，在我我例子中使用的是 man:vi[1]。

可以看到：

[.programlisting]
....
8 partitions:
#        size   offset    fstype   [fsize bsize bps/cpg]
  c: 60074784        0    unused        0     0     0   # (Cyl.    0 - 59597)
....

添加一个新的 `e` 分区给 man:ccd[4] 用。这可以是 `c` 分区的一个副本， 但 `fstype` _必须_ 是 `4.2BSD`。做完之后，您会看到一面这些：

[.programlisting]
....
8 partitions:
#        size   offset    fstype   [fsize bsize bps/cpg]
  c: 60074784        0    unused        0     0     0   # (Cyl.    0 - 59597)
  e: 60074784        0    4.2BSD        0     0     0   # (Cyl.    0 - 59597)
....

[[ccd-buildingfs]]
===== 建立文件系统

现在已给每个磁盘都加上了标签，下面需要建立 man:ccd[4]。要这样做， 需要使用 man:ccdconfig[8] 工具，同时要提供类似下面的选项：

[.programlisting]
....
ccdconfig ccd0 32 0 /dev/ad1e /dev/ad2e /dev/ad3e
....

每个选项的意义和用法如下所示：
配置设备的第一个参数，在这是 [.filename]#/dev/ccd0c#。 [.filename]#/dev/# 部分是任选项。
下一个参数是文件系统的插入页(interleave)。插入页定义了一个 磁盘块中一个分段或条带(stripe)的大小，通常是 512 个字节。所以一个为 32 的插入页将是 16,384 字节。
插入页为 man:ccdconfig[8] 附带了标记。如果您要启用驱动器镜像， 需要在这儿指定它。在这个配置中没有做 man:ccd[4] 的镜像，所以把它 设为 0 (zero)。
 man:ccdconfig[8] 的最后配置是设备的排列问题。使用完整的设备 路径名。

运行 man:ccdconfig[8] 后 man:ccd[4] 就配置好了。现在要创建文件 系统了，参考 man:newfs[8] 选项，执行下同的命令： 

[.programlisting]
....
newfs /dev/ccd0c
....

[[ccd-auto]]
===== 自动创建

最后，要挂上 man:ccd[4] ，需要先配置它。把当前的配置文件写入 [.filename]#/etc/ccd.conf# 中，使用下面的命令：

[.programlisting]
....
ccdconfig -g > /etc/ccd.conf
....

当重新启动系统时，如果 [.filename]#/etc/ccd.conf# 存在， 脚本 `/etc/rc` 就运行 `ccdconfig -C`。 这样就能自动配置 man:ccd[4] 以到它能被挂上。

[NOTE]
====
如果启动进入了单用户模式，在 man:mount[8] 上 man:ccd[4] 之前，需要执行下面的命令来配置队列：

[.programlisting]
....
ccdconfig -C
....

====

要自动挂接 man:ccd[4],需要为 man:ccd[4] 在 [.filename]#/etc/fstab# 中配置一个记录，以便在启动时它能被挂上。 如下所示：

[.programlisting]
....
/dev/ccd0c              /media       ufs     rw      2       2
....

[[vinum]]
==== Vinum 卷管理

Vinum 卷管理是一个实现虚拟磁盘的块驱动设备工具。它使磁盘从 块设备的接口和数据映射中独立出来。与传统的存储设备相比，增加了 灵活性、性能和可靠性。 man:vinum[4] 实现了 RAID-0、RAID-1 和 RAID-5 三种模式，它们既可以独立使用，也可组合使用。

参考 crossref:vinum[vinum-vinum,Vinum 卷管理程序] 得到更多 man:vinum[4] 的信息。

[[raid-hard]]
=== 硬件 RAID

FreeBSD 支持很多硬件 RAID 控制器。 这些硬件不需要 FreeBSD 指定软件来管理 RAID 系统。 

使用 BIOS 支持的硬件，一般情况下这些硬件可以自行操作。 下面是一个简明的描述设置一个 Promise IDERAID 控制器。 当硬件设备装好且系统重启后，屏幕上显示一个询问信息。接着进入硬件设置屏幕。在这里， 您可以把所有的磁盘联合在一起使用。这样 FreeBSD 将磁盘看作一个驱动器。其它 级别的 RAID 也可以相应的进行设置。 

=== 重建 ATA RAID1 阵列

FreeBSD 允许您热插拔阵列中损坏的磁盘。 在您重新启动系统之前请注意这一点。

您可能会在 [.filename]#/var/log/messages# 或者在 man:dmesg[8] 的输出中看到类似下面这些的内容：

[.programlisting]
....
ad6 on monster1 suffered a hard error.
ad6: READ command timeout tag=0 serv=0 - resetting
ad6: trying fallback to PIO mode
ata3: resetting devices .. done
ad6: hard error reading fsbn 1116119 of 0-7 (ad6 bn 1116119; cn 1107 tn 4 sn 11)\\
status=59 error=40
ar0: WARNING - mirror lost
....

使用 man:atacontrol[8]，查看更多的信息：

[source,shell]
....
# atacontrol list
ATA channel 0:
	Master:      no device present
	Slave:   acd0 <HL-DT-ST CD-ROM GCR-8520B/1.00> ATA/ATAPI rev 0

ATA channel 1:
	Master:      no device present
	Slave:       no device present

ATA channel 2:
	Master:  ad4 <MAXTOR 6L080J4/A93.0500> ATA/ATAPI rev 5
	Slave:       no device present

ATA channel 3:
	Master:  ad6 <MAXTOR 6L080J4/A93.0500> ATA/ATAPI rev 5
	Slave:       no device present

# atacontrol status ar0
ar0: ATA RAID1 subdisks: ad4 ad6 status: DEGRADED
....

[.procedure]
====

. 首先您应将包含故障盘的 ata 通道卸下， 以便安全地将其拆除：
+
[source,shell]
....
# atacontrol detach ata3
....
+
. 换上磁盘
. 重新挂接 ata 通道：
+
[source,shell]
....
# atacontrol attach ata3
Master:  ad6 <MAXTOR 6L080J4/A93.0500> ATA/ATAPI rev 5
Slave:   no device present
....
+
. 将新盘作为热备盘加入阵列：
+
[source,shell]
....
# atacontrol addspare ar0 ad6
....
+
. 重建阵列：
+
[source,shell]
....
# atacontrol rebuild ar0
....
+
. 可以通过下面的命令来查看进度：
+
[source,shell]
....
# dmesg | tail -10
[output removed]
ad6: removed from configuration
ad6: deleted from ar0 disk1
ad6: inserted into ar0 disk1 as spare

# atacontrol status ar0
ar0: ATA RAID1 subdisks: ad4 ad6 status: REBUILDING 0% completed
....
+
. 等待操作完成。
====

[[usb-disks]]
== USB 存储设备

到目前为止，有许多外部外部存储解决方案， 例如：通用串行总线 (USB)：硬盘、USB thumbdrives、CD-R burners 等等。 FreeBSD 为这些设备提供了支持。

=== 配置

USB 大容量存储设备驱动，在 man:umass[4], 中提供了对 USB 存储设备的支持。如果您使用 [.filename]#GENERIC# 内核，您不必要改变配置文件里的任何内容。 如果您使用了定制的内核，就要确定下面的行出现在您的内核配置文件里：

[.programlisting]
....
device scbus
device da
device pass
device uhci
device ohci
device ehci
device usb
device umass
....

man:umass[4] 驱动程序使用 SCSI 子系统来访问 USB 存储设备， 您的 USB 设备将被系统看成为一个 SCSI 设备。依靠您主板上的 USB 芯片， 您只须选择 `device uhci` 或用于 USB 1.X 支持的 `device ohci` 二者之一即可， 但是两者都加入内核配置文件当中也是无害的。 对于 USB 2.X 控制器的支持由 man:ehci[4] 提供 (`device ehci` 这一行)。 不要忘了如果您加入了上面的几行要重新编译和安装内核。

[NOTE]
====
如果您的 USB 设备是一个 CD-R 或 DVD 刻录机， SCSI CD-ROM 驱动程序， man:cd[4], 就必须加入内核中通过下面这行：

[.programlisting]
....
device cd
....

由于刻录机被视为 SCSI 设备， 因此， 不应该在内核配置文件中使用 man:atapicam[4] 驱动程序。
====

=== 测试配置

配置好后准备进行测试：插入您的 USB 设备， 在系统信息中 (man:dmesg[8]), 应该会出现像下面的设备：

[source,shell]
....
umass0: USB Solid state disk, rev 1.10/1.00, addr 2
GEOM: create disk da0 dp=0xc2d74850
da0 at umass-sim0 bus 0 target 0 lun 0
da0: <Generic Traveling Disk 1.11> Removable Direct Access SCSI-2 device
da0: 1.000MB/s transfers
da0: 126MB (258048 512 byte sectors: 64H 32S/T 126C)
....

当然啦，商标，设备标识 ([.filename]#da0#) 和其它的细节信息会根据您的配置不同 而有所不同。

因为 USB 设备被看作 SCSI 设备中的一个， `camcontrol` 命令也能够用来列出 USB 存储设备和系统的关联：

[source,shell]
....
# camcontrol devlist
<Generic Traveling Disk 1.11>      at scbus0 target 0 lun 0 (da0,pass0)
....

如果设备上已经包含了文件系统， 现在应该就可以挂接它了。 如果需要， 请参阅 <<disks-adding>> 来了解如何在 USB驱动器上格式化和创建分区。

[WARNING]
====

允许非可信用户挂载任意介质， 例如通过使用前面介绍的 `vfs.usermount` 来启用的功能， 从安全角度来看是很不保险的。 FreeBSD 中的绝大多数文件系统并不提供针对恶意设备的内建防护能力。
====

如果希望设备能够被普通用户挂接， 还需要做一些其它操作。 首先， 在 USB 存储设备连接到计算机上时， 系统自动生成的设备文件， 必须是该用户能够读写的。 一种做法是让所有属于 `operator` 组的用户都可以访问该设备。 要完成这项工作， 首先需要用 man:pw[8] 来给用户指定组。 其次， 在生成设备文件时， `operator` 组应能读写它们。 这可以通过在 [.filename]#/etc/devfs.rules# 中增加一些相应的设置来实现：

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

[NOTE]
====
如果系统中已经有其它 SCSI 磁盘， 则上述操作必须做一些变化。 例如， 如果系统中已经存在了设备名为 [.filename]#da0# 到 [.filename]#da2# 的磁盘， 则第二行应改为：

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

这会将系统中已经存在的磁盘， 排除在属于 `operator` 组的设备之外。
====

另外， 您还需要在 [.filename]#/etc/rc.conf# 文件中， 启用 man:devfs.rules[5] 规则集：

[.programlisting]
....
devfs_system_ruleset="localrules"
....

接下来， 需要配置内核， 令普通用户能够挂接文件系统。 最简单的方法是将下面的配置加入到 [.filename]#/etc/sysctl.conf#：

[.programlisting]
....
vfs.usermount=1
....

注意， 这个设置只有在下次重启系统时才会生效。 另外， 您也可以使用 man:sysctl[8] 来设置这个变量。

最后一步是创建将要挂接文件系统的目录。 这个目录必须是属于将要挂接文件系统的用户的。 以 `root` 身份为用户建立属于该用户的 [.filename]#/mnt/username# (此处 _username_ 应替换成用户的登录名， 并把 _usergroup_ 替换成用户所属的组)：

[source,shell]
....
# mkdir /mnt/username
# chown username:usergroup /mnt/username
....

假设已经插入了一个 USB 读卡设备， 并且系统将其识别为 [.filename]#/dev/da0s1#， 由于这些设备通常是 FAT 文件系统， 用户可以这样挂接它们：

[source,shell]
....
% mount -t msdosfs -o -m=644,-M=755 /dev/da0s1 /mnt/username
....

如果拔出设备 (必须首先将其对应的磁盘卷卸下)， 则您会在系统消息缓冲区中看到类似下面的信息：

[source,shell]
....
umass0: at uhub0 port 1 (addr 2) disconnected
(da0:umass-sim0:0:0:0): lost device
(da0:umass-sim0:0:0:0): removing device entry
GEOM: destroy disk da0 dp=0xc2d74850
umass0: detached
....

=== 深入阅读

除了 <<disks-adding,Adding Disks>> 和 crossref:basics[mount-unmount,Mounting and Unmounting File Systems] 章之外， 阅读各种手册页也是有益的： man:umass[4], man:camcontrol[8], 和 FreeBSD 8.X 的 man:usbconfig[8] 或者对于更早期 FreeBSD 版本的 man:usbdevs[8]。

[[creating-cds]]
== 创建和使用光学介质(CD)

=== 介绍

CD 与普通的磁盘相比有很多不同的特性。最初它们是不能被用户写入的。 由于没有磁头和磁道移动时的延迟，所以它们可以连续的进行读取。 方便的在两个系统之间进行数据的传输，比起相同大小的存储介质来说。

CD 有磁道，这关系到数据读取时的连续性而不是物理磁盘的性能。 要在 FreeBSD 中制作一个 CD，您要准备好要写到 CD 上的数据文件， 然后根据每个 tracks 写入到 CD。

ISO 9660 文件系统被设计用来处理这些差异。 但令人遗憾的是， 它也有一些其他文件系统所没有的限制， 不过幸运的是， 它提供了一项扩展机制， 使得正确写入的 CD 能够超越这些限制， 而又能在不支持这些扩展的系统上正常使用。

package:sysutils/[] port 包括了 man:mkisofs[8]， 这是一个可以用来生成包含 ISO 9660 文件系统的数据文件的程序。 他也提供了对于一些扩展的支持选项，下面将详细介绍。

使用哪个工具来刻录 CD 取决于您的 CD 刻录机是 ATAPI 的， 还是其他类型的。 对于 ATAPI CD 刻录机， 可以使用基本系统附带的 `burncd` 程序。 SCSI 和 USB CD 刻录机， 则需要配合 `cdrecord` 程序使用， 它可以通过 package:sysutils/cdrtools[] port 安装。 除此之外， 在 ATAPI 接口的刻录机上， 也可以配合 <<atapicam,ATAPI/CAM 模块>> 来使用 `cdrecord` 以及其它为 SCSI 刻录机撰写的工具。

如果您想使用带图形界面的 CD 刻录软件， 可以考虑一下 X-CD-Roast 或 K3b。 这些工具可以通过使用预编译安装包， 或通过 package:sysutils/xcdroast[] 和 package:sysutils/k3b[] ports 来安装。 X-CD-Roast 和 K3b 需要 <<atapicam,ATAPI/CAM 模块>> 配合 ATAPI 硬件。

[[mkisofs]]
=== mkisofs

man:mkisofs[8] 程序作为 package:sysutils/cdrtools[] port 的一部分， 将生成 ISO 9660 文件系统，其中包含 UNIX(R) 命名空间中的文件名。 最简单的用法是：

[source,shell]
....
# mkisofs -o imagefile.iso /path/to/tree
....

这个命令将创建一个包含 ISO9660 文件系统的 _imagefile.iso_ 文件，它是目录树 _/path/to/tree_ 的一个副本。 在处理过程中， 它将文件名称映射为标准的 ISO9660 文件系统的文件名，将排除那些不典型的 ISO 文件系统的文件。

有很多选项能够用来克服那些限制。特别的，`-R` 选项能够启用 Rock Ridge 扩展一般的 UNIX(R) 系统，`-J` 选项能启用用于 Microsoft 系统的 Joliet 扩展，`-hfs` 选项能用来创建用于 Mac OS(R) 系统的 HFS 文件系统。

对于那些即将要在 FreeBSD 系统中使用 CD 的人来说，`-U` 选项能用来消除所有文件名的限制。当使用 `-R` 选项时，它会产生一个 文件系统映像，它与您从那儿启动 FreeBSD 树是一样的，虽然它在许多方面也违反了 ISO 9660 的标准。

最后一个常用的选项是 `-b`。 它用来指定启动映像的位置， 用以生成 "El Torito" 启动 CD。 这个选项使用一个参数， 用以指定将写入 CD 的目录的根。 默认情况下， man:mkisofs[8] 会以常说的 "软盘模拟" 方式来创建 ISO， 因此它希望引导映像文件的尺寸恰好是 1200， 1440 或 2880 KB。 某些引导加载器， 例如 FreeBSD 发行版磁盘， 并不使用模拟模式； 这种情况下， 需要使用 `-no-emul-boot` 选项。 因此， 如果 [.filename]#/tmp/myboot# 是一个包含了启动映像文件 [.filename]#/tmp/myboot/boot/cdboot# 的可引导的 FreeBSD 系统， 您就可以使用下面的命令生成 ISO 9660 文件系统映像 [.filename]#/tmp/bootable.iso#：

[source,shell]
....
# mkisofs -R -no-emul-boot -b boot/cdboot -o /tmp/bootable.iso /tmp/myboot
....

完成这些工作之后， 如果您的内核中配置了 [.filename]#md#， 就可以用下列命令来挂接文件系统了：

[source,shell]
....
# mdconfig -a -t vnode -f /tmp/bootable.iso -u 0
# mount -t cd9660 /dev/md0 /mnt
....

可以发现 [.filename]#/mnt# 和 [.filename]#/tmp/myboot# 是一样的。

还可以使用 man:mkisofs[8] 的其它选项来调整它的行为。特别是修改 ISO 9660 的划分格式，创建 Joliet 和 HFS 格式的磁盘。查看 man:mkisofs[8] 联机手册得到更多的帮助。

[[burncd]]
=== burncd

如果用的是 ATAPI 的 CD 刻录机，可以使用 `burncd` 　命令来刻录您的 CD ISO 映像文件。 `burncd` 命令是基本 　系统的一部分，中以使用 [.filename]#/usr/sbin/burncd# 来安装。 　用法如下：

[source,shell]
....
# burncd -f cddevice data imagefile.iso fixate
....

在 _cddevice_ 上刻录一份 _imagefile.iso_ 的副本。 默认的设备是 [.filename]#/dev/acd0#。 请参考 man:burncd[8] 以了解设置写入速度的参数，如何在刻录完成之后自动弹出CD，以及刻录音频数据。

[[cdrecord]]
=== cdrecord

如果没有一个 ATAPI CD 刻录机，必须使用 `cdrecord` 来刻录您的 CD 。 `cdrecord` 不是基本系统的一部分;必须 从 package:sysutils/cdrtools[] 或适当的 package 安装它。基本系统的变化可能会引起这个程序的错误。可能是由 "coaster" 引起的。当升级系统时，同时需要升级 port， 或者如果您 crossref:cutting-edge[stable,使用 -STABLE]， 那么在升级到新版本时也要升级 port。

`cdrecord` 有许多选项，基本用法与 `burncd` 相似。刻录一个 ISO 9660 映像文件只需这样做：

[source,shell]
....
# cdrecord dev=device imagefile.iso
....

使用 `cdrecord` 的比较巧妙的方法是找到使用的 `dev` 。要找到正确的设置，可以使用 `cdrecord` 的 `-scanbus` 标记，这会产生这样的结果：

[source,shell]
....
# cdrecord -scanbus
Cdrecord-Clone 2.01 (i386-unknown-freebsd7.0) Copyright (C) 1995-2004 Jörg Schilling
Using libscg version 'schily-0.1'
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) *
....

这个列表列出了设备的的适当的 `dev` 值。找到您的 CD burner ,使用三个用逗号分隔的数值来表示 `dev`.在 这个例子中，CRW 是 `dev=1,5,0`，所以正确的输入应是 dev=1,5,0 。有一个很容易的方法可以指定这个值;看看 man:cdrecord[1] 的介绍了解有关音轨，控制速度和其他的东西。

[[duplicating-audiocds]]
=== 复制音频 CD

您可以这样复制 CD，把 CD 上面的音频数据解压缩出一系列的文件， 再把这些文件写到一张空白 CD 上。 这个过程对于 ATAPI 和 SCSI 驱动器来说有些微的不同。 

[.procedure]
====
*Procedure: SCSI 驱动器*

. 使用 `cdda2wav` 来解压缩音频。
+
[source,shell]
....
% cdda2wav -vall -D2,0 -B -Owav
....
+
. 使用 `cdrecord` 来写 [.filename]#.wav# 文件。
+
[source,shell]
....
% cdrecord -v dev=2,0 -dao -useinfo  *.wav
....
+ 
确保 _2,0_ 被适当地设置了， 具体方法在 <<cdrecord>> 中有所描述。
====

[.procedure]
====
*Procedure: ATAPI 驱动器*

[NOTE]
======
借助于 <<atapicam,ATAPI/CAM 模块>>， `cdda2wav` 同样也能在 ATAPI 设备上使用。 此工具比起下面推荐的方法通常是个更好的选择(抖动修正， 字节序问题， 等等)。
======

. ATAPI CD 驱动用 [.filename]##/dev/acddtnn##表示每个轨道， 这里 _d_ 是驱动器号， _nn_ 是轨道号，由两位小数位组成，省略前缀零。 所以第一个盘片上的第一个轨道就是 [.filename]##/dev/acd0t01##，第二个就是 [.filename]##/dev/acd0t02##，第三个就是 [.filename]##/dev/acd0t03##，等等。
+ 
请务必确认在 [.filename]#/dev# 中出现了对应的文件。 如果您发现有某些项目缺失， 则应强制系统重新识别介质：
+
[source,shell]
....
# dd if=/dev/acd0 of=/dev/null count=1
....
+
. 使用 man:dd[1] 解压缩每个轨道。当解压缩文件的时候您也必须使用 一个特殊的块大小。
+
[source,shell]
....
# dd if=/dev/acd0t01 of=track1.cdr bs=2352
# dd if=/dev/acd0t02 of=track2.cdr bs=2352
...
....
+
. 使用 `burncd` 把解压缩的文件刻录到光盘上。您必须指定 这些文件是音频文件，这样 `burncd` 会在刻录完成时 结束光盘。
+
[source,shell]
....
# burncd -f /dev/acd0 audio track1.cdr track2.cdr ... fixate
....
====

[[imaging-cd]]
=== 复制数据 CD

您可以把数据 CD 复制成一个与之等价的映像文件， 可以使用 man:mkisofs[8] 创建这种文件， 或使用它来复制任何数据 CD。 这里给出的例子假定您的 CDROM 设备是 [.filename]#acd0#， 您应将其替换为您实际使用的 CDROM 设备。

[source,shell]
....
# dd if=/dev/acd0 of=file.iso bs=2048
....

现在您有一个映像文件了，您可以像上面描述的那样把它刻录成 CD。 

[[mounting-cd]]
=== 使用数据 CD

现在您已经创建了一张标准的数据 CDROM，您或许想要 挂载来读取上面的设备。 默认情况下，man:mount[8] 假定文件系统是 `ufs` 类型的。如果您尝试下面的命令：

[source,shell]
....
# mount /dev/cd0 /mnt
....

您会得到一条 `Incorrect super block` 的错误信息，没有挂载成功。CDROM 不是 `UFS` 文件系统，所以试图这样挂载它是 是不行的。您需要告诉 man:mount[8] 文件系统是 `ISO9660` 类型的，这样 就可以了。只需要指定 man:mount[8] 的 `-t cd9660` 选项。例如， 如果您想要挂载 CDROM 设备， [.filename]#/dev/cd0# 到 [.filename]#/mnt# 目录，您需要执行：

[source,shell]
....
# mount -t cd9660 /dev/cd0 /mnt
....

注意您的设备名 (在这个例子中是 [.filename]#/dev/cd0#)可能 有所不同，取决于您的 CDROM 使用的接口。另外， `-t cd9660` 选项等同于执行 man:mount_cd9660[8]。上面的例子可以缩短 为：

[source,shell]
....
# mount_cd9660 /dev/cd0 /mnt
....

用这种方法您基本可以使用任何买到的数据 CDROM。 然而某些有 ISO 9660 扩展的光盘可能会行为古怪。 例如，joliet 光盘用两个字节的 unicode 字符存储所有的文件名。 FreeBSD 内核并不使用 Unicode， 但 FreeBSD CD9660 驱动可以将 Unicode 字符自动转换为内核可以识别的形式。 如果您发现有些非英文字符显示为问号， 就绪要使用 `-C` 选项来指定字符集了。 欲了解进一步的详情， 请参见联机手册 man:mount_cd9660[8]。

[NOTE]
====
如果希望通过 `-C` 选项来进行字符集转换， 则内核会需要加载 [.filename]#cd9660_iconv.ko# 模块。 这项工作可以通过在 [.filename]#loader.conf# 中加入下列配置：

[.programlisting]
....
cd9660_iconv_load="YES"
....

并重新启动计算机来完成， 除此之外， 也可以通过 man:kldload[8] 来手动加载。
====

有时候，当您试图挂载 CDROM 的时候，会得到一条 `Device not configured` 的错误信息。这通常 表明 CDROM 驱动认为托盘里没有光盘， 或者驱动器在总线上不可见。 需要几秒钟时间等待 CDROM 驱动器辨别已经接到反馈的信息， 请耐心等待。

有时候，SCSI CDROM 可能会找不到，因为没有足够的 时间来应答总线的 reset 信号。如果您有一个 SCSI CDROM 请将下面的选项添加到您的内核 配置文件并crossref:kernelconfig[kernelconfig-building,重建您的内核]。

[.programlisting]
....
options SCSI_DELAY=15000
....

这个告诉您的 SCSI 总线启动时暂停 15 秒钟， 给您的 CDROM 驱动器足够的机会来应答 总线 reset 信号。

[[rawdata-cd]]
=== 刻录原始数据 CD

您可以选择把一个文件目录刻录到 CD 上而不用 创建 ISO 9660 文件系统。有些人这么做是为了备份的 目的。这个运行的比刻录一个标准 CD 速度要快得多：

[source,shell]
....
# burncd -f /dev/acd1 -s 12 data archive.tar.gz fixate
....

要重新找回这样刻录到 CD 上的数据， 您必须从原始设备节点读取数据：

[source,shell]
....
# tar xzvf /dev/acd1
....

您不能像挂载一个通常的 CDROM 一样挂载这张光盘。 这样的 CDROM 也不能在除了 FreeBSD 之外的任何操作系统上读出。 如果您想要可以挂载 CD，或者 和另一种操作系统共享数据，您必须像上面描述的那样使用 man:mkisofs[8]。

[[atapicam]]
=== 使用 ATAPI/CAM 驱动

这个驱动允许 ATAPI 设备(CD-ROM, CD-RW, DVD 驱动器等...)通过 SCSI 子系统访问， 这样允许使用像 package:sysutils/cdrdao[] 或者 man:cdrecord[1] 这样的程序。

要使用这个驱动， 您需要把下面这行添加到 [.filename]#/boot/loader.conf# 文件中：

[.programlisting]
....
atapicam_load="YES"
....

接下来， 重新启动计算机。

[NOTE]
====
如果您希望将 man:atapicam[4] 以静态联编的形式加入内核， 则需要在内核配置文件中加入这行：

[.programlisting]
....
device atapicam
....

此外还需要在内核配置文件中加入：

[.programlisting]
....
device ata
device scbus
device cd
device pass
....

这些应该已经有了。 然后， 重新联编并安装新内核， 并重新启动计算机。
====

在引导过程中， 您的刻录机将会出现在内核的提示信息中， 就像这样：

[source,shell]
....
acd0: CD-RW <MATSHITA CD-RW/DVD-ROM UJDA740> at ata1-master PIO4
cd0 at ata1 bus 0 target 0 lun 0
cd0: <MATSHITA CDRW/DVD UJDA740 1.00> Removable CD-ROM SCSI-0 device
cd0: 16.000MB/s transfers
cd0: Attempt to query device size failed: NOT READY, Medium not present - tray closed
....

驱动器现在可以通过 [.filename]#/dev/cd0# 设备名访问了，例如要 挂载 CD-ROM 到 [.filename]#/mnt#，只需要键入下面的 命令：

[source,shell]
....
# mount -t cd9660 /dev/cd0 /mnt
....

作为 `root`，您可以运行下面的 命令来得到刻录机的 SCSI 地址：

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

这样 `1,0,0` 就是 SCSI 地址了，可以被 man:cdrecord[1] 和其他的 SCSI 程序使用。

有关 ATAPI/CAM 和 SCSI 系统的更多信息， 可以参阅 man:atapicam[4] 和 man:cam[4] 手册 页。

[[creating-dvds]]
== 创建和使用光学介质(DVD)

=== 介绍

和 CD 相比，DVD 是下一代光学存储介质技术。 DVD 可以容纳比任何 CD 更多的数据，已经成为现今视频出版业的标准。

我们称作可记录 DVD 的有五种物理记录格式：

* DVD-R：这是第一种可用的 DVD 可记录格式。 DVD-R 标准由 http://www.dvdforum.com/forum.shtml[DVD Forum] 定义。 这种格式是一次可写的。
* DVD-RW：这是 DVD-R 标准的可覆写版本。 一张 DVD-RW 可以被覆写大约 1000 次。
* DVD-RAM：这也是一种被 DVD Forum 所支持的可覆写格式。 DVD-RAM 可以被看作一种可移动硬盘。 然而，这种介质和大部分 DVD-ROM 驱动器以及 DVD-Video 播放器不兼容； 只有少数 DVD 刻录机支持 DVD-RAM。 请参阅 <<creating-dvd-ram>> 以了解关于如何使用 DVD-RAM 的进一步详情。
* DVD+RW：这是一种由 http://www.dvdrw.com/[DVD+RW Alliance] 定义的可覆写格式。一张 DVD+RW 可以被覆写大约 1000 次。
* DVD+R：这种格式是 DVD+RW 格式的一次可写变种。

一张单层的可记录 DVD 可以存储 4,700,000,000 字节，相当于 4.38 GB 或者说 4485 MB (1 千字节等于 1024 字节)。

[NOTE]
====
必须说明一下物理介质与应用程序的分歧。 例如 DVD-Video 是一种特殊的文件系统， 可以被覆写到任何可记录的 DVD 物理介质上： DVD-R、DVD+R、DVD-RW 等等。在选择介质类型之前， 您一定要确认刻录机和 DVD-Video 播放器 (一种单独的播放器或者计算机上的 DVD-ROM 驱动器) 是和这种介质兼容的。
====

=== 配置

man:growisofs[1] 将被用来实施 DVD 刻录。 这个命令是 dvd+rw-tools 工具集 (package:sysutils/dvd+rw-tools[]) 的一部分。 dvd+rw-tools 支持所有的 DVD 介质类型。

这些工具将使用 SCSI 子系统来访问设备，因此 <<atapicam,ATAPI/CAM 支持>> 必须加入内核。 如果您的刻录机采用 USB 接口则不需要这么做，请参考 <<usb-disks>> 来了解 USB 设备配置的进一步详情。

此外，还需要启用 ATAPI 设备的 DMA 支持。 这一工作可以通过在 [.filename]#/boot/loader.conf# 文件中加入下面的行来完成：

[.programlisting]
....
hw.ata.atapi_dma="1"
....

试图使用 dvd+rw-tools 之前您应该参考 http://fy.chalmers.se/~appro/linux/DVD+RW/hcn.html[dvd+rw-tools 硬件兼容性列表] 是否有与您的 DVD 刻录机有关的信息。

[NOTE]
====
如果您想要一个图形化的用户界面，您应该看一看 K3b (package:sysutils/k3b[])，它提供了 man:growisofs[1] 的一个友好界面和许多其他刻录工具。
====

=== 刻录数据 DVD

man:growisofs[1] 命令是 <<mkisofs,mkisofs>> 的前端，它会调用 man:mkisofs[8] 来创建文件系统布局，完成到 DVD 上的刻录。 这意味着您不需要在刻录之前创建数据映像。

要把 [.filename]#/path/to/data# 目录的数据刻录到 DVD+R 或者 DVD-R 上面，使用下面的命令：

[source,shell]
....
# growisofs -dvd-compat -Z /dev/cd0 -J -R /path/to/data
....

`-J -R` 选项传递给 man:mkisofs[8] 用于文件系统创建 (这表示创建带有带有 joliet 和 Rock Ridge 扩展的 ISO 9660 文件系统)， 参考 man:mkisofs[8] 联机手册了解更多细节。

选项 `-Z` 用来在任何情况下初始刻录会话： 不管多会话与否。 DVD 设备，_/dev/cd0_， 必须依照您的配置做出改变。 `-dvd-compat` 参数会结束光盘， 光盘成为不可附加的。这会提供更多的和 DVD-ROM 驱动器的介质兼容性。

也可以刻录成一个 pre-mastered 映像, 例如记录一个映像文件 _imagefile.iso_, 我们可以运行：

[source,shell]
....
# growisofs -dvd-compat -Z /dev/cd0=imagefile.iso
....

刻录的速度可以被检测到并自动进行调整， 根据介质和驱动器的使用情况。如果您想强制改变速度， 可以使用 `-speed=` 参数。更多的信息，请看 man:growisofs[1] 联机手册。

[NOTE]
====
如果需要在刻录的编录中添加超过 4.38GB 的单个文件， 就必须使用 man:mkisofs[8] 或其他相关工具 (例如 man:growisofs[1]) 的 `-udf -iso-level 3` 参数来创建 UDF/ISO-9660 混合文件系统。 只有在创建 ISO 映像文件或直接在盘上写数据时才需要这样做。 以这种方式创建的光盘必须通过 man:mount_udf[8] 工具以 UDF 文件系统挂载， 因此只有操作系统支持 UDF 时才可以这样做， 否则盘上的文件数据可能会无法正确读出。

要创建这样的 ISO 文件：

[source,shell]
....
% mkisofs -R -J -udf -iso-level 3 -o imagefile.iso /path/to/data
....

直接将文件刻录到光盘上：

[source,shell]
....
# growisofs -dvd-compat -udf -iso-level 3 -Z /dev/cd0 -J -R /path/to/data
....

假如只是使用包含巨型文件的 ISO 映像文件时， 就不需要在运行 man:growisofs[1] 来将映像文件刻录成光盘时指定任何额外的选项了。

另外， 在映像文件中增加或直接刻录巨型文件时， 还需要注意使用最新的 package:sysutils/cdrtools[] (包含了 man:mkisofs[8])， 因为旧版并不提供巨型文件支持。 如果您遇到问题， 也可以尝试一下开发版本的软件包， 例如 package:sysutils/cdrtools-devel[] 并参阅 man:mkisofs[8] 联机手册。
====

=== 刻录 DVD-Video

DVD-Video 是一种特殊的基于 ISO 9660 和 micro-UDF (M-UDF) 规范的文件系统。 DVD-Video 也呈现了一个特殊的数据格式， 这就是为什么您需要一个特殊的程序像 package:multimedia/dvdauthor[] 来制作 DVD 的原因。

如果您已经有了 DVD-Video 文件系统的映像， 就可以以同样的方式制作另一个映像，可以参看前面章节的例子。 如果您想制作 DVD 并想放在特定的目录中，如在目录 [.filename]#/path/to/video# 中， 可以使用下面的命令来刻录 DVD-Video：

[source,shell]
....
# growisofs -Z /dev/cd0 -dvd-video /path/to/video
....

`-dvd-video` 选项将传递给 man:mkisofs[8] 并指示它创建一个 DVD-Video 文件系统布局。 除此之外。 `-dvd-video` 选项也包含了 `-dvd-compat` man:growisofs[1] 选项。

=== 使用 DVD+RW

不像 CD-RW, 一个空白的 DVD+RW 在每一次使用前必须先格式化。 man:growisofs[1] 程序将会适时的自动对其进行适当的处理， 这是 _recommended_ 的方式。您也可以使用 `dvd+rw-format` 来对 DVD+RW 进行格式化：

[source,shell]
....
# dvd+rw-format /dev/cd0
....

您只需要执行这样的操作一次，牢记只有空白的 DVD+RW 介质才需要格式化。您可以以前面章节同样的方式来刻录 DVD+RW。

如果您想刻录新的数据 (刻录一个新的完整的文件系统 而不仅仅是追加一些数据) 到 DVD+RW，您不必再将其格式化成空白盘， 您只须要直接覆盖掉以前的记录即可。 (执行一个新的初始化对话), 像这样：

[source,shell]
....
# growisofs -Z /dev/cd0 -J -R /path/to/newdata
....

DVD+RW 格式化程序为简单的向以前的记录追加数据提供了可能性。 这个操作有一个新的会话和一个已经存在的会话合并而成。 它不需要多个写会话过程， man:growisofs[1] 将在介质上 _增加_ ISO 9660 文件系统。

例如，我们想追加一些数据到到我们以前的 DVD+RW 上，我们可以使用下面的命令：

[source,shell]
....
# growisofs -M /dev/cd0 -J -R /path/to/nextdata
....

在以后的写操作时， 应使用与最初的刻录会话时相同的 man:mkisofs[8] 选项。

[NOTE]
====
如果您想获得与 DVD-ROM 驱动更好的兼容性，可以使用 `-dvd-compat` 选项。 在 DVD+RW 这种情况下， 这样做并不妨碍您添加数据。
====

如果出于某种原因您真的想要空白介质盘， 可以执行下面的命令：

[source,shell]
....
# growisofs -Z /dev/cd0=/dev/zero
....

=== 使用 DVD-RW

 DVD-RW 接受两种光盘格式：增补顺序写入和受限式覆写。默认的 DVD-RW 盘是顺序写入格式。

空白的 DVD-RW 能够直接进行刻录而不需要格式化操作， 然而非空的顺序写入格式的 DVD-RW 需要格式化才能写入新的初始区段。

要格式化一张 DVD-RW 为顺序写入模式，运行：

[source,shell]
....
# dvd+rw-format -blank=full /dev/cd0
....

[NOTE]
====
一次完全的格式化 (`-blank=full`) 在 1x 倍速的介质上将会花费大约 1 个小时。快速格式化可以使用 `-blank` 选项来进行，如果 DVD-RW 要以 Disk-At-Once (DAO) 模式刻录的话。要以 DAO 模式刻录 DVD-RW，使用命令：

[source,shell]
....
# growisofs -use-the-force-luke=dao -Z /dev/cd0=imagefile.iso
....

`-use-the-force-luke=dao` 选项不是必需的， 因为 man:growisofs[1] 试图最低限度的检测 (快速格式化) 介质并进行 DAO 写入。

事实上对于任何 DVD-RW 都应该使用受限式覆写模式， 这种格式比默认的增补顺序写入更加灵活。
====

在一张顺序 DVD-RW 上写入数据，使用和其他 DVD 格式相同的指令：

[source,shell]
....
# growisofs -Z /dev/cd0 -J -R /path/to/data
....

如果您想在您以前的刻录上附加数据，您必须使用 man:growisofs[1] 的 `-M` 选项。然而， 如果您在一张增补顺序写入模式的 DVD-RW 上附加数据， 将会在盘上创建一个新的区段，结果就是一张多区段光盘。

受限式覆写格式的 DVD-RW 在新的初始化区段前不需要格式化， 您只是要用 `-Z` 选项覆写光盘，这和 DVD+RW 的情形是相似的。也可以用和 DVD+RW 同样方式的 `-M` 选项把现存的 ISO 9660 文件系统写入光盘。 结果会是一张单区段 DVD。

要把 DVD-RW 置于受限式覆写格式， 必须使用下面的命令：

[source,shell]
....
# dvd+rw-format /dev/cd0
....

更改回顺序写入模式使用：

[source,shell]
....
# dvd+rw-format -blank=full /dev/cd0
....

=== 多区段

几乎没有哪个 DVD-ROM 驱动器支持多区段 DVD，它们大多数时候都只读取第一个区段。 顺序写入格式的 DVD+R、DVD-R 和 DVD-RW 可以支持多区段， DVD+RW 和 DVD-RW 受限式覆写格式不存在多区段的概念。

在 DVD+R、DVD-R 或者 DVD-RW 的顺序写入格式下， 一次初始化 (未关闭) 区段之后使用下面的命令， 将会在光盘上添加一个新的区段：

[source,shell]
....
# growisofs -M /dev/cd0 -J -R /path/to/nextdata
....

对 DVD+RW 或者 DVD-RW 在受限式覆写模式下使用这条命令， 会合并新区段到存在的区段中来附加数据。 结果就是一张单区段光盘。 这是在这些介质上用于在最初的写操作之后添加数据的方式。

[NOTE]
====
介质上的一些空间用于区段之间区段的开始与结束。 因此，应该用大量的数据添加区段来优化介质空间。 对于 DVD+R 来说区段的数量限制为 154， 对于 DVD-R 来说大约是 2000，对于双层 DVD+R 来说是 127。
====

=== 更多的信息

要获得更多的关于 DVD 的信息 `dvd+rw-mediainfo /dev/cd0` 命令可以运行来获得 更多的信息。

更多的关于 dvd+rw-tools 的信息可以在 man:growisofs[1] 联机手册找到，在 http://fy.chalmers.se/~appro/linux/DVD+RW/[dvd+rw-tools web site] 和 http://lists.debian.org/cdwrite/[cdwrite mailing list] 联接中也可找到。

[NOTE]
====
`dvd+rw-mediainfo` 命令的输出结果记录， 以及介质的问题会被用来做问题报告。 如果没有这些输出， 就很难帮您解决问题。
====

[[creating-dvd-ram]]
=== 使用 DVD-RAM

==== 配置

DVD-RAM 刻录机通常使用 SCSI 或 ATAPI 两种接口之一。 对于 ATAPI 设备， DMA 传输模式必须手工启用。 这一工作可以通过在 [.filename]#/boot/loader.conf# 文件中增加下述配置来完成：

[.programlisting]
....
hw.ata.atapi_dma="1"
....

==== 初始化介质

如本章前面的介绍所言， DVD-RAM 可以视为一移动硬盘。 与任何其它型号的移动硬盘类似， 首次使用它之前， 应首先 "初始化" DVD-RAM。 在下面的例子中， 我们将在全部空间上使用标准的 UFS2 文件系统：

[source,shell]
....
# dd if=/dev/zero of=/dev/acd0 bs=2k count=1
# bsdlabel -Bw acd0
# newfs /dev/acd0
....

您应根据实际情况将 [.filename]#acd0# 改为您所使用的设备名。

==== 使用介质

一旦您在 DVD-RAM 上完成了前面的操作， 就可以像普通的硬盘一样挂接它了：

[source,shell]
....
# mount /dev/acd0 /mnt
....

然后就可以正常地对 DVD-RAM 进行读写了。

[[floppies]]
== 创建和使用软盘

把数据存储在软盘上有时也是十分有用的。 例如， 在没有其它可靠的存储介质， 或只需将少量数据传到其他计算机时。

这一章将介绍怎样在 FreeBSD 上使用软盘。 在使用 DOS 3.5 英寸软盘时首要要涉及的就是格式化， 但其概念与其它的软盘格式化极为类似。

=== 格式化软盘

==== 设备

软盘的访问像其它设备一样是通过在 [.filename]#/dev# 中的条目来实现的。 直接访问软盘时， 只需简单地使用 [.filename]#/dev/fdN# 来表示。

==== 格式化

一张软盘在使用这前必须先被低级格式化。 通常卖主已经做过了，但格式化是检测介质完整性的一种好方法。 尽管这有可能会强取大量（或少量）的硬盘大小，但 大部分磁盘都能被格式化设计为 1440kB 。

低级格式化软盘你需要使用 man:fdformat[1] 命令。这个程序需要设备名作为参数。

要留意一切错误信息，这些信息能够帮助你确定 磁盘的好与坏。

===== 软盘的格式化

使用 [.filename]#/dev/fdN# 设备来格式化软盘。插入一张新的 3.5 英寸的软盘在你的设备中：

[source,shell]
....
# /usr/sbin/fdformat -f 1440 /dev/fd0
....

=== 磁盘标签

经过低级格式化后， 你需要给它分配一个标签。 这个磁盘标签以后会被删去， 但系统需要使用它来确定磁盘的尺寸。

新的磁盘标签将会接管整个磁盘，会包括所有合适的关于软盘的 geometry 信息。 磁盘标签的 geometry 值列在 [.filename]##/etc/disktab##中。

现在可以用下面的方法来使用 man:bsdlabel[8] 了：

[source,shell]
....
# /sbin/bsdlabel -B -w /dev/fd0 fd1440
....

=== 文件系统

现在对软盘进行高级格式化。 这会在它上面安置一个新的文件系统，可使 FreeBSD 来对它进行读写。 在创建完新的文件系统后，磁盘标签将被消毁，所以如果你想重新格式化磁盘， 你必须重新创建磁盘标签。

软盘的文件系统可以选择 UFS 或 FAT 。 FAT 是通常情况下软盘比较好的选择。

要制作新的文件系统在软盘上，可以使用下面的命令：

[source,shell]
....
# /sbin/newfs_msdos /dev/fd0
....

现在磁盘已经可以进行读取和使用。

=== 使用软盘

要使用软盘，需要先使用 man:mount_msdosfs[8] 挂接它。 除此之外， 也可以使用在 ports 套件中的 package:emulators/mtools[] 程序。

[[backups-tapebackups]]
== 用磁带机备份

主流的磁带机有 4mm, 8mm, QIC, mini-cartridge 和 DLT。

[[backups-tapebackups-4mm]]
=== 4mm (DDS: Digital Data Storage)

4mm 磁带机正在逐步取代 QIC 成为工作站备份数据的首选设备。 在 Conner 收购了 QIC 磁带机领域领先的制造商 Archive 之后不久， 即不再生产这种磁带机， 这使得这一趋势变得愈加明显。 4mm 的驱动器更加小和安静，但对于数据保存的可靠性仍不及 8mm 驱动器。它要比 8mm 的便宜和小得多 (3 x 2 x 0.5 inches, 76 x 51 x 12 mm) 。和 8mm 的一样，读写关的寿命都不长，因为它们同样使用螺旋式 的方式来读写。

这些设备的数据传输的速度约在 ~150 kB/s 到 ~500 kB/s 之间， 存储空间从 1.3 GB 到 2.0 GB 之间，硬件压缩可使空间加倍。磁带库 单元可以有 6 台磁带机，120 个磁带匣，以自动切换的方式使用同一个磁带柜， 磁带库的容量可达 240 GB 。

DDS-3 标准现在支持的磁带机容量最高可达到 12 GB (或压缩的 24 GB )。

4mm 和 8mm 同样都使用螺旋式读写的方式，所有螺旋式读写的优点及缺点， 都可以在 4mm 和 8mm 磁带机上看到。

磁带在经过 2,000 次的使用或 100 次的全部备份后，就该退休了。

[[backups-tapebackups-8mm]]
=== 8mm (Exabyte)

8mm 磁带机是最常见的 SCSI 磁带机，也是磁带交换的最佳选择。几乎每个 工作站都有一台 2 GB 8mm 磁带机。8mm 磁带机可信度高、方便、安静。 卡匣小 (4.8 x 3.3 x 0.6 inches; 122 x 84 x 15 mm)而且不贵。8mm 磁带机 的下边是一个短短的读写头，而读写头的寿命取决于磁带经过读写头时，相对高 速运动情况。

数据传输速度约在 250 kB/s 到 500 kB/s 之间，可存储的空间从 300 MB 到 7 GB，硬件压缩可使空间加倍。磁带库单元可以有 6 台磁 带机，120 个磁带匣，以自动切换的方式使用同一个磁带柜，磁带库的容量可达 840+ GB。

Exabyte "Mammoth" 模型支持 12 GB 的容量在一个磁带 上(压缩后可达 24 GB )相当于普通磁带的二倍。

数据是使用螺旋式读写的方式记录在磁带上的，读写头和磁带约相差 6 度， 磁带以 270 度缠绕着轴，并抵住读写头，轴适时地旋转，使得磁带具有高密度， 从一端到另一端并可使磁道紧密地分布。

[[backups-tapebackups-qic]]
=== QIC

QIC-150 磁带和磁带机可能是最常见的磁带机和介质了。 QIC 磁带机是最便宜的 "正规" 备份设备。 它的缺点在于介质的价格较高。 QIC 磁带要比 8mm 或 4mm 磁带贵， 每 GB 的数据存储价格可能最高高出 5 倍。 但是， 如果您的需求能够为半打磁带所满足的话， 那么 QIC 可能是明智之选。 QIC 是 _最_ 常见的磁带机。 每个站点都会有某种密度的 QIC。 这有时是一种麻烦， QIC 有很多在外观上相似（有时一样），但是密度不同的磁带。 QIC 磁带机噪音很大。 它们在寻址以及读写时都会发出声音。 QIC 磁带的规格是 6 x 4 x 0.7 英寸 (152 x 102 x 17 毫米)。

数据传输的速度介于 150 kB/s 到 500 kB/s 之间，可存储的空间 从 40 MB 到 15 GB。较新的 QIC 磁带机具有硬件压缩的功能。 QIC 的使用率愈来愈低，渐渐被 DAT 所取代。

数据以磁道的方式记录在磁带上，磁道数及磁道的宽度会根据容量而有所不同。 通常新的磁带机具有的向后兼容的读取功能（通常也具备写入的功能）。对于数据 的安全性，QIC 具有不错的评价。

磁带机在经过 5,000 次的使用后，就该退休了。

[[backups-tapebackups-dlt]]
=== DLT

在这一章列出的磁带机中 DLT 具有最快的数据传输率。 1/2" (12.5mm) 的 磁带包含在单轴的磁带匣 (4 x 4 x 1 inches; 100 x 100 x 25 mm)中。磁带匣 的一边是一个旋转匣道，通过匣道的开合，可以让磁带卷动。磁带匣内只有一个 轴，而本章中所提到的其他磁带匣都是有两个轴的（9磁道磁带机例外）。

数据传输的速度约 1.5 MB/s，是 4mm, 8mm, 或 QIC 磁带机的三倍。 可存储的空间从 10 GB 到 20 GB，具有磁带机数据库。磁带机数据库 单元可以有 1 to 20 台磁带机，5 到 900 个磁带匣，磁带机数据库的容量可达 50 GB 到 9 TB 。

如果要压缩的话，DLT 型 IV 格式的磁带机最高可支持 70 GB 的存储 容量。

数据存储在平行于磁带运行方向的磁道上（就像 QIC 磁带），一次写入两个 磁道。读写头的寿命相当长，每当磁带停止前进，磁带与读写头之间没有相对运动。

=== AIT

AIT 是 Sony 开发的一种新格式，每个磁带最高可以存储 50 GB。磁带 机使用内存芯片来保存磁带上的索引内容。这个索引能够被磁带机驱动器快速阅读 来搜索磁带机上文件所处的位置，而不像其他的磁带机需要花几分钟的时间才能找 到文件。像 SAMS:Alexandria 这样的软件：能够操 作四十或者更多的 AIT 磁带库，直接使用内存芯片来进行通信把内容显示在屏幕上， 以决定把什么文件备份到哪个磁带上，加载和恢复数据。

像这样的库成本大概在 $20,000 美元左右，零售市场可能还要贵一点。

=== 第一次使用新的磁带机

当在一块完全空白的磁带上尝试定入数据时，会得到类似下面这样的错误信息：

[source,shell]
....
sa0(ncr1:4:0): NOT READY asc:4,1
sa0(ncr1:4:0):  Logical unit is in process of becoming ready
....

信息指出这块磁带没有块编号 (block 编号为 0)。在 QIC-525 之后的所有 QIC 磁带，都采用 QIC-525 标准，必须写入一个 Identifier Block 。对于这种问题， 有以下两种解决的办法：

* 用``mt fsf 1`` 可以让磁带机对磁带写入 Identifier Block 。
* 使用面板上的按钮磁带。
+ 
再插入一次，并存储 `dump` 数据到磁带上。
+ 
这时``dump`` 将传回 `DUMP: End of tape detected` ，然后您会得到这样的错误信息： `HARDWARE FAILURE info:280 asc:80,96`。
+ 
这时用 `mt rewind` 来倒转磁带。
+ 
磁带操作的后续操作就完成了。

[[backups-floppybackups]]
== 用软盘备份

[[floppies-using]]
=== 能够使用软盘来备份数据吗

软磁盘通常是用来备份的设备中不太合适的设备：

* 这种设备不太可靠，特别是长期使用。
* 备份和恢复都很慢
* 它们只有非常有限的存储容量。

然而，如果没有其它的备份数据的方法，那软盘备份总比没有备份要好。

如果必须使用软盘的话，必须确保盘片的质量。软盘在办公室中使用已经有许多 年了。最好使用一些名牌厂商的产品以确保质量。

[[floppies-creating]]
=== 如何备份数据到软盘

最好的备份数据到软盘的方法是使用 man:tar[1] 程序加上 `-M` 选项， 它可以允许数据备份到多张软盘上。

要备份当前目录中所有的文件可以使用这个命令 (需要有 ``root``权限)：

[source,shell]
....
# tar Mcvf /dev/fd0 *
....

当第一张盘满的时候， man:tar[1] 会指示您插入下一张盘，插入第二张盘之后就按回车。

[source,shell]
....
Prepare volume 2 for /dev/fd0 and hit return:
....

这个步骤可能需要重复很多次，直到这些文件备份完成为止。

[[floppies-compress]]
=== 可以压缩备份吗

不幸的是，man:tar[1] 在为多卷文件作备份时是不允许使用 `-z` 选项的。当然，可以用 man:gzip[1] 压缩所有的文件，把它们打包到磁盘，以后在用 man:gunzip[1] 解开。

[[floppies-restoring]]
=== 如何恢复备份

要恢复所有文件：

[source,shell]
....
# tar Mxvf /dev/fd0
....

有两种方法来恢复软盘中的个别文件。首先，就要用第一张软盘启动：

[source,shell]
....
# tar Mxvf /dev/fd0 filename
....

man:tar[1] 程序会提示您插入后面的软盘，直到它找到所需要的文件。

如果您知道哪个文件在哪个盘上，您就可以插入那张盘，然后使用上同同样的命令。 如果软盘上的第一个文件与前面的文件是连续的，那 man:tar[1] 命令会警告您它无法 恢复，即使您不要求它这样做。

[[backup-strategies]]
== 备份策略

设计备份计划的第一要务是确认以下问题皆已考虑到：

* 磁盘故障
* 文件的意外删除
* 随机的文件损毁
* 机器完全损毁 (例如火灾)， 包括破坏全部在线备份。

针对上述的每个问题采用完全不同的技术来解决是完全可行的。 除了只包含少量几乎没有价值数据的个人系统之外， 一般来说很少有一种技术能够同时兼顾前面所有的需要。

可以采用的技术包括：

* 对整个系统的数据进行存档， 备份到永久性的离线介质上。 这种方法实际上能够提供针对前面所有问题的保护， 但这样做通常很慢， 而且恢复时会比较麻烦。 您可以将备份置于近线或在线的状态， 然而恢复文件仍然是一个难题， 特别是对没有特权的那些用户而言。
* 文件系统快照。 这种技术实际上只对无意中删除文件这一种情况有用， 但在这种情况下它会提供 _非常大_ 的帮助， 而且访问迅速， 操作容易。
* 直接复制整个文件系统和/或磁盘 (例如周期性地对整个机器做 man:rsync[1])。 通常这对于在网络上的单一需求最为适用。 要为磁盘故障提供更为通用的保护， 通常这种方法要逊于 RAID。 对于恢复无意中删除的文件来说， 这种方法基本上与 UFS 快照属于同一层次， 使用哪一个取决于您的喜好。
* RAID。 它能够最大限度地减少磁盘故障导致的停机时间。 其代价是需要处理更为频繁的磁盘故障 (因为磁盘的数量增加了)， 尽管这类故障不再需要作为非常紧急的事项来处理。
* 检查文件的指纹。 man:mtree[8] 工具对于这种操作非常有用。 尽管这并不是一种备份的技术， 但它能够确保您有机会注意到那些您需要求助于离线备份的事情。 这对于离线备份非常重要， 而且应有计划地加以检查。

很容易列举更多的技术， 它们中有许多实际上是前面所列出的方法的变种。 特别的需求通常会需要采用特别的技术 (例如， 备份在线运行的数据库， 往往需要数据库软件提供某种方法来完成中间步骤) 来满足。 最重要的事情是， 一定要了解需要将数据保护起来免受何种风险， 以及发生问题时应该如何处理。

[[backup-basics]]
== 备份程序

有三个主要的备份程序 man:dump[8]、man:tar[1] 和 man:cpio[1]。

=== Dump 和 Restore

`dump` 和 `restore` 是 UNIX(R) 传统的备份程序。 它以 block 而不是以文件为单位来备份数据、链接或目录。 `dump` 备份的是设备上的整个文件系统， 不能只备份一个文件系统的部分或是用到两个以上文件系统的目录树。 与其他备份软件不同的是， `dump` 不会写文件和目录到磁带机， 而是写入包含文件 和目录的原始数据块。 当需要恢复数据的时候，`restore` 默认在 [.filename]#/tmp/# 下保存临时数据 - 如果你正在操作的恢复盘只有比较小的 [.filename]#/tmp# 的话， 你可能需要把环境变量 `TMPDIR` 设置到一个有更多空间的目录， 使得此过程更容易成功。

[NOTE]
====
如果在您的 root 目录使用 `dump`， 将不需要备份 [.filename]#/home#、[.filename]#/usr# 或其他目录， 因为这些是典型的其他文件系统或符号连接到那些文件系统的加载点。
====

`dump` 是最早出现于 AT&T UNIX 的 Version 6 (约 1975)。 默认的参数适用于 9-track 磁带(6250 bpi)， 所以如果要用高密度的磁带（最高可达 62,182 ftpi）， 就不能用默认的参数， 而要另外指定参数。 这些默认值必须在命令行被修改以更好地利用当前磁带机的功能。

`rdump` 和 `rrestore` 可以通过网络在另一台计算机的磁带机上备份数据。 这两个程序都是依靠 man:rcmd[3] 和 man:ruserok[3] 来访问远程的磁带机。 因此，运行备份的用户必须要有远程主机的 [.filename]#.rhosts# 访问权。 `rdump` 和 `rrestore` 的参数必须适用于远程主机 例如，当您从 FreeBSD 连到一台 SUN 工作站 knomodo 去使用磁带机时，使用：

[source,shell]
....
# /sbin/rdump 0dsbfu 54000 13000 126 komodo:/dev/nsa8 /dev/da0a 2>&1
....

要注意的是：必须检查您在使用 [.filename]#.rhosts# 时的安全情况。

也可以通过使用 `ssh` 用一个更安全的方式来使用 `dump` 和 `restore` 。

.通过 ssh 使用 `dump`
[example]
====

[source,shell]
....
# /sbin/dump -0uan -f - /usr | gzip -2 | ssh -c blowfish \
          targetuser@targetmachine.example.com dd of=/mybigfiles/dump-usr-l0.gz
....

====

或使用 `dump`　的 built-in 方法， 设置环境变量 `RSH`：

.通过设置 ssh 环境变量 `RSH` 使用 `dump`
[example]
====

[source,shell]
....
# RSH=/usr/bin/ssh /sbin/dump -0uan -f targetuser@targetmachine.example.com:/dev/sa0 /usr
....

====

=== `tar`

man:tar[1] 也同样是在第 6 版 AT&T UNIX (大约是 1975 前后) 出现的。 `tar` 对文件系统直接操作； 其作用是把文件和目录写入磁带。 `tar` 并不支持 man:cpio[1] 所提供的全部功能， 但也不需要 `cpio` 所需要使用的诡异的命令行管道。

要 `tar` 到连接在名为 `komodo` 的 Sun 机器上的 Exabyte 磁带机， 可以使用：

[source,shell]
....
# tar cf - . | rsh komodo dd of=tape-device obs=20b
....

如果您担心通过网络备份会有安全问题，应当使用 `ssh` ， 而不是 `rsh`。

=== `cpio`

man:cpio[1] 是 UNIX(R) 最早用来作文件交换的磁带机程序。它有执行字节 交换的选项，可以用几种不同的格式写入，并且可以将数据用管道传给其他程序。 `cpio` 没办法自动查找目录树内的文件列表，必须通过标准 输入 [.filename]#stdin# 来指定。

`cpio` 不支持通过网络的备份方式。可以使用 pipeline 和 `rsh` 来传送数据给远程的磁带机。

[source,shell]
....
# for f in directory_list; do
find $f >> backup.list
done
# cpio -v -o --format=newc < backup.list | ssh user@host "cat > backup_device"
....

这里的 _directory_list_ 是要备份的目录列表， _user_@_host_ 结合了将 要执行备份的用户名和主机名，_backup_device_ 是写 入备份的设备（如 [.filename]#/dev/nsa0#）。

=== `pax`

man:pax[1] 是符合 IEEE/POSIX(R) 标准的程序。多年来各种不同版本 的 `tar` 和 `cpio` 间有些不兼容。 为了防止这种情况，并使其标准化，POSIX(R) 出了这套新的工具程序。 `pax` 尝试可以读写各种 `cpio` 和 `tar` 的格式，并可以自己增加新的格式。它的命令 集比 `tar` 更接近 `cpio`。

[[backups-programs-amanda]]
=== Amanda

Amanda (Advanced Maryland Network Disk Archiver) 并非单一的程序，而是一个客户机/服务器模式的备份系统 。一台 Amanda 服务器可以备份任意数量执行 Amanda 的客户机或是将连上 Amanda 服务器的计算机上的数据备份到一台磁带机上。一个常见的问题是，数据写入磁带机的时间将超 过取行数据的时间，而 Amanda 解决了这个问题。它使用一个 "holding disk" 来同时备份几个文件系统。 Amanda 建立 "archive sets" 的一组磁带，用来备份在 Amanda 的配置文件中所列出的完整的文件系统。

Amanda 配置文件提供完整的备份控制及 Amanda 产生的网络传输。 Amanda 可以使用上述任何一个设备程序来向磁带写入数据。Amanda 可以从 port 或 package 取得，它并非系统默认安装的。

=== Do Nothing 备份策略

"Do nothing" 不是一个程序，而是被广泛使用的备份策略。 不需要预算，不需要备份的计划表，全部都不用。如果您的数据发生了什么问题， 忽略它！

如果您的时间和数据不值得您做这些事，那么 "Do nothing" 将是最好的备份程序。要注意的是，UNIX(R) 是相当好用的工具，您可能在几个月 内，就发现您已经收集了不少对您来说相当具有价值的文件和程序。

"Do nothing" 对于像 [.filename]#/usr/obj# 和其他 可由您的计算机产生的文件来说，是最好的方法。例如这本手册包含有 HTML 或 PostScript(R) 格式的文件。这些文档格式是从 SGML 输入文件创建的。创建 HTML 或 PostScript(R) 格式的文件的备份就没有必要了。只要经常备份 SGML 文件就够了。

=== 哪个备份程序最好？

在man:dump[8] _时期_ Elizabeth D. Zwicky 测试了所有以上列出的备份程序。在各种各样怪异的文件系统中， `dump` 是您明智的选择。Elizabeth 建立起各种各样、 奇怪或常见的文件系统，并用各种备份程序，测试在各种文件系统上备份 及恢复数据。这些怪异之处包括：具有 holes 和一个 nulls block 的文件， 文件名具有有趣字符，无法读写的文件及设备，在备份时改变文件大小，在 备份时建立或删除的文件。她将结果写在： LISA V in Oct. 1991. 参阅 http://www.coredumps.de/doc/dump/zwicky/testdump.doc.html[torture-testing Backup and Archive Programs].

=== 应急恢复程序

==== 在出现灾难前

在遇到灾难前，只需要执行以下四个步骤：

第一，打出您的每个磁盘驱动器的磁盘标签 (例如： `bsdlabel da0 | lpr`)，文件系统表， ([.filename]#/etc/fstab#) ，以及所有启动信息， 并将其复制两份。

第二， 刻录一张 "livefs" CDROM。 这个 CDROM 包含了用于引导进入 FreeBSD "livefs" 修复模式的支持， 这种模式允许用户执行许多任务， 例如执行 man:dump[8]、 man:restore[8]、 man:fdisk[8]、 man:bsdlabel[8]、 man:newfs[8]、 man:mount[8]， 等等。 Livefs CD 映像文件随 FreeBSD/i386 {rel120-current}-RELEASE 提供， 可以从 link:ftp://ftp.FreeBSD.org/pub/FreeBSD/releases/i386/ISO-IMAGES/{rel120-current}/FreeBSD-{rel120-current}-RELEASE-i386-livefs.iso[ftp://ftp.FreeBSD.org/pub/FreeBSD/releases/i386/ISO-IMAGES/{rel120-current}/FreeBSD-{rel120-current}-RELEASE-i386-livefs.iso] 获得。

第三，定期将数据备份到磁带。任何在上次备份后的改变都无法恢复。记得将 磁盘写保护。

第四， 测试在第二步所建立的 "livefs" CDROM 及备份的磁带。 写下笔记， 并和这张 CDROM、 打印副本以及磁带放在一起。 您在需要恢复数据时可能正心慌意乱， 而这些记录可能会帮助您避免毁掉备份磁带 （怎么会发生这种情况呢？ 举例来说， 本应执行 `tar xvf /dev/sa0` 命令时， 您可能会不小心输入 `tar cvf /dev/sa0`， 从而覆盖备份磁带）。

保险起见， 您可以制作两份 "livefs" CDROM 和备份磁带。 其中一份应放到其它地方， 这里说的其他地方当然不是指同一栋办公楼的地下室， 世贸中心的一大批公司已经学到了血的教训。 保存这份备份的位置应该与您的计算机和磁盘驱动器越远越好。

==== 出现灾难后

关键问题是： 您的硬件是否幸免于难？ 由于已经做好了定期的备份工作， 因此并不需要担心软件的问题。

如果硬件已经损坏， 这些部分应该在尝试使用计算机之前换掉。

如果硬件还能用， 将 "livefs" CDROM 插入 CDROM 驱动器并引导系统。 您将看到最初安装系统时的菜单。 选择正确的国家之后， 选择 [.guimenuitem]#Fixit -- Repair mode with CDROM/DVD/floppy or start a shell# 选项， 然后再选择 [.guimenuitem]#CDROM/DVD -- Use the live filesystem CDROM/DVD# 这项。 您可以使用 `restore` 以及其他位于 [.filename]#/mnt2/rescue# 的工具。

分别恢复每一个文件系统

试着 `mount` （例如： `mount /dev/da0a /mnt`） 第一个磁盘上的 root 分区。 如果 bsdlabel 已经毁坏， 则需要使用 `bsdlabel` 根据您先前打印存档的记录来重新分区并分配磁盘标签。 接着使用 `newfs` 重建文件系统。 以读写方式重新挂载磁盘的根分区 (`mount -u -o rw /mnt`)。 使用您的备份程序以及备份磁带恢复文件系统数据 （例如 `restore vrf /dev/sa0`）。 最后卸下文件系统 （例如 `umount /mnt`）。 对于毁掉的其他文件系统， 重复执行前面这些操作。

当您的系统正常启动后， 将您的数据备份到新的磁带。 任何造成数据丢失的的灾难都可能再次发生。 现在花一些时间， 也许可以在下次发生灾难时救您一把。

[[disks-virtual]]
== 网络、内存和 和以及映像文件为介质的虚拟文件系统

除了插在您计算机上的物理磁盘： 软盘、 CD、 硬盘驱动器， 等等之外， FreeBSD 还能识别一些其他的磁盘形式 - _虚拟磁盘_。

这还包括， 如 crossref:network-servers[network-nfs,网络文件系统 (Network File System)] 和 Coda一类的网络文件系统、 内存以及映像文件为介质的虚拟文件系统。

随运行的 FreeBSD 版本不同， 用来创建和使用以映像文件介质文件系统和内存文件系统的工具也不尽相同。

[NOTE]
====
系统会使用 man:devfs[5] 来创建设备节点， 这对用户来说是透明的。
====

[[disks-mdconfig]]
=== 以映像文件为介质的文件系统

在 FreeBSD 系统中， 可以用 man:mdconfig[8] 程序来配置和启用内存磁盘， man:md[4]。 要使用 man:mdconfig[8]， 就需要在内核配置文件中添加 man:md[4] 模块来支持它：

[.programlisting]
....
device md
....

man:mdconfig[8] 命令支持三种类型的虚拟文件系统： 使用 man:malloc[9]，来分配内存文件系统，内存文件系统作为文件或作为 备用的交换分区。一种使用方式是在文件中来挂载一个软盘和 CD 镜像。

将一个暨存的映像文件作为文件系统挂载：

.使用 `mdconfig` 挂载已经存在的映像文件
[example]
====

[source,shell]
....
# mdconfig -a -t vnode -f diskimage -u 0
# mount /dev/md0 /mnt
....

====

使用 man:mdconfig[8] 来创建新的映像文件:

.使用 `mdconfig` 将映像文件作为文件系统挂载
[example]
====

[source,shell]
....
# dd if=/dev/zero of=newimage bs=1k count=5k
5120+0 records in
5120+0 records out
# mdconfig -a -t vnode -f newimage -u 0
# bsdlabel -w md0 auto
# newfs 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
....

====

如果没有通过 `-u` 选项指定一个标识号 man:mdconfig[8] 将使用 man:md[4] 为它自动选择一个未用的设备标识号。 分配给它的标识名将被输出到标准输出设备， 其形式是与 [.filename]#md4# 类似。 如果希望了解更多相关信息， 请参见联机手册 man:mdconfig[8]。

man:mdconfig[8] 功能很强大， 但在将映像文件作为文件系统挂载时， 仍需使用许多行的命令。 为此 FreeBSD 也提供了一个名为 man:mdmfs[8] 的工具， 该程序使用 man:mdconfig[8] 来配置 man:md[4] 设备， 并用 man:newfs[8] 在其上创建 UFS 文件系统， 然后用 man:mount[8] 来完成挂载操作。 例如， 如果想创建和挂接像上面那样的文件系统映像， 只需简单地执行下面的步骤：

.使用 `mdmfs` 命令配置和挂载一个映像文件为文件系统
[example]
====

[source,shell]
....
# dd if=/dev/zero of=newimage bs=1k count=5k
5120+0 records in
5120+0 records out
# mdmfs -F newimage -s 5m md0 /mnt
# df /mnt
Filesystem 1K-blocks Used Avail Capacity  Mounted on
/dev/md0        4718    4  4338     0%    /mnt
....

====

如果你使用没有加标识号的 `md` 选项， man:mdmfs[8] 将使用 man:md[4] 的自动标示号特性来自动为其 选择一个未使用的设备。更详细的 man:mdmfs[8]，请参考联机手册。

[[disks-md-freebsd5]]
=== 以内存为介质的文件系统

一般来说， 在建立以内存为介质的文件系统时， 应使用 "交换区作为介质 (swap backing)"。 使用交换区作为介质， 并不意味着内存盘将被无条件地换出到交换区， 它只是表示将根据需要从可换出的内存池中分配内存。 此外， 也可以使用 man:malloc[9] 创建以内存作为介质的文件系统。 不过在内存不足时， 这种方式可能引致系统崩溃。

.用 `mdconfig` 创建新的内存盘设备
[example]
====

[source,shell]
....
# 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
....

====

.使用 `mdmfs` 来新建内存介质文件系统
[example]
====

[source,shell]
....
# mdmfs -s 5m md2 /mnt
# df /mnt
Filesystem 1K-blocks Used Avail Capacity  Mounted on
/dev/md2        4846    2  4458     0%    /mnt
....

====

=== 从系统中移除内存盘设备

当不再使用内存盘设备时， 应将其资源释放回系统。 第一步操作是卸下文件系统， 然后使用 man:mdconfig[8] 把虚拟磁盘从系统中分离， 以释放资源。

例如， 要分离并释放所有 [.filename]#/dev/md4# 使用的资源， 应使用命令：

[source,shell]
....
# mdconfig -d -u 4
....

`mdconfig -l` 命令可以列出关于配置 man:md[4] 设备的信息。

[[snapshots]]
== 文件系统快照

FreeBSD 提供了一个和 crossref:cutting-edge[soft-updates,Soft Updates] 关联的新功能: 文件系统快照

快照允许用户创建指定文件系统的映像，并把它们当做一个文件来对待。 快照文件必须在文件系统正在使用时创建，一个用户对每个文件系统创建的 快照不能大于20个。活动的快照文件被记录在超级块中，所以它们可以在系统 启动的时候一块进行挂接后摘掉。当一个快照不再需要时，可以使用标准的 man:rm[1] 使用来使其删除。快照可以以任何顺序进行移除，但所有使用 的快照不可能同时进行移除，因为其它的快照将有可能互相引用一些块。

不可改的 `snapshot` 文件标志， 是由 man:mksnap_ffs[8] 在完成创建快照文件时设置的。 man:unlink[1] 命令是一个特例， 以允许删除快照文件。

快照可以通过 man:mount[8] 命令创建。 将文件系统 [.filename]#/var# 的快照放到 [.filename]#/var/snapshot/snap# 可以使用下面的命令：

[source,shell]
....
# mount -u -o snapshot /var/snapshot/snap /var
....

作为选择，你也可以使用 man:mksnap_ffs[8] 来创建一个快照：

[source,shell]
....
# mksnap_ffs /var /var/snapshot/snap
....

可以查找文件系统中的快照文件 (例如 [.filename]#/var#)， 方法是使用 man:find[1] 命令：

[source,shell]
....
# find /var -flags snapshot
....

当快照文件被创建好后，可以用于下面一些目的：

* 有些管理员用文件快照来进行备份， 因为快照可以被转移到 CD 或磁带上。
* 文件系统一致性检查程序 man:fsck[8] 可以用来检查快照文件。 如果文件系统在挂接前是一致的， 则检查结果也一定是一致的 (也就是不会做任何修改)。 实际上这也正是后台 man:fsck[8] 的操作过程。
* 在快照上运行 man:dump[8] 程序。 dump 将返回包含文件系统和快照的时间戳。man:dump[8] 也能够抓取快照，使用 `-L` 标志可以首先创建快照， 完成 dump 映像之后再自动删除它。
* 用 man:mount[8] 来挂接快照作为文件系统的一个冻结的镜像。 要 man:mount[8] 快照 [.filename]#/var/snapshot/snap# 运行：
+
[source,shell]
....
# mdconfig -a -t vnode -f /var/snapshot/snap -u 4
# mount -r /dev/md4 /mnt
....

现在你就可以看到挂接在 [.filename]#/mnt# 目录下的 [.filename]#/var# 文件系统的快照。 每一样东西都保存的像它创建时的状态一样。 唯一例外的是更早的快照文件将表现为长度为 0 的文件。 用完快照文件之后可以把它卸下，使用：

[source,shell]
....
# umount /mnt
# mdconfig -d -u 4
....

想了解更多关于 `softupdates` 和 文件系统快照的信息， 包括技术说明， 可以访问 Marshall Kirk McKusick 的 WWW 站点 http://www.mckusick.com/[http://www.mckusick.com/]。

[[quotas]]
== 文件系统配额

配额是操作系统的一个可选的功能， 它允许管理员以文件系统为单元， 限制分派给用户或组成员所使用的磁盘空间大小或是使用的总文件数量。 这经常被用于那些分时操作的系统上， 对于这些系统而言， 通常希望限制分派到每一个用户或组的资源总量， 从而可以防止某个用户占用所有可用的磁盘空间。

=== 配置系统来启用磁盘配额

在决定使用磁盘配额前，确信磁盘配额已经在内核中配置好了。只要在在内核 中配置文件中添加下面一行就行了：

[.programlisting]
....
options QUOTA
....

在默认情况下 [.filename]#GENERIC# 内核是不会启用这个功能的， 所以必须配置、重建和安装一个定制的内核。请参考 FreeBSD 内核配置 crossref:kernelconfig[kernelconfig,配置FreeBSD的内核] 这章了解更多有关内核配置的信息。

接下来，需要在 [.filename]#/etc/rc.conf# 中启用磁盘配额。可以 通过添加下面这行来完成：

[.programlisting]
....
enable_quotas="YES"
....

为了更好的控制配额时的启动，还有另外一个可配置的变量。通常 启动时，集成在每个文件系统上的配额会被配额检查程序 man:quotacheck[8] 自动检查。配额检查功能能够确保在配额数据库中 的数据正确地反映了文件系统的数 据情况。这是一个很耗时间的处理进程，它会影响系统的启动时间。如果 想跳过这一步，可以在文件 [.filename]#/etc/rc.conf# 加入 下面这一行来达到目的：

[.programlisting]
....
check_quotas="NO"
....

最后，要编辑 [.filename]#/etc/fstab# 文件，以在每一个 文件系统基础上启用磁盘配额。这是启用用户和组配额，或同时启用用户 和组配额的地方。

要在一个文件系统上启用每个用户的配额，可以在 [.filename]#/etc/fstab# 里添加 `userquota` 选项在要雇用配额文件的系统上。例如：

[.programlisting]
....
/dev/da1s2g   /home    ufs rw,userquota 1 2
....

同样的，要启用组配额，使用 `groupquota` 选项来代替 `userquota` 选项。要同时启用用户和组配额，可以这样做：

[.programlisting]
....
/dev/da1s2g    /home    ufs rw,userquota,groupquota 1 2
....

默认情况下，配额文件是存放在文件系统的以 [.filename]#quota.user# 和 [.filename]#quota.group# 命名的根目录下。可以查看 man:fstab[5] 联机手册了解更多信息。 尽管联机手册 man:fstab[5] 提到， 可以为配额文件指定其他的位置， 但并不推荐这样做， 因为不同的配额工具并不一定遵循此规则。

到这儿，可以用新内核重新启动系统。 [.filename]#/etc/rc# 将自动 运行适当的命令来创建最初的配额文件，所以并不需要手动来创建任何零长度的配额 文件。

在通常的操作过程中，并不要求手动运行 man:quotacheck[8]、 man:quotaon[8], 或 man:quotaoff[8] 命令，然而可能需要阅读与他们的操作 相似的联机手册。

=== 设置配额限制

一旦您配置好了启用配额的系统，可以检查一下它们是真的有用。 可以这样做：

[source,shell]
....
# quota -v
....

您应该能够看到一行当前正在使用的每个文件系统启用的磁盘配额 使用情况的摘要信息。

现在可以使用 man:edquota[8] 命令准备启用配额限制。

有几个有关如何强制限制用户或组可以分配到的磁盘空间大小的选项。 您可以限制磁盘存储块的配额， 或文件的数量， 甚至同时限制两者。 这些限制最终可分为两类： 硬限制和软限制。

硬性限制是一种不能越过的限制。 一旦用户达到了系统指定的硬性限制， 他就无法在对应的文件系统分配到更多的资源。 例如， 如果文件系统上分给用户的硬性限制是 500 KB， 而现在已经用掉了 490 KB， 那么这个用户最多还能再分配 10 KB 的空间。 换言之， 如果这时试图再分配 11 KB， 则会失败。

而与此相反， 软性限制在一段时间内是允许越过的。 这段时间也称为宽限期， 其默认值是一周。 如果一个用户延缓时间太长的话，软限制将会变成硬限制， 而继续分配磁盘空间的操作将被拒绝。 当用户占用的空间回到软性限制值以下时， 宽限期将重新开始计算。

下面是一个运行 man:edquota[8] 时看到的例子。当 man:edquota[8] 命令被调用时，会被转移进 `EDITOR` 环境变量指派的编辑 器中，允许编辑配额限制。如果环境变量没有设置，默认在 vi 编辑器上进行。

[source,shell]
....
# edquota -u test
....

[.programlisting]
....
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)
....

在每一个启用了磁盘配额的文件系统上，通常会看到两行。一行是 block 限制，另一行是 inode 限制。简单地改变要修改的配额限制的值。 例如，提高这个用户软限制的数值到 500 ，硬限制到 600 ：

[.programlisting]
....
/usr: kbytes in use: 65, limits (soft = 50, hard = 75)
....

to:

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

当离开编辑器的时候，新的配额限制设置将会被保存。

有时，在 UIDs 的范围上设置配额限制是非常必要的。这可以通过在 man:edquota[8] 命令后面加上 `-p` 选项来完成。首先， 给用户分配所需要的配额限制，然后运行命令 `edquota -p protouser startuid-enduid`。例如，如果 用户 `test` 已经有了所需要的配额限制，下面的命令 可以被用来复制那些 UIDs 为10,000 到 19,999 的配额限制：

[source,shell]
....
# edquota -p test 10000-19999
....

更多细节请参考 man:edquota[8] 联机手册。

=== 检查配额限制和磁盘使用

既可以使用 man:quota[1] 也可以使用 man:repquota[8] 命令来检查 配额限制和磁盘使用情况。 man:quota[1] 命令能够检查单个用户和组的配置 使用情况。只有超级用户才可以检查其它用户的配额和磁盘使用情况。 man:repquota[8] 命令可以用来了解所有配额和磁盘的使用情况。

下面是一个使用 `quota -v` 命令后的输出情况：

[.programlisting]
....
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
....

前面以 [.filename]#/usr# 作为例子。 此用户目前已经比软限制 50 KB 超出了 15 KB， 还剩下 5 天的宽限期。 请注意， 星号 `*` 说明用户已经超出了其配额限制。

通常， 如果用户没有使用文件系统上的磁盘空间， 就不会在 man:quota[1] 命令的输出中显示， 即使已经为那个用户指定了配额。 而使用 `-v` 选项则会显示它们， 例如前面例子中的 [.filename]#/usr/var#。

=== 通过 NFS 使用磁盘配额

配额能够在 NFS 服务器上被配额子系统强迫使用。在 NFS 客户端， man:rpc.rquotad[8] 命令可以使用 quota 信息用于 man:quota[1] 命令， 可以允许用户查看它们的 quota 统计信息。

可以这样在 [.filename]#/etc/inetd.conf# 中启用 `rpc.rquotad`：

[.programlisting]
....
rquotad/1      dgram rpc/udp wait root /usr/libexec/rpc.rquotad rpc.rquotad
....

现在重启 `inetd`：

[source,shell]
....
# /etc/rc.d/inetd restart
....

[[disks-encrypting]]
== 加密磁盘分区

FreeBSD 提供了极好的数据保护措施，防止未受权的数据访问。 文件权限和强制访问控制(MAC)(看 crossref:mac[mac,强制访问控制]) 可以帮助预防在操作系统处于运行状态和计算机加电时未受权的第三方访问数据。 但是，和操作系统强制受权不相关的是，如果黑客有物理上访问计算机的可能， 那他就可以简单的把计算机的硬件安装到另一个系统上复制出敏感的数据。

无论攻击者如何取得停机后的硬件或硬盘驱动器本身， FreeBSD GEOM Based Disk Encryption (基于 GEOM 的磁盘加密， gbde) 和 `geli` 加密子系统都能够保护计算机上的文件系统数据， 使它们免受哪怕是训练有素的攻击者获得有用的资源。 与那些只能加密单个文件的笨重的加密方法不同， `gbde` 和 `geli` 能够透明地加密整个文件系统。 明文数据不会出现在硬盘的任何地方。

=== 使用 gbde 对磁盘进行加密

[.procedure]
====
. 成为 `root`
+ 
配置 gbde 需要超级用户的权力。
+
[source,shell]
....
% su -
Password:
....
+
. 在内核配置文件中添加对 man:gbde[4] 的支持
+ 
在您的内核配置中加入下面一行：
+ 
`options GEOM_BDE`
+ 
按照 crossref:kernelconfig[kernelconfig,配置FreeBSD的内核] 所进行的介绍重新编译并安装内核。
+ 
重新引导进入新的内核。
. 另一种无需重新编译内核的方法， 是使用 `kldload` 来加载 man:gbde[4]：
+
[source,shell]
....
# kldload geom_bde
....
====

==== 准备加密盘

下面这个例子假设您添加了一个新的硬盘在您的系统并将拥有一个单独的加密分区。 这个分区将挂接在 [.filename]##/private##目录下。 gbde 也可以用来加密 [.filename]##/home## 和 [.filename]##/var/mail##， 但是这需要更多的复杂命令来执行。

[.procedure]
====

. 添加新的硬盘
+ 
添加新的硬盘到系统中可以查看在 <<disks-adding>> 中的说明。 这个例子的目的是说明一个新的硬盘分区已经添加到系统中如： [.filename]#/dev/ad4s1c#。在例子中 [.filename]#/dev/ad0s1*# 设备代表系统中存在的标准 FreeBSD 分区。
+
[source,shell]
....
# 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
....
+
. 创建一个目录来保存 gbde Lock 文件
+
[source,shell]
....
# mkdir /etc/gbde
....
+ 
gbde lock 文件包含了 gbde 需要访问的加密分区的信息。 没有 lock 文件， gbde 将不能解密包含在加密分区上的数据。 每个加密分区使用一个独立的 lock 文件。
. 初始化 gbde 分区
+ 
一个 gbde 分区在使用前必须被初始化， 这个初始化过程只需要执行一次：
+
[source,shell]
....
# gbde init /dev/ad4s1c -i -L /etc/gbde/ad4s1c.lock
....
+ 
man:gbde[8] 将打开您的编辑器， 提示您去设置在一个模板文件中的配置变量。 使用 UFS1 或 UFS2，设置扇区大小为 2048：
+
[.programlisting]
....
$FreeBSD: src/sbin/gbde/template.txt,v 1.1 2002/10/20 11:16:13 phk 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
[...]
....
+ 
man:gbde[8] 将让您输入两次用来加密数据的密钥短语。 两次输入的密钥必须相同。 gbde 保护您数据的能力依靠您选择输入的密钥的质量。 
+ 
`gbde init` 命令为您的 gbde 分区创建了一个 lock 文件， 在这个例子中存储在 [.filename]##/etc/gbde/ad4s1c.lock##中。 gbde lock 文件必须使用 ".lock" 扩展名才能够被 [.filename]##/etc/rc.d/gbde## 启动脚本正确识别。
+
[CAUTION]
======

gbde lock 文件 _必须_ 和加密分区上的内容同时备份。 如果发生只有 lock 文件遭到删除的情况时， 就没有办法确定 gbde 分区上的数据是否是解密过的。 另外， 如果没有 lock 文件， 即使磁盘的合法主人， 不经过大量细致的工作也无法访问加密分区上的数据， 而这是在设计 man:gbde[8] 时完全没有考虑过的。
======
+
. 把加密分区和内核进行关联
+
[source,shell]
....
# gbde attach /dev/ad4s1c -l /etc/gbde/ad4s1c.lock
....
+ 
在加密分区的初始化过程中您将被要求提供一个密码短语。 新的加密设备将在 [.filename]#/dev# 中显示为 [.filename]#/dev/device_name.bde#：
+
[source,shell]
....
# 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
....
+
. 在加密设备上创建文件系统
+ 
当加密设备和内核进行关联后， 您就可以使用 man:newfs[8] 在此设备上创建文件系统， 使用 man:newfs[8] 来初始化一个 UFS2 文件系统比初始化一个 UFS1 文件系统还要快，摧荐使用 `-O2` 选项。
+
[source,shell]
....
# newfs -U -O2 /dev/ad4s1c.bde
....
+
[NOTE]
======
man:newfs[8] 命令必须在一个 gbde 分区上执行， 这个分区通过一个存在的 [.filename]#*.bde# 设备名进行标识。
======
+
. 挂接加密分区
+ 
为加密文件系统创建一个挂接点。
+
[source,shell]
....
# mkdir /private
....
+ 
挂接加密文件系统。
+
[source,shell]
....
# mount /dev/ad4s1c.bde /private
....
+
. 校验加密文件系统是否有效
+ 
加密的文件系统现在对于 man:df[1] 应该可见并可以使用。
+
[source,shell]
....
% 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
....
====

==== 挂接已有的加密文件系统

每次系统启动后， 在使用加密文件系统前必须和内核重新进行关联， 校验错误和再次挂接。使用的命令必须由 ``root``用户来执行。

[.procedure]
====

. 关联 gbde 分区到内核
+
[source,shell]
....
# gbde attach /dev/ad4s1c -l /etc/gbde/ad4s1c.lock
....
+ 
接下来系统将提示您输入在初始化加密的 gbde 分区时所用的密码短语。
. 校验文件系统错误
+ 
加密文件系统不能列在 [.filename]#/etc/fstab# 文件中进行自动加载， 在加载前必须手动运行 man:fsck[8] 命令对文件系统进行错误检测。
+
[source,shell]
....
# fsck -p -t ffs /dev/ad4s1c.bde
....
+
. 挂接加密文件系统
+
[source,shell]
....
# mount /dev/ad4s1c.bde /private
....
+ 
加密后的文件系统现在可以有效使用。
====

===== 自动挂接加密分区

可以创建脚本来自动地附加、 检测， 并挂接加密分区， 然而， 处于安全考虑， 这个脚本不应包含 man:gbde[8] 密码。 因而， 我们建议这类脚本在控制台或通过 man:ssh[1] 执行并要求用户输入口令。

除此之外， 系统还提供了一个 [.filename]#rc.d# 脚本。 这个脚本的参数可以通过 man:rc.conf[5] 来指定， 例如：

[.programlisting]
....
gbde_autoattach_all="YES"
gbde_devices="ad4s1c"
gbde_lockdir="/etc/gbde"
....

在启动时将要求输入 gbde 的口令。 在输入正确的口令之后， gbde 加密分区将被自动挂接。 对于将 gbde 用在笔记本电脑上时， 这就很有用了。

==== gbde 提供的密码学保护

man:gbde[8] 采用 CBC 模式的 128-位 AES 来加密扇区数据。 磁盘上的每个扇区都采用不同的 AES 密钥来加密。 要了解关于 gbde 的密码学设计， 包括扇区密钥如何从用户提供的口令字中生成等细节， 请参考 man:gbde[4]。

==== 兼容性问题

man:sysinstall[8] 是和 gbde 加密设备不兼容的。 在启动 man:sysinstall[8] 时必须将 [.filename]#*.bde# 设备和内核进行分离，否则在初始化探测设备时将引起冲突。 与加密设备进行分离在我们的例子中使用如下的命令：

[source,shell]
....
# gbde detach /dev/ad4s1c
....

还需要注意的是， 由于 man:vinum[4] 没有使用 man:geom[4] 子系统， 因此不能同时使用 gbde 与 vinum 卷。

=== 使用 `geli` 对磁盘进行加密

还有另一个可用于加密的 GEOM class - `geli`。 它目前由 {pjd} 开发。 `Geli` 工具与 `gbde` 不同； 它提供了一些不同的功能， 并采用了不同的方式来进行密码学运算。

man:geli[8] 最重要的功能包括：

* 使用了 man:crypto[9] 框架 - 如果系统中有加解密硬件加速设备， 则 `geli` 会自动加以利用。
* 支持多种加密算法 (目前支持 AES、 Blowfish， 以及 3DES)。
* 允许对根分区进行加密。 在系统启动时， 将要求输入用于加密根分区的口令。
* 允许使用两个不同的密钥 (例如， 一个 "个人密钥" 和一个 "公司密钥")。
* `geli` 速度很快 - 它只进行简单的扇区到扇区的加密。
* 允许备份和恢复主密钥。 当用户必须销毁其密钥时， 仍然可以通过从备份中恢复密钥来存取数据。
* 允许使用随机的一次性密钥来挂接磁盘 - 这对于交换区和临时文件系统非常有用。

更多 `geli` 功能介绍可以在 man:geli[8] 联机手册中找到。

下面的步骤介绍了如何启用 FreeBSD 内核中的 `geli` 支持， 并解释了如何创建新和使用 `geli` 加密 provider。

由于需要修改内核， 您需要拥有超级用户权限。

[.procedure]
====

. 在内核中加入 `geli` 支持
+ 
在内核配置文件中加入下面两行：
+
[.programlisting]
....
options GEOM_ELI
device crypto
....
+ 
按照 crossref:kernelconfig[kernelconfig,配置FreeBSD的内核] 介绍的步骤重新编译并安装内核。
+ 
另外， `geli` 也可以在系统引导时加载。 这是通过在 [.filename]#/boot/loader.conf# 中增加下面的配置来实现的：
+
[.programlisting]
....
geom_eli_load="YES"
....
+ 
man:geli[8] 现在应该已经为内核所支持了。
. 生成主密钥
+ 
下面的例子讲描述如何生成密钥文件， 它将作为主密钥 (Master Key) 的一部分， 用于挂接到 [.filename]#/private# 的加密 provider。 这个密钥文件将提供一些随机数据来加密主密钥。 同时， 主密钥也会使用一个口令字来保护。 Provider 的扇区尺寸为 4kB。 此外， 这里的讨论将介绍如何挂载 `geli` provider， 在其上创建文件系统， 如何挂接并在其上工作， 最后将其卸下。
+ 
建议您使用较大的扇区尺寸 (例如 4kB)， 以获得更好的性能。
+ 
主密钥将由口令字保护， 而密钥文件的数据来源则将是 [.filename]#/dev/random#。 我们称之为 provider 的 [.filename]#/dev/da2.eli# 的扇区尺寸将是 4kB。
+
[source,shell]
....
# dd if=/dev/random of=/root/da2.key bs=64 count=1
# geli init -s 4096 -K /root/da2.key /dev/da2
Enter new passphrase:
Reenter new passphrase:
....
+ 
同时使用口令字和密钥文件并不是必须的； 您也可以只使用其中的一种来加密主密钥。
+ 
如果密钥文件写作 "-"， 则表示使用标准输入。 下面是关于如何使用多个密钥文件的例子：
+
[source,shell]
....
# cat keyfile1 keyfile2 keyfile3 | geli init -K - /dev/da2
....
+
. 将 provider 与所生成的密钥关联
+
[source,shell]
....
# geli attach -k /root/da2.key /dev/da2
Enter passphrase:
....
+ 
新的明文设备将被命名为 [.filename]#/dev/da2.eli#。
+
[source,shell]
....
# ls /dev/da2*
/dev/da2  /dev/da2.eli
....
+
. 创建新的文件系统
+
[source,shell]
....
# dd if=/dev/random of=/dev/da2.eli bs=1m
# newfs /dev/da2.eli
# mount /dev/da2.eli /private
....
+ 
现在加密的文件系统应该已经可以被 man:df[1] 看到， 并处于可用状态了：
+
[source,shell]
....
# 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
....
+
. 卸下卷并断开 provider
+ 
一旦在加密分区上的工作完成， 并且不再需要 [.filename]#/private# 分区， 就应考虑将其卸下并将 `geli` 加密分区从内核上断开。
+
[source,shell]
....
# umount /private
# geli detach da2.eli
....
====

关于如何使用 man:geli[8] 的更多信息， 可以在其联机手册中找到。

==== 使用 [.filename]#geli# [.filename]#rc.d# 脚本

`geli` 提供了一个 [.filename]#rc.d# 脚本， 它可以用于简化 `geli` 的使用。 通过 man:rc.conf[5] 配置 `geli` 的方法如下：

[.programlisting]
....
geli_devices="da2"
geli_da2_flags="-p -k /root/da2.key"
....

这将把 [.filename]#/dev/da2# 配置为一个 `geli` provider， 其主密钥文件位于 [.filename]#/root/da2.key#， 而 `geli` 在连接 provider 时将不使用口令字 (注意只有在 `geli` init 阶段使用了 `-P` 才可以这样做)。 系统将在关闭之前将 `geli` provider 断开。

关于如何配置 [.filename]#rc.d# 的详细信息可以在使用手册的 crossref:config[configtuning-rcd,rc.d] 一节中找到。

[[swap-encrypting]]
== 对交换区进行加密

FreeBSD 提供了易于配置的交换区加密机制。 随所用的 FreeBSD 版本， 可用的配置选项会有所不同， 而配置方法也会有一些差异。 可以使用 man:gbde[8] 和 man:geli[8] 两种加密系统来进行交换区的加密操作。 前面所说的这两种加密系统， 都用到了 [.filename]#encswap# 这个 crossref:config[configtuning-rcd,rc.d] 脚本。

在前面的小节 <<disks-encrypting,如何加密磁盘分区>> 中， 已经就不同的加密系统之间的区别进行了简单的讨论。

=== 为什么需要对交换区进行加密？

与加密磁盘分区类似， 加密交换区有助于保护敏感信息。 为此， 我们不妨考虑一个需要处理敏感信息的程序， 例如， 它需要处理口令。 如果这些口令一直保持在物理内存中， 则一切相安无事。 然而， 如果操作系统开始将内存页换出到交换区， 以便为其他应用程序腾出内存时， 这些口令就可能以未加密的形式写到磁盘上， 并为攻击者所轻易获得。 加密交换区能够有效地解决这类问题。

=== 准备

[NOTE]
====
在本节余下的部分中， 我们约定使用 [.filename]#ad0s1b# 作为交换区。
====

到目前为止， 交换区仍是未加密的。 很可能其中已经存有明文形式的口令或其他敏感数据。 要纠正这一问题， 首先应使用随机数来覆盖交换分区的数据：

[source,shell]
....
# dd if=/dev/random of=/dev/ad0s1b bs=1m
....

=== 使用 man:gbde[8] 来加密交换区

[.filename]#/etc/fstab# 中与交换区对应的行中， 设备名应追加 `.bde` 后缀：

[.programlisting]
....

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

=== 使用 man:geli[8] 来加密分区

另一种方法是使用 man:geli[8] 来达到加密交换区的目的， 其过程与使用 man:gbde[8] 大体相似。 此时， 在 [.filename]#/etc/fstab# 中交换区对应的行中， 设备名应追加 `.eli` 后缀：

[.programlisting]
....

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

man:geli[8] 默认情况下使用密钥长度为 256-位的 AES 加密算法。

当然， 这些默认值是可以通过 [.filename]#/etc/rc.conf# 中的 `geli_swap_flags` 选项来修改的。 下面的配置表示让 rc.d 脚本 [.filename]#encswap# 创建一个 man:geli[8] 交换区， 在其上使用密钥长度为 128-位 的 Blowfish 加密算法， 4 kilobytes 的扇区尺寸， 并采用 "最后一次关闭时卸下" 的策略：

[.programlisting]
....
geli_swap_flags="-e blowfish -l 128 -s 4096 -d"
....

请参见 man:geli[8] 联机手册中关于 `onetime` 命令的说明， 以了解其他可用的选项。

=== 验证所作的配置能够发挥作用

在重启系统之后， 就可以使用 `swapinfo` 命令来验证加密交换区是否已经在正常运转了。

如果使用了 man:gbde[8]， 则：

[source,shell]
....
% swapinfo
Device          1K-blocks     Used    Avail Capacity
/dev/ad0s1b.bde    542720        0   542720     0%
....

如果使用了 man:geli[8]， 则：

[source,shell]
....
% swapinfo
Device          1K-blocks     Used    Avail Capacity
/dev/ad0s1b.eli    542720        0   542720     0%
....

[[disks-hast]]
== 高可用性存储 (HAST)

=== 概述

高可用性是担负关键业务的应用的一项主要需求， 而高可用存储则是这类环境中的一项关键组件。 高可用存储 Highly Available STorage， 或 HAST， 是由 {pjd} 开发的一种用于提供在两台物理上隔离的系统之间以透明的方式， 通过 TCP/IP 网络传输数据的高可用性框架。 HAST 可以看作通过网络进行的 RAID1 (镜像)， 类似于 GNU/Linux(R) 平台上的 DRBD(R) 存储系统。 配合 FreeBSD 提供的其他高可用性基础设施， 如 CARP， HAST 可以用来构建可以抗御硬件故障的高可用存储集群。

读完这节， 您将了解：

* 何为 HAST， 它如何工作以及提供哪些功能。
* 如何在 FreeBSD 上配置和使用 HAST。
* 如何与 CARP 及 man:devd[8] 配合构建可靠的存储系统。

在阅读这节之前， 您应：

* 了解 UNIX(R) 和 FreeBSD 的基础知识 (crossref:basics[basics,UNIX 基础])。
* 知道如何配置网络接口以及其他核心 FreeBSD 子系统 (crossref:config[config-tuning,设置和调整)])。
* 理解 FreeBSD 的网络功能 (crossref:partiv[network-communication,网络通讯])。
* 使用 FreeBSD 8.1-RELEASE 或更新版本。

HAST 项目是由 FreeBSD 基金会资助完成的， 并得到了来自 http://www.omc.net/[OMCnet Internet Service GmbH] 和 http://www.transip.nl/[TransIP BV] 的支持。

=== HAST 的功能

HAST 系统提供的功能主要包括：

* 可以掩盖本地硬盘的 I/O 错误。
* 文件系统无关， 因而可以配合 FreeBSD 支持的任何文件系统使用。
* 高效率的快速重新同步机制， 令系统只同步在另一节点停机时修改过的块。
* 可以在已经部署好的环境中添加冗余。
* 配合 CARP、 Heartbeat 或其他类似的工具， 可以实现健壮的可靠存储系统。

=== HAST 的运行机制

由于 HAST 本质上是在多个机器间同步地进行块级复制， 因此它需要至少两个节点 (物理的机器) - 其一作为 `主` (也称作 `master`) 节点， 另一个作为 `从` (`slave`) 节点。 这两台机器会共同构成一个集群。

[NOTE]
====
目前 HAST 只能使用最多两个集群节点。
====

由于 HAST 是配置成以主从节点的方式运行， 在任何时刻都只能有唯一的一个节点是主节点。 `主` 节点， 也称作 `活跃` 节点， 负责处理由 HAST 管理的设备的全部 I/O 请求。 而 `从` 节点则会自动从 `主` 节点同步数据的变更操作。

在 HAST 系统中的物理设备包括：

* 本地磁盘 (在主节点上)
* 远程磁盘 (在从节点上)

HAST 在块的级别上同步运行， 这使其对文件系统和应用程序透明。 HAST 在 [.filename]#/dev/hast/# 目录中提供标准的 GEOM 设备供其他工具或应用程序使用， 因此， 在使用上， 对应用程序或文件系统而言， HAST 提供的设备与普通的裸盘或分区等没有任何区别。

发到本地磁盘的每次写、 删除或缓存刷写操作， 都会同时通过 TCP/IP 发到远程磁盘上。 读操作是由本地磁盘完成， 除非本地磁盘上的数据不是最新的， 或发生了 I/O 错误。 在这种情况下， 读操作会在从节点上完成。

==== 同步及复制模式

HAST 希望提供快速的故障恢复能力。 基于这一考量， 减少在某个节点停机后需要的同步时间就十分重要。 为了提供快速的同步能力， HAST 会维护一份保存在磁盘上的脏区段位映射表 (bitmap of dirty extents)， 在普通的同步模式中， 它只同步这些部分的数据 (初始的同步除外)。

处理同步有多种不同的方式， HAST 计划实现以下几种同步方式：

* _memsync_： 当本地的写操作已经完成， 并且远程节点汇报已经收到数据时， 便认为数据的写操作已经完成， 而不是等待远程节点完成数据的写操作。 远程节点在发出回应之后， 会立即开始执行写操作。 这种模式的目标是减少响应时间， 但在同时仍然保持很好的可靠性。 目前 _memsync_ 复制模式尚未实现。
* _fullsync_： 只有在本地写操作完成， 并且远程的写操作也已经完成的情况下， 才认为数据的写操作已经完成。 这种模式是最保险， 同时也是最慢的一种复制模式。 这是目前系统预设的复制模式。
* _async_： 在本地写操作完成时， 即认为数据已经写完。 这是最快， 同时也是风险最大的复制模式， 一般而言只有在另一节点的延迟较大时才应考虑使用。 目前 _async_ 复制模式尚未实现。

[WARNING]
====

目前， 只支持 _fullsync_ 复制模式。
====

=== HAST 的配置

HAST 需要 `GEOM_GATE` 支持才能正常工作。 系统自带的预设 `GENERIC` 内核 _并不_ 包含 `GEOM_GATE`， 但默认的 FreeBSD 安装包含了 [.filename]#geom_gate.ko# 内核模块。 如果对系统进行了裁剪， 则应确认这个模块是否可用。 此外， `GEOM_GATE` 也可以静态联编进内核， 方法是在内核的编译配置中添加下面的设置：

[.programlisting]
....
options	GEOM_GATE
....

从操作系统的角度， HAST 框架包含了下面这些部件：

* 负责进行数据同步的 man:hastd[8] 服务程序，
* 用于执行管理操作的 man:hastctl[8] 用户态管理工具，
* 配置文件 man:hast.conf[5]。

下面的例子将介绍使用 HAST 在两个节点之间以 `主`-`从` 模式复制数据的方法。 两个节点的名字分别是 `hasta` 其 IP， 地址为 _172.16.0.1_， 以及 `hastb`， 其 IP 地址为 _172.16.0.2_。 这两台机器都使用尺寸相同的磁盘 [.filename]#/dev/ad6# 来专用于 HAST 的运行。 HAST 存储池 (有时也称为资源， 例如位于 [.filename]#/dev/hast/# 的设备文件) 将命名为 [.filename]#test#。

HAST 的配置文件是 [.filename]#/etc/hast.conf#。 在两个节点上， 这个文件的内容应该是完全一样的。 最简配置如下：

[.programlisting]
....
resource test {
	on hasta {
		local /dev/ad6
		remote 172.16.0.2
	}
	on hastb {
		local /dev/ad6
		remote 172.16.0.1
	}
}
....

如果需要更高级的配置， 请参阅联机手册 man:hast.conf[5]。

[TIP]
====

在 `remote` 语句中也可以使用主机名。 这种情况下需要确保这些主机名是可以解析的， 例如在 [.filename]#/etc/hosts# 文件中， 或在本地 DNS 中进行了定义。
====

现在在两个节点上都有同样的配置了， 接下来我们需要创建 HAST 存储池。 在两个节点上分别运行下面的命令来初始化本地此怕， 并启动 man:hastd[8] 服务：

[source,shell]
....
# hastctl create test
# /etc/rc.d/hastd onestart
....

[NOTE]
====
_没有_ 办法使用已经包含文件系统的 GEOM 设备来创建存储池 (换言之， 已经存在的文件系统无法转换为 HAST 管理的存储池)， 这是因为创建存储池的过程需要保存一些元数据， 而已经写入文件系统的设备不再能提供保存这些元数据所需的空间。
====

HAST 并不负责选择节点的角色 (`主` 或 `从`)。 节点的角色是由管理员手工， 或由类似 Heartbeat 这样的软件通过 man:hastctl[8] 来完成配置的。 在希望成为主节点的系统 (`hasta`) 上运行下面的命令令其成为主节点：

[source,shell]
....
# hastctl role primary test
....

类似地， 用下面的命令来指明从节点 (`hastb`)：

[source,shell]
....
# hastctl role secondary test
....

[CAUTION]
====

有可能会出现两个节点之间无法正常通讯， 但又都配置为主节点这样的情况； 这种称作 `脑分裂` 的状态是十分危险的。 在 <<disks-hast-sb>> 中介绍了如何从这种状态中恢复的方法。
====

接下来， 可以在两个节点上分别用 man:hastctl[8] 工具来验证节点身份是否正确：

[source,shell]
....
# hastctl status test
....

这其中比较重要的是 `status`(状态) 这行， 在两个节点上， 其输出均应为 `complete`(完好)。 如果系统给出的输出是 `degraded` (降级)， 则表示出现了问题。 正常情况下， 节点间的同步已经开始。 当 `hastctl status` 命令报告的 `dirty` 数据块数量为 0 字节时， 表示两个节点的数据已经完全同步。

最后一步是在 GEOM 设备 [.filename]#/dev/hast/test# 上创建文件系统。 这项工作必须在 `主` 节点上进行 (因为 [.filename]#/dev/hast/test# 只在 `主` 节点上出现)， 随硬盘尺寸的不同， 这可能需要花费数分钟的时间：

[source,shell]
....
# newfs -U /dev/hast/test
# mkdir /hast/test
# mount /dev/hast/test /hast/test
....

一旦完成了 HAST 框架的配置， 最后一步就是确保 HAST 在系统引导过程中会自动启动了。 为了达到这个目的， 应在 [.filename]#/etc/rc.conf# 文件中添加这行配置：

[.programlisting]
....
hastd_enable="YES"
....

==== 故障转移配置

这个例子的目的在于建立一套健壮的存储系统， 令其能够抵御在任何一个节点上发生的故障。 这其中的关键任务是对集群中的 `主` 节点发生故障的情形进行及时的补救处理。 当发生这种情况时， `从` 节点可以无缝地接手主节点的工作， 对文件系统进行检查并挂接， 从而继续运行， 而不损失任何数据。

为了达成这一任务， 需要使用 FreeBSD 提供的另一项功能 - CARP 所提供的 IP 层自动故障转移能力。 CARP 是共用地址冗余协议 Common Address Redundancy Protocol 的缩写， 它允许多个同网段的主机共享同一 IP 地址。 请根据 crossref:advanced-networking[carp,Common Address Redundancy Protocol (CARP， 共用地址冗余协议] 的介绍在两个节点上都配置 CARP。 完成这些配置之后， 两个节点都会有自己的 [.filename]#carp0# 网络接口， 共用 IP 地址 _172.16.0.254_。 显然， 集群中的 HAST 主节点也必须是 CARP 主节点。

前面一节中创建的 HAST 存储池现在可以提供给网络上的其他主机使用了。 其上的文件系统可以通过 NFS、 Samba 等等， 以共用 IP 地址 _172.16.0.254_ 来访问。 现在余下的唯一问题是自动化对主节点故障的处理。

当 CARP 网络接口的链路状态发生变化时， FreeBSD 操作系统会产生一个 man:devd[8] 消息， 这样就可以监视 CARP 网络接口的状态了。 CARP 接口的状态变化表示节点发生故障， 或重新回到了网络中。 这些情况下需要运行特定的脚本来完成对应的处理。

为了截获 CARP 网络接口的状态变化， 需要在两个节点的 [.filename]#/etc/devd.conf# 文件中添加如下的设置：

[.programlisting]
....
notify 30 {
	match "system" "IFNET";
	match "subsystem" "carp0";
	match "type" "LINK_UP";
	action "/usr/local/sbin/carp-hast-switch master";
};

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

为使编辑的配置生效， 需要在两个节点上执行下面的命令：

[source,shell]
....
# /etc/rc.d/devd restart
....

当网络接口 [.filename]#carp0# 的状态发生变化时， 系统会产生一个通知消息， 这允许 man:devd[8] 子系统运行管理员指定的任意脚本， 在这个例子中是 [.filename]#/usr/local/sbin/carp-hast-switch#。 这个脚本的作用是自动化故障转移。 关于前面 man:devd[8] 配置的具体含义， 请参阅联机手册 man:devd.conf[5]。

下面是一个这种脚本的示例：

[.programlisting]
....
#!/bin/sh

# Original script by Freddie Cash <fjwcash@gmail.com>
# Modified by Michael W. Lucas <mwlucas@BlackHelicopters.org>
# and Viktor Petersson <vpetersson@wireload.net>

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

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

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

# end of user configurable stuff

case "$1" in
	master)
		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

	;;

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

简而言之， 在节点成为网络的 `master` / `primary` 节点时， 脚本会进行下面的操作：

* 在本节点升格为 HAST 存储池的主节点。
* 检查 HAST 存储池上的文件系统。
* 挂接存储池中的文件系统到适当的位置。

当节点成为 `backup` / `secondary` 节点时：

* 卸下 HAST 存储池。
* 将本节点降格为 HAST 存储池的从节点。

[CAUTION]
====

务必注意， 上面的脚本只是概念性的介绍。 它并不能处理所有可能发生的情况， 因此应根据实际情况进行修改， 例如启动/停止必要的服务， 等等。
====

[TIP]
====

在前面的例子中， 出于示范的目的我们使用的是标准的 UFS 文件系统。 为了减少恢复所需的时间， 可以使用带日志的 UFS 文件系统， 或者使用 ZFS 文件系统。
====

更具体的信息和例子请参阅 http://wiki.FreeBSD.org/HAST[HAST Wiki] 页面。

=== 故障排除

==== 一般故障排除提示

HAST 通常都能够无故障地运行， 不过， 和任何其他软件产品一样， 有时它也可能会无法以希望的方式运转。 导致问题的可能性有很多， 但一般来说， 首先要确保集群中所有节点的时间是同步的。

当尝试排除 HAST 故障时， 应提高 man:hastd[8] 的调试级别。 这可以通过在启动 man:hastd[8] 服务时指定 `-d` 参数来实现。 需要说明的是， 可以多次指定这一参数来进一步提高调试级别。 此外， 还可以考虑使用 `-F` 参数来启动服务， 它会令 man:hastd[8] 服务在前台运行。

[[disks-hast-sb]]
==== 从脑分裂状态恢复

当集群中的两个节点之间无法相互通讯时， 两个节点都会认为自己是主节点， 从而导致 `脑分裂` 的状态。 这种情形十分危险， 因为两个节点会产生互相无法合并的数据。 这种情形需要系统管理员实施手工干预。

从这种状态中恢复时， 管理员必须决定哪一个节点包含最重要的数据变动 (或者手工合并这些改动) 并让 HAST 进行一次完整的同步操作， 覆盖有问题的那个节点的数据。 要完成这个工作，在有问题的节点上执行下面的命令：

[source,shell]
....
# hastctl role init <resource>
# hastctl create <resource>
# hastctl role secondary <resource>
....
