FreeBSD 和固态设备

商标

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

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

摘要

本文介绍了在 FreeBSD 中使用固态磁盘设备创建嵌入式系统。

嵌入式系统由于缺乏整体移动部件(硬盘驱动器),因此具有更高的稳定性。然而,必须考虑系统中通常可用的磁盘空间有限以及存储介质的耐用性。

本文将涵盖以下特定主题:适合在 FreeBSD 中用作磁盘的固态介质的类型和属性;在这样的环境中感兴趣的内核选项;rc.initdiskless 机制,该机制自动初始化此类系统并需要只读文件系统;以及从头开始构建文件系统。本文将以一些针对小型和只读 FreeBSD 环境的一般策略作为结尾。


1. 固态磁盘设备

本文的范围将限于由闪存制成的固态磁盘设备。闪存是一种固态存储器(没有移动部件),它是不可挥发的(即使在所有电源断开后,存储器仍能保持数据)。闪存能够承受极大的物理冲击,并且速度相当快(本文中介绍的闪存解决方案在写入操作方面比 EIDE 硬盘略慢,而在读取操作方面快得多)。闪存的一个非常重要的方面是每个扇区都有有限的重写容量,这将在本文后面讨论。您只能对闪存扇区进行一定次数的写入、擦除和重新写入操作,然后该扇区将永久不可用。虽然许多闪存产品会自动映射坏块,并且有些甚至会将写入操作均匀地分布在整个单元中,但事实仍然是,对设备进行写入操作的次数是有限的。竞争性单元的规格中每个扇区的写入次数在 1,000,000 到 10,000,000 之间。该数字会因环境温度而异。

具体来说,我们将讨论 ATA 兼容的紧凑型闪存单元,这些单元作为数码相机的存储介质非常流行。特别重要的是,它们直接引出到 IDE 总线,并与 ATA 命令集兼容。因此,借助非常简单且低成本的适配器,这些设备可以直接连接到计算机中的 IDE 总线。以这种方式实现后,FreeBSD 等操作系统会将该设备视为一个普通的硬盘驱动器(尽管体积较小)。

也存在其他固态磁盘解决方案,但由于它们的成本高昂、默默无闻以及使用起来相对不方便,因此超出了本文的范围。

2. 内核选项

对于创建嵌入式 FreeBSD 系统的人员来说,一些内核选项特别有用。

所有使用闪存作为系统磁盘的嵌入式 FreeBSD 系统都会对内存磁盘和内存文件系统感兴趣。由于对闪存进行写入操作的次数有限,因此磁盘和磁盘上的文件系统很可能将以只读方式挂载。在这种环境中,/tmp/var 等文件系统以内存文件系统的方式挂载,以便系统能够创建日志,更新计数器以及创建临时文件。内存文件系统是成功实现固态 FreeBSD 的关键组成部分。

您应确保在内核配置文件中存在以下行

options         MD_ROOT         # md device usable as a potential root device

3. rc 子系统和只读文件系统

嵌入式 FreeBSD 系统的启动后初始化由 /etc/rc.initdiskless 控制。

/etc/rc.d/var/var 挂载为内存文件系统,使用 mkdir(1) 命令在 /var 中创建一个可配置的目录列表,并更改其中一些目录的模式。在执行 /etc/rc.d/var 时,另一个 rc.conf 变量会起作用,即 varsize/etc/rc.d/var 会根据 rc.conf 中该变量的值来创建 /var 分区

varsize=8192

请记住,默认情况下,此值以扇区为单位。

事实上,/var 是一个读写文件系统,这是一个重要的区别,因为 / 分区(以及您可能在闪存介质上创建的任何其他分区)应该以只读方式挂载。请记住,在 固态磁盘设备 中,我们详细介绍了闪存的局限性,特别是写入能力有限。不以读写方式挂载闪存介质上的文件系统以及不使用交换文件的的重要性怎么强调都不过分。在繁忙的系统中,交换文件可以在不到一年的时间内耗尽一块闪存介质。频繁的日志记录或临时文件的创建和销毁也会产生同样的效果。因此,除了从 /etc/fstab 中删除 swap 条目之外,您还应将每个文件系统的 Options 字段更改为 ro,如下所示

# Device                Mountpoint      FStype  Options         Dump    Pass#
/dev/ad0s1a             /               ufs     ro              1       1

