initrd和initramfs之间的区别?

Amu*_*umu 56 linux filesystems boot kernel

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

但是由于缓存,ramdisks实际上浪费了更多的内存.Linux旨在缓存从块设备读取或写入的所有文件和目录条目,因此Linux将数据复制到ramdisk和从"ramdisk"复制到"页面缓存"(用于文件数据)和"dentry cache"(用于目录条目) .假装是块设备的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今天使用的,这个名字只是出于历史目的吗?

rod*_*igo 59

我认为你是对的.

如果您按照启动时所需的步骤操作,则很容易看出差异:

initrd

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

initramfs

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

是的,它仍然initrd在许多地方被调用,虽然它是一个initramfs,特别是在启动加载器中,因为它们只是一个BLOB.操作系统启动时会产生差异.

  • @Adrian:对 mount 的调用需要两个参数,“设备”和“挂载点”,通常您用“-t <type>”指定挂载类型。但是`tmpfs`挂载没有设备,因为它们使数据脱离RAM内存。因此,“tmpfs”的挂载“mount”的“device”参数是必需的,但不使用,并且可以是您想要的任何文本,但作为约定,它通常是“nodev”。 (4认同)

Jan*_*dec 47

Dentry(和inode)缓存

Linux中的文件系统子系统有三层.VFS(虚拟文件系统),它实现系统调用接口并处理交叉挂载点以及默认权限和限制检查.下面是各个文件系统的驱动程序,而这些驱动程序又与块设备的驱动程序接口(磁盘,存储卡等;网络接口是例外).

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

是的,它意味着对于每个打开的文件,并到根目录下的任何必须有inodedentry结构分配的内核内存代表它.

页面缓存

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

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

ramdev(ramdisk)

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

这是旧的实施方式initrd.从initrd罕见和充满异国情调的时候开始.

TMPFS

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

这意味着内存中没有额外的数据副本,整个过程更加简单,并且由于速度稍快.它只是使用数据结构,作为任何其他文件系统的缓存,因为它是主存储.

这是实现的新方法initrd(initramfs但仍然只调用图像initrd).

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

  • @Amumu - `initrd` 是一个块设备,简单地说,块设备被缓存。`initramfs` 不是文件系统映像,它只是一个压缩的 _cpio_ 文件;它被解压缩到 `tmpfs` 中,就像解压缩 _zip_ 文件一样。 (2认同)
  • @Amumu:说 `initramfs` 立即被缓存表明有两个副本。但恰恰相反。它存储在缓存中,(ab)将其用作数据的主存储,因此引导加载程序加载的原始压缩副本可能会立即丢弃。 (2认同)
  • @PiotrDobrogost:与任何正常的高速缓存一样,与后备存储相比,页面高速缓存仅丢弃未修改的内容。由于没有用于tmpfs的后备存储,因此它无法丢弃页面(如果存在交换,则可以将swap用作没有自己的页面的临时存储)。 (2认同)

Cir*_*四事件 11

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

在这个答案中,我将:

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

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

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

安装程序会在运行时打印出 QEMU 命令,正如该存储库中所解释的,我们可以轻松生成以下三种工作类型的启动:

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

    qemu-system-x86_64 -kernel normal/bzImage -drive file=rootfs.ext2
    
    Run Code Online (Sandbox Code Playgroud)
  2. 根文件系统位于 initrd 中:

    qemu-system-x86_64 -kernel normal/bzImage -initrd rootfs.cpio
    
    Run Code Online (Sandbox Code Playgroud)

    -drive没有给出。

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

  3. 根文件系统位于 initramfs 中:

    qemu-system-x86_64 -kernel with_initramfs/bzImage
    
    Run Code Online (Sandbox Code Playgroud)

    既没有-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 也会加载到内存中,因为它粘附到内核映像!


hum*_*ace 5

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

  • 内核initrd默认移交给用户pid 1空间/sbin/init
  • 然而,较新的 initramfs 改变了一切并pid 1/init

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