在桌面 PC 上实现 UFS 日志记录

商标

FreeBSD 是 FreeBSD 基金会的注册商标。

制造商和销售商用来区分其产品的许多名称都被声称为商标。在本文件中,这些名称出现时,如果 FreeBSD 项目知道该商标声明,则在这些名称后面会加上“™”或“®”符号。

摘要

日志文件系统使用日志记录文件系统中发生的全部事务,并在系统崩溃或断电时保持其完整性。虽然仍然有可能丢失未保存的文件更改,但日志记录几乎完全消除了因系统意外关闭导致的文件系统损坏的可能性。它还将故障后文件系统检查所需的时间缩短至最短。虽然 FreeBSD 使用的 UFS 文件系统本身没有实现日志记录,但 FreeBSD 7. *X* 中的 GEOM 框架的新日志类可用于提供独立于文件系统的日志记录。本文解释了如何在典型的桌面 PC 场景中实现 UFS 日志记录。


1. 简介

虽然专业服务器通常受到良好保护,不会出现意外关闭,但典型的桌面电脑容易受到断电、意外重置和其他与用户相关事件的影响,这些事件会导致系统意外关闭。软更新通常在这些情况下有效地保护文件系统,尽管大多数情况下需要进行长时间的后台检查。在极少数情况下,文件系统损坏达到需要用户干预的程度,可能会导致数据丢失。

GEOM 提供的新日志记录功能可以极大地帮助解决这些情况,几乎可以消除文件系统检查所需的时间,并确保文件系统快速恢复到一致状态。

本文描述了在典型的桌面 PC 场景中(一个硬盘用于操作系统和数据)实现 UFS 日志记录的过程。它应该在全新安装 FreeBSD 时遵循。这些步骤非常简单,不需要过度复杂的命令行交互。

阅读完本文后,您将了解

  • 如何在全新安装 FreeBSD 时预留日志记录空间。

  • 如何加载和启用 geom_journal 模块(或在自定义内核中构建对它的支持)。

  • 如何将现有文件系统转换为使用日志记录,以及在 /etc/fstab 中使用哪些选项来挂载它们。

  • 如何在新的(空的)分区中实现日志记录。

  • 如何对与日志记录相关的常见问题进行故障排除。

在阅读本文之前,您应该能够

  • 了解基本的 UNIX® 和 FreeBSD 概念。

  • 熟悉 FreeBSD 的安装过程和 sysinstall 实用程序。

此处描述的过程旨在用于准备新安装,其中磁盘上还没有实际的用户数据。虽然可以修改和扩展此过程以适用于已经投入生产的系统,但在这样做之前,您应该备份所有重要数据。在低级别操作磁盘和分区可能会导致致命错误和数据丢失。

2. 了解 FreeBSD 中的日志记录

FreeBSD 7. *X* 中 GEOM 提供的日志记录不是特定于文件系统的(例如与 Linux® 中的 ext3 文件系统不同),而是工作在块级别。虽然这意味着它可以应用于不同的文件系统,但对于 FreeBSD 7.0-RELEASE,它只能用于 UFS2。

此功能通过将 geom_journal.ko 模块加载到内核中(或将其构建到自定义内核中)并使用 gjournal 命令来配置文件系统来提供。通常,您希望对大型文件系统(如 /usr)进行日志记录。但是,您需要(请参阅下一节)预留一些可用磁盘空间。

当对文件系统进行日志记录时,需要一些磁盘空间来保存日志本身。保存实际数据的磁盘空间称为数据提供程序,而保存日志的磁盘空间称为日志提供程序。对现有(非空)分区进行日志记录时,数据和日志提供程序需要位于不同的分区上。对新分区进行日志记录时,可以选择使用单个提供程序作为数据和日志提供程序。无论哪种情况,gjournal 命令都会组合这两个提供程序来创建最终的日志记录文件系统。例如

  • 您希望对存储在 /dev/ad0s1f 中的 /usr 文件系统进行日志记录(其中已经包含数据)。

  • 您在 /dev/ad0s1g 中的分区中预留了一些可用磁盘空间。

  • 使用 gjournal,将创建一个新的 /dev/ad0s1f.journal 设备,其中 /dev/ad0s1f 是数据提供程序,而 /dev/ad0s1g 是日志提供程序。此新设备将用于所有后续文件操作。

