2-2-18-9 QNX系统架构之文件系统(三)
阅读前言
本文以QNX系统官方的文档英文原版资料为参考,翻译和逐句校对后,对QNX操作系统的相关概念进行了深度整理,旨在帮助想要了解QNX的读者及开发者可以快速阅读,而不必查看晦涩难懂的英文原文,这些文章将会作为一个或多个系列进行发布,从遵从原文的翻译,到针对某些重要概念的穿插引入,以及再到各个重要专题的梳理,大致分为这三个层次部分,分不同的文章进行发布,依据这样的原则进行组织,读者可以更好的查找和理解。
1. 文件系统
本文接上一篇继续介绍文件系统:《 2-2-18-9 QNX系统架构之文件系统(二)》
1.7. DOS文件系统
DOS文件系统fs-dos.so
提供了对DOS磁盘的透明访问,因此你可以像对待POSIX文件系统一样对待DOS文件系统。这种透明性允许进程在没有任何特殊知识或工作的情况下对DOS文件进行操作。
磁盘上的DOS文件系统结构老旧且效率低下,并且缺乏许多理想的特性。仅有的主要优点是它在 DOS 和 Windows 环境中具有可移植性。只有在需要将DOS文件传输到需要它的其他机器时,才应该选择这个DOS文件系统。如果不存在 DOS文件可移植性问题,那么请考虑单独使用 Power-Safe 文件系统;如果存在 DOS 文件可移植性问题,则再考虑与 DOS 文件系统结合使用。
如果没有对应于 POSIX 特性的 DOS,fs-dos.so
,要么返回错误,要么返回合理的默认值。例如,尝试创建 link() 将导致返回适当的errno
。另一方面,如果试图读取文件上的 POSIX 时间,fs-dos.so
将会把对任何不支持的“时间”的读取当作是对最后一次的写入时间的读取。
- DOS version support【DOS 版本支持】
fs-dos.so
程序,支持从 DOS 2.1 版本 到 带有长文件名的 Windows 98 的硬盘分区。
- DOS text files【DOS 文本文件】
DOS 用两个字符 (CR/LF
)结束文本文件中的每行,而POSIX(和大多数其他)系统以单个字符(LF
)结束每行。 请注意,在读取时,fs-dos.so
不会尝试转换文本文件。但是大多数实用程序和软件程序可以不受这种差异的影响。
另外,请注意,一些非常旧的 DOS 程序可能会使用 Ctrl–Z (^Z) 作为文件的结束符。对该字符同样不会进行修改。
@>> 阅读扩展:
这里的^Z并不是一个通过常规键值表示的组合,而是一个特殊的控制字符。在ASCII码表中,Ctrl–Z对应的字符编码值是26,也就是ASCII码的控制字符END OF FILE(EOF)。这个字符在文本文件中用来表示文件的结束,特别是在一些旧的文本编辑器和DOS程序中。
- QNX-to-DOS filename mapping
在 DOS 中,文件名不能包含如下任何字符:
/ \ [ ] : * | + = ; , ?
尝试创建包含这些无效字符之一的文件将返回错误。DOS(8.3 格式) 还期望所有字母字符都是大写的,因此当在磁盘上创建文件名时,fs-dos.so
会映射这些字符为大写。但是,在返回文件名给 QNX Neutrino 应用程序时,默认情况下它会把文件名映射为小写,以便 QNX Neutrino 用户和程序始终可以看到并键入小写(通过sfn= sfn_mode
选项)
- Handling filenames【处理文件名】
你可以指定期望fs-dos.so
的处理方式长文件名(通过lfn= lfn_mode
选项)。
-
- 忽略它们 - 仅显示/创建 8.3 格式的文件名。
- 显示它们 - 如果文件名长度超过 8.3 格式规定的长度或使用了大小写混合。
- 始终创建短文件名和长文件名。
如果使用ignore
选项,则可以指定 是否以静默方式截断超出 8.3 格式所限制部分的文件名字符。
- International filenames【国际化文件名】
DOS 文件系统支持 DOS“code page【代码页】”(国际字符集)用于区域化文件名。 短的 8.3 格式文件名使用特定字符集存储(通常区域化最常见的扩展字符,以第 8 比特位字符范围进行编码)。 所有常见的美国以及西欧和东欧的code page【代码页】,支持 (437、850、852、866、1250、1251、1252)。 如果你制作的软件必须访问各种 DOS/Windows 硬盘,或在非美国英语国家/地区运行,则该功能提供了重要的可移植性,文件名将会同时使用 Unicode 编码及区域化名称进行创建,并且是可通过任意一个名称进行访问。
DOS 文件系统仅支持文件名国际化文本。 不会尝试了解数据内容,使用 Windows "shortcut【快捷方式】"(.LNK) 文件,该文件将会被解析并 translated to symbolic links(如果你指定了(
lnk=lnk_mode
)选项。
- DOS volume labels【卷标】
DOS文件系统使用卷标的概念,它实际是一个的 directory
项。 为了区分卷标和实际的 DOS 目录,程序fs-dos.so
根据你指定卷标选项的方式报告卷标。你可以选择:
-
- 忽略卷标。
- 将卷标签显示为名称专用文件。
- 将卷标显示为带有等号的名称专用文件(
=
) 作为卷名称的第一个字符(默认值)。
- DOS-QNX permission mapping【权限映射】
DOS 并非支持所有的 POSIX 所指定的权限位。 例如,它用 READ_ONLY 位代替了单独的 READ 和 WRITE 位;它没有 EXECUTE 位。 创建 DOS 文件时,如果所有 POSIX WRITE 位都被关闭,那么 READ_ONLY 会被置位。访问 DOS 文件时,对于 user、group 和 other,始终假定 POSIX READ 位被置位。
由于你无法执行没有 EXECUTE 权限的文件,fs-dos.so
有一个选项(exe=exec_mode
),允许你指定如何处理可执行文件的 POSIX EXECUTE 位。
- File ownership【文件所有权】
尽管 DOS 文件结构不支持 user ID 和 group ID ,但是如果尝试更改它们,fs-dos.so
(默认情况下)不会返回错误代码。 不返回错误的原因,是因为许多实用程序会尝试修改它们,并且如果失败将导致意外错误。 因此,采取的方法是“你可以把任何东西变成任何东西,因为它反正不会写入磁盘“。
posix=
选项允许你设置更严格的 POSIX 检查并启用 POSIX 仿真。 例如,在 POSIX 模式下,尝试执行以下任一操作时,会标记EINVAL
错误:
-
- 将 User ID 或 Group ID 设置为 default (root) 的 root 对象。
- 删除 (
r
,read) 权限。 - 设置 (
s
,set ID on execution) 权限。
如果将 posix
选项设置为(默认) 或emulatestrict
,你将获得以下好处:
-
.
和..
目录项是在root
目录中创建。- 计算目录大小。
- 目录中的链接数是根据其子目录计算的。
1.8. FFS3文件系统
FFS3 文件系统驱动程序实现了 类似POSIX 的 NOR 闪存设备上的文件系统。驱动程序是独立的可执行文件,既包含 Flash 文件系统代码,又包含 Flash 设备代码。对于不同的嵌入式系统硬件以及 PCMCIA 存储卡,有不同 FFS3 文件系统驱动程序的版本。
驱动程序的命名约定是devf-system
,其中system
字段,描述嵌入式系统。
要了解我们目前支持的 Flash 设备, 请参阅以下来源:
bsp_working_dir/src/hardware/flash
下的 boards 和 mtd-flash 目录- QNX Neutrino 实时操作系统文档 (实用程序参考中的
devf-*
条目) - BlackBerry QNX 网站 (www.qnx.com)
除了预构建的 flash 文件系统驱动程序外,还包括 “通用”驱动程序 (devf-generic)。我们提供了构建自定义Flash FileSystem 驱动程序所需的库和源代码,用于不同的嵌入式系统。
1.8.1. 组织结构【Organization】
FFS3 文件系统驱动程序支持一个或多个逻辑 Flash 驱动器。 每个逻辑驱动器称为一个socket【套接字】,它由一个 Flash 内存的连续且同构的区域组成。例如,在包含两种不同类型 Flash 器件(处于不同地址)的系统中,其中 1 个 Flash 设备用于引导映像【boot image】另一个用于 flash 文件系统,每个 flash 设备 将会出现在不同的socket【套接字】中。
每个socket【套接字】可以分为一个或多个分区。支持的两个分区类型是:Raw Partitions【原始分区】和 Flash filesystem partitions【文件系统分区】。
Raw Partitions【原始分区】
套接字【socket】中的原始分区是不包含 flash 文件系统的任何分区的。 驱动程序无法识别除 flash 文件系统以外的任何其他文件系统类型。 原始分区可能会包含image filesystem【映像文件系统】或一些特定于应用程序的数据。
该FFS3文件系统,将会通过 raw mountpoint【原始挂载点】(见下文)访问 flash 上的任何非 flash 分区。 请注意,flash 文件系统分区也可以作为 raw 分区使用。
Flash filesystem partitions【文件系统分区】
Flash 文件系统分区,包含了与 POSIX Flash filesystem 类似的文件系统,它使用一种 BlackBerry QNX 专有的格式,将文件系统数据存储在 Flash 设备上。此格式与 Microsoft FFS2 或 PCMCIA FTL 规范不兼容。
该文件系统允许自由创建和删除文件和目录。 它使用与垃圾回收【reclaim mechanism】类似的回收机制,从已删除的文件中回收存储空间。
当你启动 flash 文件系统驱动程序时,默认情况下,它将会挂载它在套接字中所能找到的任何分区。 请注意,每个 Flash 设备只能有一个驱动程序实例,并且你必须向驱动程序提供 Flash 芯片的完整大小。 你可以使用mkefs
或flashctl
指定挂载点(例如 /flash)。
挂载点 | 描述 |
| 原始挂载点套接字X |
| 原始挂载点套接字X分区Y |
| 文件系统挂载点套接字X分区Y |
| 文件系统压缩的挂载点套接字X分区Y |
1.8.2. 特征【Features】
FFS3 文件系统支持许多高级功能,例如 POSIX 兼容性, 多线程, 后台回收【background reclaim】、故障恢复【fault recovery】、透明解压【transparent decompression】、 字节序感知【endian-awareness】、磨损均衡【wear-leveling】和错误处理【error-handling】。
POSIX
文件系统支持标准的 POSIX 功能(包括长文件名、访问特权【access privileges】、随机写入【random writes】、truncation【截断】 和 symbolic links【符号链接】),但以下情况除外:
- 你无法创建硬链接【hard links】。
- 访问时间不受支持(但支持文件修改时间和属性更改时间)。
这些设计上的妥协,使这个文件系统保持小而简单,但通常包含了块设备文件系统能够找到的大多数功能。
@>> 阅读扩展:
truncation指的是调整文件大小的功能。具体来说,truncation操作可以删除文件中从某个位置开始到文件末尾的数据,使得文件大小发生变化。在这个过程中,被截断部分之前占用的数据块会被释放,以供其他文件使用。此操作对于管理文件存储空间、优化文件系统等具有重要意义。在Linux文件系统中,truncation操作可以通过特定的系统调用或命令来实现,如
truncate
命令。该命令允许用户将文件大小缩小或扩展到指定的大小,如果文件大于指定的大小,则会丢失额外的数据;如果文件较短,则会被扩展,扩展部分的内容为零字节。
存储效率
文件系统对存储在文件系统上的每个用户数据块使用固定大小的32字节区段头。文件系统有一个512字节的“append buffer”,用于把 small append 合并到文件,然后再将其刷新到磁盘。 文件系统中没有其他的用户数据缓存(读取或写入)。 尽管mkefs
可以创建16 KB的 extents【数据区段】,但是对于在运行时所创建的文件,目前最大 extent 大小被限制为 4096 字节的数据(加上32字节header)。
@>> 阅读扩展:
文件系统的extents表示一组连续的数据块(通常是磁盘块或页),它们按顺序分配给文件或数据结构。这一概念用于描述一种用于组织和分配数据存储空间的方式,旨在提高文件系统的性能并减少文件碎片。
- 连续性:一个extent是一个连续的数据块范围,有助于提高读取和写入性能。
- 分配策略:文件系统或存储管理系统通常会分配一个或多个连续的extent来容纳文件的数据。
- 大小可变:extent的大小可以根据存储系统的配置和策略而变化。
- 元数据:存储管理系统会维护关于extent的元数据,包括数据块偏移量、大小和位置等信息。
- 文件系统支持:extent 是一种在现代文件系统中广泛使用的分配策略。一些文件系统,如 Btrfs、XFS 和 ZFS,使用 extent 作为它们的默认分配单元,以提高性能和管理数据。
总之,extent 是一种用于管理存储空间和提高文件系统性能的方法,它通过分配连续的数据块范围来减少文件碎片。这对于文件系统、数据库管理系统和其他需要大规模数据存储的应用程序非常有用。
磨损均衡
磨损均衡是在给定分区内的块上执行的。 如果 flash 被拆分为多个分区,则每个分区都有一个 较小的池要均衡访问。 块永远不会从一个分区迁移到另一个分区。
前台回收是文件系统中最常见的回收类型,总是会执行双重回收操作。 第一重回收总是查找分区中擦除计数最少的块,并将其与备用块进行交换。 然后是第二重回收,将需要回收的块将与备用块进行交换。 事实证明,当使用前台回收时,会导致近乎完美的磨损均衡。
后台回收
FFS3 文件系统会把文件和目录存储为extents【数据区段】的链接列表,这些extents【数据区段】被标记为要删除状态,则它们将会被删除或更新。要回收的 extents 会使用一种简单的算法来进行选择,该算法会查找具有要回收的最大空间的块,同时保持每个单独块的磨损量水平。 这种磨损均衡可以增加 Flash 设备的 MTBF(平均故障间隔时间),从而延长其使用寿命。
当没有足够的可用空间时,将执行后台回收过程。 后台回收过程首先会将待回收块的内容复制到一个空的备用块中,然后使用该备用块替换待回收块。再然后,待回收块会被擦除。与带有机械磁头的旋转存储介质原理不同,数据分布的接近性并不是 Flash 文件系统性能的一个因素,因此数据可以分散在介质上,而不会降低性能。
故障恢复
该文件系统旨在最大程度地减少由于意外断电故障而导致的损坏。 对 extent headers 及 erase block headers 的更新,始终按照经过谨慎计划的顺序进行执行。 这些步骤允许在数据损坏的情况下恢复文件系统的完整性。
请注意,对于有效的故障恢复系统,正确设计的 Flash 硬件是至关重要的。 特别是,必须有特殊的复位电路,以便在电源电压跌落至某临界值以下之前,使系统保持在“复位”状态。 否则,虚假或随机的总线活动会形成写入/擦除命令,并损坏闪存,从而造成无法恢复。
重命名操作保证是原子的,即使发生断电故障也是如此。 这意味着,例如,如果你在为映像或可执行文件指定新名称时断电, 恢复后,你仍然可以通过其旧名称访问文件。
当 FFS3 文件系统驱动程序启动时,从 简单的块的回收 到 擦除悬空的 extent 链接,它会扫描介质上每个 extent header 的状态(以便验证其完整性),并采取适当的措施。 此过程与文件系统的正常挂载过程合并,以实现最佳的引导计时。
压缩和解压缩
为了快速有效地压缩/解压缩,你可以使用deflate
和inflator
实用程序,它们依赖于流行的 deflate/inflate 算法。
deflate
算法结合了两种算法。第一个算法负责删除文件中的数据重复;第二个算法通过给它们分配更短的符号,处理出现频率最高的数据序列。这两种算法提供了出色的数据及可执行文件的无损压缩。而inflate
算法只是简单地反向执行了deflate
算法所做的事情。
deflate
实用程序旨在与mkefs
的filter
属性一起使用。 你还可以使用它来预压缩文件用于 Flash 文件系统。
inflate
资源管理器位于其他文件系统之前,该文件系统先前使用deflate
实用程序对文件进行了压缩。 它几乎可以使 flash 的有效空间增加一倍。
压缩文件可以使用cp
或ftp
等标准实用程序进行操作,如果对正确的挂载点使用ls
实用程序,可以显示其压缩后大小和未压缩的大小。这些功能使得系统设计师对压缩的 Flash 文件系统可以进行无缝管理。
Flash 错误
随着 flash 硬件的磨损,其写入状态机可能会发现它无法再写入或擦除某些特定的 bit cell【比特单元】。当发生这种情况时,错误状态会被传回 flash 驱动程序,以便它可以采取适当的操作(也就是,标记 bad 区域,并尝试在另一个位置进行写入或擦除)。
此错误处理机制是透明的。 请注意,在发生多次 Flash 错误之后,所有失败的写入和擦除操作最终会造成 Flash 被呈现为只读状态。幸运的是,在多年的 flash 操作之前这种情况不应该会发生。 检查你的 Flash 规格并分析应用程序到 Flash 的数据流,可以计算其潜在寿命或 MTBF。
字节序感知
FFS3 文件系统具有字节序感知功能,因此可以跨不同平台进行移植。 推荐的最佳方法是,使用 mkefs 实用程序选择目标字节序。
1.8.3. 实用程序【Utilities】
文件系统支持所有标准的 POSIX 实用程序,比如ls
,mkdir
,rm
,ln
,mv
,和cp
等。还有一些特定于 QNX Neutrino 的实用程序也可以用于管理 falsh:
flashctl
擦除、格式化和挂载 Flash 分区。
deflate
压缩 Flash 文件系统的文件。
mkefs
创建 Flash 文件系统映像文件。
1.8.4. 系统调用【System calls】
该文件系统支持所有标准的 POSIX I/O 函数,例如 open()
,close()
,read()
,以及 write()
等。 使用非 POSIX 的 devctl()
函数支持擦除等特殊功能。
1.9. NFS文件系统
网络文件系统(NFS)允许客户端工作站通过网络执行透明的文件访问。它允许客户端工作站跨各种操作系统对驻留在服务器上的文件进行操作。客户端对文件的访问调用会转换为NFS协议请求,并通过网络发送给服务器。服务器在接收到请求后,执行实际的文件系统操作,并将响应结果发送回客户端。
网络文件系统通过使用远程程序调用(RPC)以及TCP/IP 进行传输,以无状态方式进行运行。因此,要使用fs-nfs3
,还需要为 QNX Neutrino 运行 TCP/IP 客户端。
在远程服务器文件系统中的任何 POSIX 限制,都会被传递给客户端。例如,文件名的长度可能因服务器的不同操作系统而有所不同。version 3 版本的 NFS 将文件名长度限制为了 255 个字符;而 version 1 和 version 3 版本的mountd将路径名长度限制为1024个字符。
1.10. CIFS文件系统
CIFS(Common Internet File System,通用互联网文件系统,以前称为SMB)允许客户端工作站通过网络对运行SMB服务器的 Windows 系统或 UNIX 系统执行透明的文件访问。客户端对文件的访问调用会被转换为CIFS协议请求,通过网络发送给服务器。服务器在接收到请求后,执行实际的文件系统操作,并将响应发送回客户客户端。
CIFS协议未试图与POSIX保持一致。
fs-cifs
管理器使用TCP/IP进行传输。因此,要使用fs-cifs
,还需要为QNX Neutrino RTOS运行TCP/IP客户端。
1.11. Linux Ext2文件系统
Ext2
文件系统提供对Linux磁盘分区的透明访问。
fs-ext2.so
实现了支持Ext2的 version 0 和 version 1 版本中的标准功能集。
对稀疏文件的支持也包含在内,是为了与现有的Linux分区兼容。其他文件系统只能在稀疏文件之上“堆叠”为只读。普通文件没有这样的限制。
@>> 阅读扩展:
稀疏文件是一种特殊类型的计算机文件,旨在更有效地使用文件系统的空间。
- 定义:稀疏文件是一种计算机文件,当文件内容大多为空时,它尝试更有效地使用文件系统的空间。
- 原理:稀疏文件使用简短的信息(元数据)来表示空数据块,而不是在磁盘上占用实际空间来存储空数据块。只有真实(非空)的数据块会按原样写入磁盘。
- 读取方式:在读取稀疏文件时,文件系统会根据元数据在运行时将这些空数据块转换为“真实”的数据块,即填充为零,应用程序不会察觉这个转换。
- 应用场景:稀疏文件常用于数据库文件、虚拟机文件等场景,可以有效减少物理磁盘的占用。
其他文件系统只能以只读的方式“堆叠”在稀疏文件之上,而对于普通文件则没有这样的限制。
具体来说,“堆叠”在这里可能指的是将另一个文件系统叠加在当前文件系统之上,以便同时访问两个文件系统的内容。然而,当涉及到稀疏文件时,这种堆叠操作只能以只读方式进行,这可能是为了防止对稀疏文件结构的破坏或数据丢失。
相比之下,对于普通文件,没有这样的堆叠限制,可以自由地以读写方式访问和修改它们。
如果Ext2
文件系统没有正确卸载,则文件系统检查器通常会在下次挂载文件系统时负责清理。虽然fs-ext2.so
模块配备了执行快速测试的功能,如果检测到任何(应该使用文件系统检查器修复的)重大问题,它会自动将文件系统挂载为只读状态。
1.12. 通用磁盘格式(UDF)文件系统
通用磁盘格式(UDF)文件系统提供对可记录媒体的访问,例如CD、CD-R、CD-RW和DVD。它可以用于DVD视频,但也可以用于备份数据到CD,等等。欲了解更多信息,请访问 OSTA Universal Disk Format Specifications。
在我们的实现中,UDF文件系统是只读的。
1.13. 苹果麦金塔 HFS 和 HFS Plus
苹果麦金塔 HFS(Hierarchical File System,分级文件系统)和 HFS Plus 是苹果麦金塔系统上的文件系统。
fs-mac.so
共享对象,提供了对 QNX Neutrino 系统上的 HFS 和 HFS Plus 磁盘的只读访问。该程序可以识别以下变体:HFS、HFS Plus、HFSJ(HFS Plus with journal,带日志的HFS Plus)、HFS包装器中的HFS Plus、HFSX(区分大小写)和 HFS/ISO-9660 混合型。在QNX Neutrino 7.0.4或更高版本中,你也可以用热日志(或脏日志)挂载 HFSJ 文件系统。
1.14. Windows NT文件系统
NT
文件系统用于 Microsoft Windows NT 及更高版本。
fs-nt.so
共享对象,提供了对 QNX Neutrino 系统上的 NTFS 磁盘的只读访问。
1.15. 解压缩直通文件系统
QNX Neutrino 提供了一个解压缩直通文件系统【Inflator pass-through filesystem】,它是一个位于其他文件系统前面的资源管理器,可以(使用deflate
实用程序)对以前被压缩的文件进行解压。
当底层文件系统是 flash 文件系统时,通常会结合inflator
实用程序进行使用,几乎可以使 flash 的有效空间增加一倍。
如果正在打开文件进行读取,则inflator
将尝试在底层文件系统上打开该文件本身。它读取前16个字节并检查压缩文件的签名。如果文件被压缩,inflator
会将自己置于应用程序和底层文件系统之间。所有读操作都返回文件被压缩之前的原始数据。
从应用程序的角度来看,文件似乎是未压缩的。也支持随机查找。如果应用程序对文件执行stat()
操作,则会返回解压后的文件的大小(也就是文件被压缩前的原始大小)。
在重叠的路径名空间上运行多个直通文件系统或资源管理器可能会导致死锁。
1.16. QNX可信磁盘
QNX可信磁盘(QTD,QNX Trusted Disk)设备,在安全引导环境中,为底层磁盘数据提供完整性保护。它们可以将安全引导链扩展到核心操作系统的文件系统中,在该文件系统中存储有关键二进制文件和配置文件。
QTD保护机制基于哈希树(Merkle tree),由fs-qtd.so
共享对象进行支持。
在构建QTD映像时,会从源文件系统映像的块中构造元数据哈希树【metadata hash tree】。
@>> 阅读扩展:
Merkle Tree是一种基于哈希的树状数据结构。以下是关于Merkle Tree的详细解释:
- 定义:Merkle Tree,又称哈希树,是一种持久性数据结构,用于实现集合和映射,旨在替换纯函数式编程中的哈希表。
- 结构:在Merkle Tree中,每个叶子节点代表一个数据块(如文件或文件集合)的哈希值,每个非叶子节点是其子节点哈希值的哈希。通常,Merkle Tree的分支因子为2,即每个节点最多有2个子节点。
- 应用:Merkle Tree在密码学、分布式系统和区块链等领域得到广泛应用。在区块链中,它用于验证交易和区块的完整性,确保数据不被篡改,从而提高区块链的可扩展性和安全性。
QTD磁盘设备是只读的。QTD驱动程序位于原始块设备和受支持的上层文件系统层之间(例如,由fs-qnx6.so
进行支持的Power-Safe文件系统)。在读访问时,它使用哈希树元数据【hash tree metadata】来验证数据的完整性。如果验证失败,则返回错误。
使用密钥对【key pair】对QTD元数据进行签名和验证。对签名进行验证可以确保树的根哈希是有效的,并且没有被篡改。它是可信验证机制的根。
QTD 映像的大小取决于所选择的块大小以及所选择的摘要算法【digest algorithm】。可以使用mkqfs
实用程序生成统计信息,描述元数据消耗了多少额外的空间。
1.16.1. 使用QTD作为受保护的容器(应用模型)
通过挂载一个本身就是QTD映像的文件,你可以将QTD用作 package container 的解决方案。请参见实用程序参考中的fs-qtd.so
项。
1.16.2. 安全散列算法(SHA)
根据你目标的架构和摘要函数所需的安全强度,请你参考下表,选择性能最佳的算法。并对你的系统进行基准测试以确定最佳组合。
Architecture【架构】 | Digest security【摘要的安全性】 | |
128 bits | 256 bits | |
32-bit | sha256 blake2s256 blake3 | sha512 blake2b512 |
64-bit | sha512‑256 blake2b256 blake3 | sha512 blake2b512 |
@>> 阅读扩展:
Secure Hash Algorithms(SHA),即安全散列算法,是一个密码散列函数家族,能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法。且若输入的消息不同,它们对应到不同字符串的几率很高。SHA是由美国国家安全局(NSA)开发的算法家族,用于保障数据的安全性和完整性。SHA算法能将接收到的消息通过哈希算法转换成固定位数的哈希值(也称消息摘要),用于验证数据的完整性。SHA算法经历了多个版本的更新,包括SHA1、SHA2、SHA3等,其中SHA1已经被破解,目前使用比较广泛的是SHA2类,如SHA256。SHA算法主要应用于各种网络安全和数据加密领域,如数字签名标准(DSS)里面定义的数字签名算法(DSA),以及汽车ECU中重要数据的保护等。
1.16.3. 签名密钥【Signing keys】
有关支持的密钥类型和签名算法,请参阅mkqfs
实用程序。
1.16.4. 加密引擎【Crypto engines】
QTD使用通过QNX加密库(qcrypto
)提供的加密算法。它可以使用任何支持所选摘要算法和签名类型的qcrypto插件。有关更多信息,请参阅系统安全指南中的“QNX Cryptography Library”。
1.17. 文件系统事件
对于使用它的程序来说,跟上一个经常快速变化的非常“活跃”的文件系统是一个挑战。为了帮助解决这个问题,QNX Neutrino包含了文件系统事件。
这些事件使得应用程序能够跟踪相关文件系统中的更改,包括文件和目录的创建和删除、所有权和权限的更改、挂载和卸载操作等等。对文件系统事件的管理,涉及到一个事件管理器、一个事件机制和客户端事件处理程序。
事件管理器fsevmgr
是一个进程,它会在系统名称空间中注册一个固定的名称(默认为/dev/fsevents
),并在该路径上接收文件系统事件(可能来自多个io-blk.so
实例),从而确定哪些客户端需要哪些事件,并将事件提供给这些客户端。
事件机制是io-blk.so
的一部分,任何的文件系统,或者块I/O系统部分,都可以轻松地使用它。这种方式提供了最大的灵活性,因为我们可以在系统调用级别协调事件进入文件系统,这些事件可能来自文件系统内部、分区、缓存甚至块设备驱动程序(如果需要的话)。
该机制会将事件先放入缓冲区,然后最终发送给事件管理器。这种机制仅限于用于报告事件来源的API、指示事件的唯一标识符,以及进一步描述事件的属性。io-blk.so
库负责打包每个事件并将其发送给事件管理器。该实现使用定时器来确保事件不会在此缓冲区中停留很长时间。
在启动时,io-blk.so
寻找事件管理器。如果事件管理器未加载,则禁用事件机制。所提供的三个配置参数如下所示:
- fse-device — 事件管理器的名称
- fse-period — 在事件被发送到事件管理器之前延迟的最大时间
- fse-size — 保存事件的缓冲区的大小
在加载事件管理器期间,devctl
命令DCMD_FSYS_FSEVMGR_CHECK
会被发送到各个io-blk.so
挂载点,通知它们事件管理器已经加载完成。
最后,客户端事件处理程序可以实例化一个线程,该线程需要进入阻塞状态从/dev/fsevents
读取数据,或者在数据可用时选择文件描述符进行通知。
以下是客户端通常如何与事件管理器交互的概述:
open()
FSE_DEFAULT_MANAGER_NAME
(在<sys/fs_events.h>
中定义)描述了事件管理器的默认路径。请记住,它可能被事件管理器覆盖【overridden 】,并且io-blk.so
也可能会转而寻找另一个事件管理器。
客户端通常应该以O_RDONLY
模式打开事件管理器,以便简单地读取事件。只有当客户端需要发送事件时,才需要写模式。如果客户端要轮询事件管理器,则设置O_NONBLOCK
标志。
read()
客户端将事件从事件管理器读取到字节数组中。字节数组被填充到存储整个事件所需的大小。换句话说,部分事件不会返回给读取者。不能对缓冲区内事件的对齐进行任何假设。
FSE_READ_EVENT_S(pev, pbytes)
作为包装器提供给memcpy()
从字节数组到对齐结构的事件。从那里,客户端可以使用其他FSE_*
访问器宏来解释事件特征。
虽然事件管理器通常会有一个大的队列来容纳事件,但不可避免地,它如果被填满将会开始覆盖旧事件。如果任何事件客户端没有跟上新事件的添加速度,那么这些读取器将会被置于溢出状态。换句话说,如果事件管理器已经开始覆盖读取器尚未使用的事件,则从该描述符读取的下一次读取开始,将会指示EOVERFLOW
错误。随后的read()
操作会返回当前队列中最早的事件。
lseek()
事件管理器支持有限的查找功能。通常,客户端从队列的头部开始读取,并且立即阻塞和等待新事件。如果客户端必须评估过去的事件,则可以使用lseek()
。
使用SEEK_SET
作为whence
的值并将偏移量设置为零,可将文件描述符定位到队列中最早的事件。请注意,这种情况可能会在随后的read()
中导致EOVERFLOW
错误。
使用SEEK_END
作为whence
的值并将偏移量设置为零,可将读取器定位到队列末尾以读取新事件。
客户端可以使用事件计数值作为偏移量,使用SEEK_SET
或SEEK_END
分别从队列的头部或尾部,索引一些事件的计数值。
write()
客户端可以使用write()
将事件发送到事件管理器。事件管理器检查事件数据以确保其格式良好;如果检查失败,事件管理器将会终止在单次写操作中所发送的所有事件的写操作的执行。
close()
如果一旦不再需要文件描述符,则可能就会需要被关闭。
头文件<sys/fs_events.h>
中包含了从事件管理器读取以及处理事件所需的所有内容。有关更多信息,请参阅 C 库参考中的 FSE_*() 的内容。