Linux 中的虚拟文件系统:为什么需要它们以及它们如何工作? 第2部分

大家好,我们正在与您分享《Linux 中的虚拟文件系统:为什么需要它们以及它们如何工作?》的第二部分。 你可以阅读第一部分 这里。 让我们提醒您,该系列出版物的发布时间与课程新流的推出同时进行 《Linux 管理员》,很快就开始了。

如何使用 eBPF 和 bcc 工具监控 VFS

了解内核如何操作文件的最简单方法 sysfs 就是在实践中看,而看ARM64最简单的方法就是使用eBPF。 eBPF(伯克利数据包过滤器的缩写)由运行在 核心,特权用户可以请求哪些(query)从命令行。 内核源代码告诉读者内核可以做什么; 在已加载的系统上运行 eBPF 工具可以显示内核实际在做什么。

Linux 中的虚拟文件系统:为什么需要它们以及它们如何工作? 第2部分

幸运的是,在工具的帮助下开始使用 eBPF 非常容易 BCC,它们可以作为一般发行版的包提供 Linux 并详细记录 伯纳德·格雷格。 工具 bcc 是插入少量 C 代码的 Python 脚本,这意味着熟悉这两种语言的任何人都可以轻松修改它们。 在 bcc/tools Python 脚本有 80 个,这意味着开发人员或系统管理员很可能能够选择适合解决问题的脚本。
要至少粗略地了解 VFS 在正在运行的系统上所做的工作,请尝试 vfscount или vfsstat。 比方说,这将显示数十个调用 vfs_open() “他的朋友”几乎每秒都在发生。

Linux 中的虚拟文件系统:为什么需要它们以及它们如何工作? 第2部分

vfsstat.py 是一个带有 C 代码插入的 Python 脚本,用于简单地计算 VFS 函数调用的数量。

让我们举一个更简单的例子,看看当我们将 USB 闪存驱动器插入计算机并且系统检测到它时会发生什么。

Linux 中的虚拟文件系统:为什么需要它们以及它们如何工作? 第2部分

使用 eBPF 你可以看到发生了什么 /sys当插入 USB 闪存驱动器时。 这里显示了一个简单和复杂的示例。

在上面所示的示例中, bcc 工具 跟踪.py 运行命令时打印一条消息 sysfs_create_files()。 我们看到 sysfs_create_files() 是使用启动的 kworker 流响应闪存驱动器插入的事实,但创建了什么文件? 第二个示例展示了 eBPF 的强大功能。 这里 trace.py 打印内核回溯(-K 选项)和创建的文件的名称 sysfs_create_files()。 单语句插入是 C 代码,其中包含运行 LLVM 的 Python 脚本提供的易于识别的格式字符串 即时编译器。 它编译该行并在内核内的虚拟机中执行它。 全功能签名 sysfs_create_files () 必须在第二个命令中重现,以便格式字符串可以引用参数之一。 这段 C 代码中的错误会导致 C 编译器出现可识别的错误。 例如,如果省略 -l 参数,您将看到“无法编译 BPF 文本”。 熟悉 C 和 Python 的开发人员会找到这些工具 bcc 易于扩展和更改。

当USB驱动器插入时,内核回溯将显示PID 7711是一个线程 kworker创建了该文件 «events» в sysfs。 因此,来自 sysfs_remove_files() 将显示删除驱动器导致文件被删除 events,这对应于引用计数的一般概念。 同时,观看 sysfs_create_link () 插入 USB 驱动器时使用 eBPF 将显示至少已创建 48 个符号链接。

那么事件文件有什么意义呢? 用法 示波器 用于搜索 __device_add_disk(),显示其原因 disk_add_events (),或者 "media_change""eject_request" 可以记录在事件文件中。 这里内核块层通知用户空间一个“磁盘”已经出现并弹出。 请注意,与试图纯粹从源头上弄清楚事物如何工作相比,这种通过插入 USB 驱动器的研究方法提供了多少信息。

只读根文件系统支持嵌入式设备

当然,没有人会通过从插座上拔下插头来关闭服务器或计算机。 但为什么? 这是因为物理存储设备上安装的文件系统可能具有滞后写入,并且记录其状态的数据结构可能与对存储的写入不同步。 发生这种情况时,系统所有者必须等到下次启动才能启动该实用程序。 fsck filesystem-recovery 并且,在最坏的情况下,还会丢失数据。

