80

据我所知,initrd它充当块设备,因此需要文件系统驱动程序(例如ext2)。内核必须至少有一个内置模块来检测initrd. 在这篇文章introducing initramfs,一种用于初始 RAM 磁盘的新模型中,它写道:

但是由于缓存,ramdisk 实际上浪费了更多的内存。Linux 旨在缓存从块设备读取或写入的所有文件和目录条目,因此 Linux 将数据从 ramdisk 复制到“页面缓存”(用于文件数据)和“dentry 缓存”(用于目录条目) . 伪装成块设备的 ramdisk 的缺点是它被视为块设备。

什么是page cachedentry cache?在段落中,这是否意味着数据被重复,因为ramdisk被视为块设备,因此所有数据都被缓存了?

相反,ramfs

几年前,Linus Torvalds 有一个绝妙的想法:如果 Linux 的缓存可以像文件系统一样挂载会怎样?只是将文件保存在缓存中,直到它们被删除或系统重新启动之前永远不会摆脱它们?Linus 为缓存编写了一个名为“ramfs”的小型包装器,其他内核开发人员创建了一个名为“tmpfs”的改进版本(它可以将数据写入交换空间,并限制给定挂载点的大小,以便在使用之前填满)所有可用内存)。Initramfs 是 tmpfs 的一个实例。

这些基于 ram 的文件系统会自动增长或缩小以适应它们包含的数据的大小。将文件添加到 ramfs(或扩展现有文件)会自动分配更多内存,删除或截断文件会释放该内存。块设备和缓存之间没有重复,因为没有块设备。缓存中的副本是数据的唯一副本。最重要的是,这不是新代码,而是现有 Linux 缓存代码的新应用程序,这意味着它几乎不增加任何大小,非常简单,并且基于经过严格测试的基础架构。

总之,ramfs只是文件打开并加载到内存中,不是吗?

两者initrdramfs都是在编译时压缩的,但不同的是,initrd块设备解压缩后由内核在启动时挂载,而ramfs通过 cpio 解压缩到内存中。我对么?或者是ramfs一个非常小的文件系统?

最后,直到今天,该initrd图像仍以最新内核呈现。但是,这initrd实际上是ramfs今天使用的名称,并且只是出于历史目的吗?

4

4 回答 4

79

我认为你是对的。

如果您在启动时遵循所需的步骤,则很容易看出差异:

initrd

  • 创建一个ramdev块设备。它是基于 ram 的块设备,即使用内存而不是物理磁盘的模拟硬盘。
  • initrd文件被读取并解压缩到设备中,就像您这样做zcat initrd | dd of=/dev/ram0或类似的东西一样。
  • 包含文件系统的initrd映像,因此现在您可以照常挂载文件系统:mount /dev/ram0 /root. 自然,文件系统需要驱动程序,所以如果您使用 ext2,则必须在内核中编译 ext2 驱动程序。
  • 完毕!

initramfs

  • Atmpfs已安装:mount -t tmpfs nodev /root. tmpfs 不需要驱动程序,它总是在内核上。无需设备,无需额外的驱动程序。
  • initramfs直接解压缩到这个新的文件系统中:,zcat initramfs | cpio -i或类似的。
  • 完毕!

是的,它在很多地方仍然被调用initrd,尽管它是一个initramfs,特别是在引导加载程序中,因为它只是一个 BLOB。操作系统启动时会产生差异。

于 2012-05-15T15:27:32.507 回答
56

Dentry(和 inode)缓存

Linux 中的文件系统子系统具有三层。VFS(虚拟文件系统),它实现系统调用接口并处理跨挂载点以及默认权限和限制检查。下面是单个文件系统的驱动程序,以及与块设备(磁盘、内存卡等;网络接口除外)驱动程序的接口。

VFS 和文件系统之间的接口是几个类(它是普通的 C,所以结构包含指向函数等的指针,但它在概念上是面向对象的接口)。主要的三个类是inode,描述文件系统中的任何对象(文件或目录),dentry描述目录中的条目file,以及描述进程打开的文件。挂载后,文件系统驱动程序会创建它的根,inodedentry其他驱动程序是在进程想要访问文件并最终过期时按需创建的。那是一个 dentry 和 inode 缓存。

是的,这确实意味着对于每个打开的文件和任何目录到根目录,都必须在内核内存中分配代表它的结构inodedentry

页面缓存

在 Linux 中,每个包含用户空间数据的内存页面都由统一的page结构表示。这可能会将页面标记为匿名(如果可用,可能会交换到交换空间)或将其与inode某个文件系统相关联(可能会被写回文件系统并从文件系统重新读取),并且它可以是任意数量的内存映射的一部分,即在某个进程的地址空间中可见。当前加载到内存中的所有页面的总和就是页面缓存。