为日志提供程序预留的磁盘空间量取决于文件系统的使用负载,而不是数据提供程序的大小。例如,在典型的办公桌面电脑上,/usr 文件系统的 1 GB 日志提供程序就足够了,而处理大量磁盘 I/O(例如视频编辑)的机器可能需要更多空间。如果日志空间在有机会提交之前就耗尽了,则会发生内核恐慌。

此处建议的日志大小在典型的桌面使用(例如网页浏览、文字处理和媒体文件播放)中极不可能造成问题。如果您的工作负载包括密集的磁盘活动,请使用以下规则以确保最大可靠性:您的 RAM 大小应适合日志提供程序空间的 30%。例如,如果您的系统拥有 1 GB RAM,请创建一个大约 3.3 GB 的日志提供程序。(将您的 RAM 大小乘以 3.3 以获取日志大小)。

有关日志记录的更多信息,请阅读 gjournal(8) 的手册页。

3. FreeBSD 安装过程中的步骤

3.1. 预留日志记录空间

典型的桌面机器通常只有一块硬盘,用于存储操作系统和用户数据。可以说,sysinstall 选择的默认分区方案或多或少适合:桌面机器不需要很大的 /var 分区,而 /usr 被分配了大部分磁盘空间,因为用户数据和许多软件包都安装在其子目录中。

默认分区(通过在 FreeBSD 分区编辑器(称为 Disklabel)中按 A 获得的分区)没有留下任何未分配的空间。每个要进行日志记录的分区都需要另一个分区作为日志。由于 /usr 分区是最大的,因此缩小这个分区一点以获得日志记录所需的磁盘空间是合理的。

在我们的示例中,使用了 80 GB 的磁盘。以下屏幕截图显示了 Disklabel 在安装期间创建的默认分区

disklabel1

如果这或多或少是您需要的,那么调整以进行日志记录非常容易。只需使用箭头键将高亮移动到 /usr 分区,然后按 D 删除它。

现在,将高亮移动到屏幕顶部的磁盘名称,然后按 C 创建一个新的 /usr 分区。这个新分区应该小 1 GB(如果您只打算对 /usr 进行日志记录),或小 2 GB(如果您打算对 /usr/var 进行日志记录)。从弹出的窗口中,选择创建文件系统,然后键入 /usr 作为挂载点。

是否应该对 /var 分区进行日志记录?通常情况下,对相当大的分区进行日志记录是有意义的。您可以选择不对 /var 进行日志记录,尽管在典型的桌面电脑上这样做不会造成任何伤害。如果文件系统使用量很小(对于桌面电脑来说很可能),您可能希望为其日志分配更少的磁盘空间。

在我们的示例中,我们对 /usr/var 都进行了日志记录。当然,您可以根据自己的需要调整此过程。

为了使事情尽可能简单,我们将使用 sysinstall 来创建日志记录所需的分区。但是,在安装过程中,sysinstall 坚持要求您为创建的每个分区指定一个挂载点。此时,您还没有为将要保存日志的分区指定任何挂载点,实际上您根本不需要它们。这些不是我们要挂载到某个地方的分区。

为了避免 sysinstall 的这些问题,我们将创建日志分区作为交换空间。交换空间永远不会被挂载,sysinstall 不会有任何问题创建所需的交换空间分区。在第一次重启后,需要编辑 /etc/fstab 并删除额外的交换空间条目。

要创建交换分区,再次使用箭头键将高亮移动到 Disklabel 屏幕顶部,使磁盘名称本身被高亮显示。然后按下 N,输入所需大小(1024M),并在出现的弹出菜单中选择“交换空间”。对于要创建的每个日志,重复此操作。在我们的示例中,我们创建了两个分区,用于提供 /usr/var 的日志。最终结果如下面的屏幕截图所示

disklabel2

完成分区创建后,建议您记下分区名称和挂载点,以便在配置阶段轻松参考这些信息。这将有助于避免可能损坏安装的错误。下表显示了我们的示例配置注释

表 1. 分区和日志
分区挂载点日志

ad0s1d

/var

ad0s1h

ad0s1f

/usr

ad0s1g