然而,我们都知道许多物联网设备,以及路由器、恒温器和汽车,现在都运行 Linux。 其中许多设备几乎没有用户界面,并且无法“彻底”关闭它们。 想象一下,当控制单元的电源关闭时,启动一辆电池没电的汽车 Linux 不断地上下跳跃。 系统启动没有很长的时间怎么办? fsck发动机什么时候最终开始运转? 答案很简单。 嵌入式设备依赖根文件系统 仅供阅读 (略 ro-rootfs (只读根文件系统))。

ro-rootfs 提供了许多不如真实性那么明显的好处。 优点之一是恶意软件无法写入 /usr или /lib,如果没有 Linux 进程可以在那里写入。 另一个问题是,很大程度上不可变的文件系统对于远程设备的现场支持至关重要,因为支持人员依赖于名义上与现场系统相同的本地系统。 也许最重要(但也是最阴险)的好处是 ro-rootfs 迫使开发人员在系统设计阶段决定哪些系统对象是不可变的。 使用 ro-rootfs 可能会很尴尬和痛苦,因为 const 变量通常出现在编程语言中,但它们的好处很容易证明额外的开销是合理的。

创建 rootfs 只读需要嵌入式开发人员付出一些额外的努力,这就是 VFS 发挥作用的地方。 Linux 要求文件位于 /var 是可写的,此外,许多运行嵌入式系统的流行应用程序将尝试创建配置 dot-files в $HOME。 主目录中配置文件的一种解决方案通常是预先生成并将它们构建到 rootfs。 为 /var 一种可能的方法是将其安装在单独的可写分区上,同时 / 以只读方式安装。 另一种流行的替代方法是使用绑定或覆盖安装。

可连接和可堆叠的安装座及其在容器中的使用

执行命令 man mount 是了解可绑定和可覆盖安装的最佳方式,它使开发人员和系统管理员能够在一个路径中创建文件系统,然后将其公开给另一个路径中的应用程序。 对于嵌入式系统,这意味着能够将文件存储在 /var 在只读闪存驱动器上,但来自覆盖或可链接的安装路径 tmpfs в /var 加载时,它将允许应用程序在那里写笔记(乱写乱画)。 下次打开更改时 /var 会迷路。 覆盖安装在之间创建联合 tmpfs 和底层文件系统,并允许您对现有文件进行表面上的更改 ro-tootf 而可绑定的安装座可以使新的安装座变空 tmpfs 文件夹可见可写 ro-rootfs 方法。 尽管 overlayfs 这是正确的(proper) 文件系统类型,可绑定挂载实现于 VFS命名空间.

根据对覆盖层和可连接安装座的描述,没有人对此感到惊讶 Linux容器 它们被积极使用。 让我们看看当我们使用时会发生什么 systemd-nspawn 使用该工具运行容器 mountsnoopbcc.

通话 system-nspawn 运行时启动容器 mountsnoop.py.

让我们来看看发生了什么:

发射 mountsnoop 当容器正在“启动”时,表明容器的运行时高度依赖于正在链接的挂载(仅显示长输出的开头)。

这是 systemd-nspawn 提供选定的文件 procfs и sysfs 主机到容器作为其路径 rootfs... 除了 MS_BIND 设置绑定挂载的标志,挂载上的其他一些标志定义主机和容器名称空间更改之间的关系。 例如,链接安装可以跳过对 /proc и /sys 放入容器中,或根据调用隐藏它们。

结论

了解 Linux 的内部工作原理似乎是一项不可能完成的任务,因为内核本身包含大量代码,不考虑 Linux 用户空间应用程序和 C 库中的系统调用接口,例如 glibc。 取得进展的一种方法是阅读一个内核子系统的源代码,重点是理解系统调用和用户空间标头,以及主要的内部内核接口,例如表 file_operations。 文件操作提供了“一切都是文件”的原则,使管理起来特别愉快。 顶层目录中的C内核源文件 fs/ 提出了虚拟文件系统的实现,它是一个包装层,在流行的文件系统和存储设备之间提供广泛且相对简单的兼容性。 通过 Linux 命名空间进行链接和覆盖安装是 VFS 的魔力,它使创建只读容器和根文件系统成为可能。 结合源码考察,eBPF核心工具及其接口 bcc
让岩心勘探变得比以往更容易。

朋友们,请留言,这篇文章对您有用吗? 也许您有什么意见或评论? 欢迎对 Linux 管理员课程感兴趣的人参加 开放日,将于 18 月 XNUMX 日举行。

第一部分。

来源: habr.com

添加评论