页面用于实现 mmap 接口,而文件系统可以通过其他方式实现常规读写系统调用,但大多数接口使用也使用页面的通用函数。有一些通用函数,当请求读取文件时,分配页面并调用文件系统来逐一填充它们。对于基于块设备的文件系统,它只计算适当的地址并将此填充委托给块设备驱动程序。

ramdev(虚拟磁盘)

Ramdev 是常规块设备。这允许在其上分层任何文件系统,但它受到块设备接口的限制。这只是填充调用者分配的页面并将其写回的方法。这正是真正的块设备(如磁盘、存储卡、USB 大容量存储等)所需要的,但对于 ramdisk 这意味着数据在内存中存在两次,一次在 ramdev 的内存中,一次在由呼叫者。

这是旧的实现方式initrd。从 initrd 很少见和异国情调的时代开始。

tmpfs

Tmpfs 是不同的。这是一个虚拟文件系统。它提供给 VFS 的方法是使其工作的绝对最低限度(因此它是关于 inode、dentry 和 file 方法应该做什么的优秀文档)。文件只有在 inode 缓存中存在对应的 inode 和 dentry 时才存在,在文件创建时创建并且永不过期,除非文件被删除。当数据被写入时,页面与文件相关联,否则表现为匿名页面(数据可以存储为交换,page只要文件存在,结构就会保持使用状态)。

这意味着内存中没有额外的数据副本,整个事情要简单得多,而且速度也更快。它只是使用数据结构,作为任何其他文件系统的缓存,因为它是主存储。

这是实现initrd(的新方法initramfs,但图像仍称为 just initrd)。

这也是实现“posix共享内存”的方式(这仅仅意味着安装了tmpfs/dev/shm并且应用程序可以自由地在那里创建文件并映射它们;简单而高效)最近甚至/tmp/run(或/var/run)经常安装tmpfs,特别是在笔记本上以防止磁盘在 SSD 的情况下必须旋转或避免一些磨损。

于 2012-05-15T16:05:39.280 回答
6

最小可运行 QEMU 示例和新手解释

在这个答案中,我将:

  • 提供一个最小的可运行 Buildroot + QEMU 示例供您测试
  • 为可能在谷歌上搜索的初学者解释两者之间最基本的区别

希望这些将作为验证和理解差异的更多内部细节的基础。

此处的最小设置是完全自动化的,这就是相应的入门

安装程序会在运行 QEMU 命令时打印出它们,并且如该 repo 中所述,我们可以轻松生成以下三种工作类型的引导:

  1. 根文件系统位于 ext2“硬盘”中:

    qemu-system-x86_64 -kernel normal/bzImage -drive file=rootfs.ext2
    
  2. 根文件系统在 initrd 中:

    qemu-system-x86_64 -kernel normal/bzImage -initrd rootfs.cpio
    

    -drive没有给出。

    rootfs.cpio包含与 相同的文件rootfs.ext2,除了它们是CPIO格式,类似于.tar:它序列化目录而不压缩它们。

  3. 根文件系统在 initramfs 中:

    qemu-system-x86_64 -kernel with_initramfs/bzImage
    

    既没有-drive也没有-initrd给出。

    with_initramfs/bzImage是使用与 相同的选项编译的内核normal/bzImage,除了一个:CONFIG_INITRAMFS_SOURCE=rootfs.cpio指向与示例中完全相同的 CPIO -initrd

通过比较设置,我们可以得出每个设置的最基本属性:

  1. 在硬盘设置中,QEMU 将 bzImage 加载到内存中。

    这项工作通常由引导加载程序/固件在GRUB 等真实硬件中完成。

    Linux 内核启动,然后使用其驱动程序从磁盘读取根文件系统。

  2. 在 initrd 设置中,除了将内核加载到内存中之外,QEMU 还进行了一些引导加载程序工作:它还:

    这一次,内核直接使用rootfs.cpio内存,因为不存在硬盘。

    重新启动后写入不会持久,因为所有内容都在内存中

  3. 在 initramfs 设置中,我们构建内核有点不同:我们也将 提供给rootfs.cpio内核构建系统。

    内核构建系统然后知道如何将内核映像和 CPIO 粘贴到单个映像中。

    因此,我们需要做的就是将 bzImage 传递给 QEMU。QEMU 将其加载到映像中,就像它为其他设置所做的那样,但没有其他要求:CPIO 也被加载到内存中,因为它被粘在内核映像上!

于 2019-01-22T10:32:25.450 回答
3

在上面的优秀答案中添加另一个值得注意的区别initrdinitramfs未提及的区别。

  • 默认情况下,内核会initrd移交给用户空间pid 1/sbin/init
  • 然而,较新的 initramfs 会改变并pid 1执行/init

因为它可能成为一个陷阱(请参阅https://unix.stackexchange.com/a/147688/24394

于 2019-01-31T12:10:19.757 回答