继续安装,就像平常一样。但是,我们建议您在完全设置日志记录之前,推迟安装第三方软件(包)。

3.2. 第一次启动

您的系统将正常启动,但您需要编辑 /etc/fstab 并删除为日志创建的额外交换分区。通常,您实际使用的交换分区是带有“b”后缀的那个(例如,在我们示例中为 ad0s1b)。删除所有其他交换空间条目并重新启动,以便 FreeBSD 停止使用它们。

当系统再次启动时,我们将准备好配置日志记录。

4. 设置日志记录

4.1. 执行 gjournal

准备好所有必需的分区后,配置日志记录非常容易。我们需要切换到单用户模式,因此以 root 身份登录并输入

# shutdown now

按下 Enter 以获取默认 Shell。我们需要卸载将被记录的分区,在我们的示例中为 /usr/var

# umount /usr /var

加载日志记录所需的模块

# gjournal load

现在,使用您的笔记确定哪个分区将用于每个日志。在我们的示例中,/usrad0s1f,其日志为 ad0s1g,而 /varad0s1d,并将记录到 ad0s1h。需要以下命令

# gjournal label ad0s1f ad0s1g
GEOM_JOURNAL: Journal 2948326772: ad0s1f contains data.
GEOM_JOURNAL: Journal 2948326772: ad0s1g contains journal.

# gjournal label ad0s1d ad0s1h
GEOM_JOURNAL: Journal 3193218002: ad0s1d contains data.
GEOM_JOURNAL: Journal 3193218002: ad0s1h contains journal.

如果任一分区的最后一个扇区被使用,gjournal 将返回错误。您必须使用 -f 标志运行该命令以强制覆盖,即

# gjournal label -f ad0s1d ad0s1h

由于这是一个新安装,因此实际覆盖任何内容的可能性很小。

此时,将创建两个新设备,即 ad0s1d.journalad0s1f.journal。它们代表我们要挂载的 /var/usr 分区。但是,在挂载之前,我们必须为它们设置日志标志并清除 Soft Updates 标志

# tunefs -J enable -n disable ad0s1d.journal
tunefs: gjournal set
tunefs: soft updates cleared

# tunefs -J enable -n disable ad0s1f.journal
tunefs: gjournal set
tunefs: soft updates cleared

现在,将新设备手动挂载到它们各自的位置(请注意,我们现在可以使用 async 挂载选项)

# mount -o async /dev/ad0s1d.journal /var
# mount -o async /dev/ad0s1f.journal /usr

编辑 /etc/fstab 并更新 /usr/var 的条目

/dev/ad0s1f.journal     /usr            ufs     rw,async      2       2
/dev/ad0s1d.journal     /var            ufs     rw,async      2       2

确保上述条目正确,否则在重新启动后,您将无法正常启动!

最后,编辑 /boot/loader.conf 并添加以下行,以便在每次启动时加载 gjournal(8) 模块

geom_journal_load="YES"

恭喜!您的系统现在已设置为日志记录。您可以键入 exit 返回多用户模式,或重新启动以测试您的配置(建议)。在启动过程中,您将看到类似以下的消息

ad0: 76293MB XEC XE800JD-00HBC0 08.02D08 at ata0-master SATA150
GEOM_JOURNAL: Journal 2948326772: ad0s1g contains journal.
GEOM_JOURNAL: Journal 3193218002: ad0s1h contains journal.
GEOM_JOURNAL: Journal 3193218002: ad0s1d contains data.
GEOM_JOURNAL: Journal ad0s1d clean.
GEOM_JOURNAL: Journal 2948326772: ad0s1f contains data.
GEOM_JOURNAL: Journal ad0s1f clean.

在不干净的关机后,消息将略有不同,即

GEOM_JOURNAL: Journal ad0s1d consistent.

这通常意味着 gjournal(8) 使用了日志提供程序中的信息来将文件系统恢复到一致状态。

4.2. 为新创建的分区设置日志记录

虽然上述过程对于已经包含数据的日志记录分区是必需的,但日志记录空分区要简单一些,因为数据和日志提供程序都可以存储在同一个分区中。例如,假设安装了新的磁盘,并且创建了一个新的分区 /dev/ad1s1d。创建日志将像下面一样简单

# gjournal label ad1s1d