由于此更改,普通系统中的一些应用程序将立即开始出现故障。例如,由于 /etc/rc.d/var 创建的 /var 中缺少 cron 任务,cron 将无法正常运行,而 syslog 和 dhcp 也会遇到问题,因为只读文件系统和 /var 中缺少 /etc/rc.d/var 创建的项目。然而,这些只是暂时的问题,它们将在 小型和只读环境的系统策略 中得到解决,其中还包括解决其他常用软件包执行问题的方案。

请记住,使用 /etc/fstab 以只读方式挂载的文件系统可以在任何时候通过执行以下命令变为读写方式

# /sbin/mount -uw partition

并且可以使用以下命令切换回只读方式

# /sbin/mount -ur partition

4. 从头开始构建文件系统

由于 ATA 兼容的紧凑型闪存卡被 FreeBSD 看作是普通的 IDE 硬盘驱动器,因此从理论上讲,您可以使用 kern 和 mfsroot 软盘或 CD 从网络安装 FreeBSD。

然而,即使使用正常的安装过程进行的 FreeBSD 小规模安装也会产生一个超过 200 兆字节的系统。大多数人都会使用更小的闪存设备(128 兆字节被认为相当大,32 兆字节甚至 16 兆字节很常见),因此无法使用正常的机制进行安装,因为即使是最小的传统安装也需要足够的磁盘空间。

克服此空间限制的最简单方法是使用传统方式将 FreeBSD 安装到普通硬盘驱动器。安装完成后,将操作系统精简到可以容纳在闪存介质上的大小,然后将整个文件系统压缩成 tar 格式。以下步骤将指导您完成为压缩后的文件系统准备一块闪存介质的过程。请记住,由于没有执行正常的安装操作,因此需要手动执行分区、标记、文件系统创建等操作。除了 kern 和 mfsroot 软盘之外,您还需要使用 fixit 软盘。

  1. 对闪存介质设备进行分区

    使用 kern 和 mfsroot 软盘启动后,从安装菜单中选择 custom。在自定义安装菜单中,选择 partition。在分区菜单中,您应使用 d 删除所有现有的分区。删除所有现有的分区后,使用 c 创建一个分区,并接受分区的默认大小值。当询问分区类型时,请确保该值设置为 165。现在,通过按 w 将此分区表写入磁盘(这是此屏幕上的隐藏选项)。如果您使用的是 ATA 兼容的紧凑型闪存卡,则应选择 FreeBSD 启动管理器。现在,按 q 退出分区菜单。您将再次看到启动管理器菜单,重复您之前做出的选择。

  2. 在闪存介质设备上创建文件系统

    退出自定义安装菜单,从主安装菜单中选择 fixit 选项。进入 fixit 环境后,输入以下命令

    # disklabel -e /dev/ad0c

    此时,您将以 disklabel 命令的方式进入 vi 编辑器。接下来,您需要在文件末尾添加一个 a: 行。此 a: 行应类似于

    a:      123456  0       4.2BSD  0       0

    其中 123456 是与现有 c: 条目中大小值完全相同的数字。基本上,您要复制现有的 c: 行作为 a: 行,并确保 fstype 为 4.2BSD。保存文件并退出。

    # disklabel -B -r /dev/ad0c
    # newfs /dev/ad0a
  3. 将文件系统放置到闪存介质上

    挂载新准备好的闪存介质

    # mount /dev/ad0a /flash

    使此机器连接到网络,以便我们可以传输 tar 文件并将其解压缩到闪存介质文件系统中。以下是执行此操作的一种示例

    # ifconfig xl0 192.168.0.10 netmask 255.255.255.0
    # route add default 192.168.0.1

    现在机器已经连接到网络,请传输你的 tar 文件。这时你可能会遇到一个问题 - 如果你的闪存容量是 128 兆字节,而你的 tar 文件大于 64 兆字节,那么你无法同时将 tar 文件存储在闪存介质上并进行解压缩,因为会超出空间限制。如果使用 FTP,解决这个问题的一种方法是在通过 FTP 传输文件的同时进行解压缩。以这种方式进行传输,tar 文件和解压缩后的内容将不会同时存在于磁盘上。

    ftp> get tarfile.tar "| tar xvf -"

    如果你的 tar 文件是 gzip 压缩的,也可以采用这种方式。

    ftp> get tarfile.tar "| zcat | tar xvf -"

    将 tar 文件系统的内容复制到闪存文件系统后,你可以卸载闪存并重启系统。

    # cd /
    # umount /flash
    # exit

    假设你在正常硬盘上构建文件系统时配置正确(文件系统以只读方式挂载,并且将必要的选项编译到内核中),你应该可以成功启动你的 FreeBSD 嵌入式系统。

