文件系统架构

本文档旨在简要介绍 Fuchsia 文件系统。 从其初始化、讨论标准文件系统操作(例如 开放、读取、写入等)以及实现用户空间文件系统的怪异。 此外,本文档还将介绍命名空间内的 VFS 级别遍历, 可用于与非存储实体(例如系统 服务)。

文件系统即服务

与更为常见的单体式内核不同,Fuchsia 的文件系统完全依赖于 用户空间内的数据它们既不会与内核关联,也不会加载内核;它们是 用户空间进程,这些进程用来实现 文件系统因此,Fuchsia 的文件系统本身可以改变。 - 修改不需要重新编译内核。

文件系统方框图

图 1:典型的文件系统进程块图。

与 Fuchsia 上的其他原生服务器一样, 文件系统服务器是使用句柄基元(而不是系统)实现的 调用。内核不了解文件、目录或文件系统。如 因此文件系统客户端无法向内核请求“文件系统访问权限” 。

此架构意味着,与文件系统的交互仅限于 以下接口:

  • 在通过文件系统建立的信道上发送的消息 服务器。这些通信渠道对于客户端而言可能是本地信息 文件系统或远程
  • 初始化例程(预计会在 按文件系统进行分配网络文件系统需要网络访问权限 永久性文件系统可能需要块设备访问、内存中文件系统 只需要一种机制来分配新的临时页面)。

此界面的优势在于,任何可通过通道访问的资源都有助于 它们本身就像文件系统一样, 文件或目录例如,组件为其 传出目录 ,其中包含自己的 功能

文件生命周期

建立连接

为打开文件,Fuchsia 程序(客户端)会向文件系统发送 RPC 请求 服务器

FIDL 定义了在 文件系统客户端和服务器你无需与由内核实现的 VFS 层,Fucsia 会处理向文件系统服务发送请求, 实现文件、目录和设备协议。发送上述任一邮件 ,则 Fuchsia 进程必须通过现有 目录句柄;有关此流程的更多详情,请参阅广告的生命周期 打开文档

命名空间

在 Fuchsia 上,命名空间是存在的小型文件系统 完全在客户端中进行最基本的概念是 将“/”保存为根并将句柄与其相关联是非常原始的 命名空间。而不再使用一个典型的“global”文件系统命名空间,Fucsia 进程可以提供任意目录句柄来表示“根目录”, 来限制其命名空间的范围为了限制这一范围 文件系统故意不允许通过 dotdot

Fuchsia 进程可能会额外重定向某些路径操作, 文件系统服务器。当客户提及“/bin”时,客户可以选择 将这些请求重定向到表示“/bin”目录的本地句柄, 而不是直接向“root”下的“bin”目录发送请求 目录。与所有文件系统结构一样,命名空间也不会从 内核:而是在客户端运行时(例如 libfdio)是介于大多数客户端代码之间的 以及远程文件系统的句柄

由于命名空间对句柄以及大多数 Fuchsia 资源和服务运行 都可通过标识名进行访问,它们是非常有用的概念。 文件系统对象(如目录和文件)、服务、设备 软件包和环境(对特权进程可见)均可使用 这些句柄,并且可以在子进程中任意组合。作为 命名空间让您可以在自定义资源层级发现 应用。一个进程在“/svc”中观察到的服务不一定 与其他进程看到的内容不匹配,并且可被限制或重定向 应用启动政策

用于详细了解限制过程的机制和政策 功能,请参阅有关 沙盒

传递数据

与某文件、目录、设备、 后续操作也会使用 RPC 消息进行传输。 这些消息通过一个或多个句柄传输 服务器进行验证和理解

对于文件、目录、设备和服务,这些操作会使用 FIDL 协议。

例如,如需在文件中跳转,客户端会发送 Seek 消息替换为 FIDL 消息中的所需位置和“whence”,以及 则会返回新的定位位置。如需截断文件,您可以使用 Truncate 以及一条状态消息 返回的值。如需读取目录,可以创建 ReadDirents 消息, 已发送,同时会返回目录列表。如果这些请求是 如果文件系统实体无法处理,则会发送错误,而 操作将不会执行(例如,发送至文本的 ReadDirents 消息 文件)。

内存映射

对于支持此功能的文件系统,内存映射文件要稍微多一点, 复杂。要实际对文件的一部分进行 mmap,客户端会发送一个“GetVmo” 消息,并收到响应的虚拟内存对象 (VMO)。此对象 随后通常会使用虚拟内存映射到客户端的地址空间 地址区域,即 VMAR。传输有限视图的文件内部 将“VMO”返回客户端需要通过中间消息执行额外的工作 传递层,让他们知道自己传回的是服务器供应商提供的 对象句柄。

通过传回这些虚拟内存对象,客户端可以快速访问 表示文件的内部字节,实际上无需支付 往返 IPC 消息。这一功能使 mmap 成为 尝试在文件系统交互上实现高吞吐量的客户端。

对路径执行操作的其他操作

除了“open”操作之外,系统还会执行一些 分别是“重命名”和“关联”与“开放”不同, 操作实际上会同时对多个路径执行操作,而不是对单个 位置。这会使其用法变得复杂:如果调用“rename(‘/foo/bar’, “baz”),那么文件系统需要想出一种方法来:

  • 需要遍历这两条路径,即使起点不同(例如 就是这里;一个路径从根目录开始,另一个路径从 CWD 开始)
  • 打开两个路径的父级目录
  • 同时对父目录和尾随路径名执行操作