日志大小默认情况下将为 1 GB。您可以使用 -s 选项调整它。该值可以以字节表示,也可以附加 KMG 来分别表示千字节、兆字节或吉字节。请注意,gjournal 不允许您创建过小的日志大小。

例如,要创建 2 GB 的日志,您可以使用以下命令

# gjournal label -s 2G ad1s1d

然后,您可以在新分区上创建文件系统,并使用 -J 选项启用日志记录

# newfs -J /dev/ad1s1d.journal

4.3. 将日志记录构建到您的自定义内核中

如果您不想将 geom_journal 作为模块加载,则可以将它的功能直接构建到您的内核中。编辑您的自定义内核配置文件,并确保它包含这两行

options UFS_GJOURNAL # Note: This is already in GENERIC

options GEOM_JOURNAL # You will have to add this one

按照 FreeBSD 手册中的相关说明 重新构建和重新安装您的内核。

如果您之前使用过它,请不要忘记从 /boot/loader.conf 中删除相关的“load”条目。

5. 日志记录故障排除

以下部分介绍了与日志记录相关问题的常见问题解答。

日志可能在有机会提交(刷新)到磁盘之前就已填满。请记住,日志的大小取决于使用负载,而不是数据提供程序的大小。如果您的磁盘活动量很大,则需要更大的分区来存放日志。请参阅 了解 FreeBSD 中的日志记录 部分中的说明。

5.2. 在配置过程中,我犯了一些错误,现在无法正常启动。这可以通过某种方式修复吗?

您可能忘记了(或拼写错误) /boot/loader.conf 中的条目,或者您的 /etc/fstab 文件中存在错误。这些通常很容易修复。按下 Enter 进入默认单用户 shell。然后找到问题的根源

# cat /boot/loader.conf

如果 geom_journal_load 条目丢失或拼写错误,则不会创建记录的设备。手动加载该模块,挂载所有分区,并继续进行多用户启动

# gjournal load

GEOM_JOURNAL: Journal 2948326772: ad0s1g contains journal.
GEOM_JOURNAL: Journal 3193218002: ad0s1h contains journal.
GEOM_JOURNAL: Journal 3193218002: ad0s1d contains data.
GEOM_JOURNAL: Journal ad0s1d clean.
GEOM_JOURNAL: Journal 2948326772: ad0s1f contains data.
GEOM_JOURNAL: Journal ad0s1f clean.

# mount -a
# exit
(boot continues)

另一方面,如果该条目正确,请查看 /etc/fstab。您可能会发现拼写错误或缺少条目。在这种情况下,手动挂载所有剩余的分区,并继续进行多用户启动。

5.3. 我可以删除日志记录并恢复到使用 Soft Updates 的标准文件系统吗?

当然可以。使用以下过程,它将反转更改。如果您愿意,您可以将为日志提供程序创建的分区用于其他目的。

root 身份登录并切换到单用户模式

# shutdown now

卸载已记录的分区

# umount /usr /var

同步日志

# gjournal sync

停止日志提供程序

# gjournal stop ad0s1d.journal
# gjournal stop ad0s1f.journal

从所有使用的设备中清除日志记录元数据

# gjournal clear ad0s1d
# gjournal clear ad0s1f
# gjournal clear ad0s1g
# gjournal clear ad0s1h

清除文件系统日志记录标志,并恢复 Soft Updates 标志

# tunefs -J disable -n enable ad0s1d
tunefs: gjournal cleared
tunefs: soft updates set

# tunefs -J disable -n enable ad0s1f
tunefs: gjournal cleared
tunefs: soft updates set

手动重新挂载旧设备

# mount -o rw /dev/ad0s1d /var
# mount -o rw /dev/ad0s1f /usr

编辑 /etc/fstab 并将其恢复到原始状态

/dev/ad0s1f     /usr            ufs     rw      2       2
/dev/ad0s1d     /var            ufs     rw      2       2

最后,编辑 /boot/loader.conf,删除加载 geom_journal 模块的条目,然后重新启动。

6. 进一步阅读

日志记录是 FreeBSD 的一项相当新的功能,因此目前文档还不够完善。但是,您可能会发现以下其他参考资料很有用


最后修改于:2024 年 9 月 20 日,由 Fernando Apesteguía 修改