5. 小型只读环境的系统策略

rc 子系统和只读文件系统 中,提到了 /var 文件系统(由 /etc/rc.d/var 构建)以及只读根文件系统会对 FreeBSD 中许多常用的软件包造成问题。本文将提供一些在这些环境下成功运行 cron、syslog、ports 安装以及 Apache web 服务器的建议。

5.1. Cron

启动时,/var 会根据 /etc/mtree/BSD.var.dist 中的列表,由 /etc/rc.d/var 填充,因此 croncron/tabsat 以及其他一些标准目录会被创建。

然而,这并没有解决在重启之间维护 cron 任务的问题。当系统重启时,内存中的 /var 文件系统将消失,你可能在其中创建的任何 cron 任务也会消失。因此,一种解决方案是为需要使用 cron 任务的用户创建 cron 任务,将 / 文件系统挂载为可读写,并将这些 cron 任务复制到安全的位置,例如 /etc/tabs,然后在 /etc/rc.initdiskless 的末尾添加一行,在系统初始化期间创建 /var/cron/tabs 目录后将这些 cron 任务复制到该目录。你可能还需要添加一行来使用 /etc/rc.initdiskless 更改你创建的目录和复制的文件的模式和权限。

5.2. Syslog

syslog.conf 指定了 /var/log 中特定日志文件的位置。这些文件不是在系统初始化时由 /etc/rc.d/var 创建的。因此,你需要在 /etc/rc.d/var 中添加一些类似下面的代码,位于创建 /var 中目录的部分之后。

# touch /var/log/security /var/log/maillog /var/log/cron /var/log/messages
# chmod 0644 /var/log/*

5.3. Ports 安装

在讨论成功使用 ports 树所需的更改之前,需要提醒一下你关于闪存介质上文件系统只读性的注意事项。由于它们是只读的,你需要使用 rc 子系统和只读文件系统 中显示的挂载语法,将它们临时挂载为可读写。在完成任何维护操作后,你应该始终将这些文件系统重新挂载为只读,因为对闪存介质进行不必要的写入可能会大大缩短其使用寿命。

为了能够进入 ports 目录并成功运行 make install,我们必须在一个非内存文件系统上创建一个 packages 目录,以便在重启之间跟踪我们的软件包。由于安装软件包时需要将文件系统挂载为可读写,因此可以合理地假设闪存介质上的某个区域也可以用于写入软件包信息。

首先,创建一个软件包数据库目录。通常它位于 /var/db/pkg,但我们不能将其放在那里,因为它会在每次系统启动时消失。

# mkdir /etc/pkg

现在,在 /etc/rc.d/var 中添加一行,将 /etc/pkg 目录链接到 /var/db/pkg。例如:

# ln -s /etc/pkg /var/db/pkg

现在,只要将文件系统挂载为可读写并安装软件包,make install 就可以正常工作,软件包信息将成功写入 /etc/pkg(因为此时文件系统将被挂载为可读写),并且操作系统始终可以访问 /var/db/pkg

5.4. Apache Web 服务器

本节中的步骤仅在 Apache 设置为将 pid 或日志信息写入 /var 之外的位置时才需要。默认情况下,Apache 将其 pid 文件存储在 /var/run/httpd.pid 中,并将日志文件存储在 /var/log 中。

现在假设 Apache 将其日志文件存储在 /var 之外的 apache_log_dir 目录中。当该目录位于只读文件系统上时,Apache 将无法保存任何日志文件,并且可能无法正常工作。如果是这样,你需要在 /etc/rc.d/var 中添加一个新的目录列表,以便在 /var 中创建它,并将 apache_log_dir 链接到 /var/log/apache。你还需要设置此新目录的权限和所有权。

首先,将目录 log/apache 添加到要在 /etc/rc.d/var 中创建的目录列表中。

其次,在目录创建部分之后,在 /etc/rc.d/var 中添加以下命令:

# chmod 0774 /var/log/apache
# chown nobody:nobody /var/log/apache

最后,删除现有的 apache_log_dir 目录,并将其替换为链接:

# rm -rf apache_log_dir
# ln -s /var/log/apache apache_log_dir

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