为了满足这种行为,VFS 层利用 Zircon 概念 称为“Cookie”这些 Cookie 可让客户端操作存储打开的 使用句柄在服务器上存储状态, 标识名。Fuchsia 文件系统使用此功能来引用一个 Vnode, 对另一个数据库执行操作。

这些多路径操作执行以下操作:

  • 打开父级源 vnode(对于“/foo/bar”,这意味着打开“/foo”)
  • 打开目标父级 vnode(对于“baz”,这意味着打开当前的 工作目录),并使用命令获取 vnode 令牌 GetToken:文件系统 Cookie 的句柄。
  • 向源父级 vnode 发送“重命名”请求以及源 和目标路径(“bar”和“baz”),以及获取的 vnode 令牌 。这为文件系统提供了一种机制来安全地引用 目的地 vnode 间接 -- 如果客户端提供的句柄无效, 内核会拒绝访问 Cookie 的请求,然后服务器就可以返回 出错。

文件系统生命周期

安装方式

Fshost 负责在系统上装载文件系统。时间: 系统正在进行更改,以使文件系统作为组件运行(尽管 fshost 仍会控制这些文件系统的装载)。请尽可能 则使用静态路由请参阅 fuchsia.fs.startup/Startup 协议。

文件系统管理

有一系列文件系统操作被视为与 “administration”(包括“卸载当前文件系统”)。这些 由 fs.Admin 接口定义的 admin.fidl.文件系统会导出此服务 以及对文件系统根目录的访问权限

当前文件系统

由于 Fuchsia 架构的模块化性质, 向系统添加文件系统目前,有很多文件系统 来满足各种不同的需求

MemFS:内存文件系统

MemFS 用于实现对 /tmp 等临时文件系统的请求, 完全存在于 RAM 中,且不会传输到底层块存储设备。 此文件系统目前还用于“bootfs”协议,其中 表示一组文件和目录集合的大型只读 VMO 在启动时解封装到用户可访问的 Vnodes(这些文件可在 /boot)。

MinFS:永久性文件系统

MinFS 是一种简单的传统文件系统, 持续运行。与 MemFS 一样,它广泛利用了前面提到的 VFS 层 但与 MemFS 不同,它需要一个额外的块存储设备句柄 (在启动时传输到新的 MinFS 进程)。为了便于使用 MinFS 还提供各种工具:用于格式化的“mkfs”、用于进行格式化的“fsck” 以及用于加减 MinFS 的“mount”和“umount” 从命令行迁移到命名空间。

Blobfs:进行完整性验证的不可变软件包存储文件系统

Blobfs 是一个简单的平面文件系统,已针对“一次写入,然后只读”签名进行了优化 数据,例如 软件包。 除了两个小前提条件(文件名是确定性的)、内容 文件的 Merkle 树根目录的可寻址哈希值,用于完整性验证) 并转发文件大小信息(通过调用 在将 blob 写入存储空间之前执行“ftruncate”操作),则 Blobfs 看上去像是 一个典型的文件系统它能装载和卸载,似乎包含一个 哈希值的单个平面目录,而 Blob 可通过 “open”“read”“stat”和“mmap”

FVM

Fuchsia 音量管理器 是“逻辑卷管理器”在现有代码块的基础上更灵活地提升灵活性 设备。当前功能包括添加、删除、扩展和 压缩虚拟分区。为了在内部使用 FVM, 维护从(虚拟分区、块)到 (切片、物理块)。为了将维护开销降至最低 以称为“切片”的块的形式缩小/增大分区。切片是 本地块大小除了元数据之外,设备的其余部分还可以分为 。每个切片要么是空闲的,要么属于且仅属于一个分区。 如果某个 Slice 属于某个分区,FVM 会保留其相关元数据 该分区正在使用该 Slice,且该 Slice 在 中的虚拟地址 该分区。

FVM 的磁盘布局如下所示,并声明 此处

      +---------------------------------+ <- Physical block 0
      |           metadata              |
      | +-----------------------------+ |
      | |       metadata copy 1       | |
      | |  +------------------------+ | |
      | |  |    superblock          | | |
      | |  +------------------------+ | |
      | |  |    partition table     | | |
      | |  +------------------------+ | |
      | |  | slice allocation table | | |
      | |  +------------------------+ | |
      | +-----------------------------+ | <- Size of metadata is described by
      | |       metadata copy 2       | |    superblock
      | +-----------------------------+ |
      +---------------------------------+ <- Superblock describes start of
      |                                 |    slices
      |             Slice 1             |
      +---------------------------------+
      |                                 |
      |             Slice 2             |
      +---------------------------------+
      |                                 |
      |             Slice 3             |
      +---------------------------------+
      |                                 |

分区表由多个虚拟分区组成 条目 (VPartitionEntry)。除了包含名称和分区之外, 每个 vpart 条目都包含分配的 多个切片。

切片分配表由紧凑的切片条目组成 (SliceEntry)。每个条目均包含

  • 分配状态
  • 如果已分配 <ph type="x-smartling-placeholder">
      </ph>
    • 它属于哪个分区
    • 该切片映射到该分区中的哪个逻辑切片

可以找到 FVM 库 此处。中 铺路、 一些分区会从主机复制到目标分区。分区和 FVM 文件本身可能在主机上创建。为此,可以使用主机端实用程序 此处。 可以使用 fvm-check