linux initrd和initramfs有什么区别?

72qzrwbm  于 2023-04-20  发布在  Linux
关注(0)|答案(4)|浏览(161)

据我所知,initrd作为一个块设备,因此需要一个文件系统驱动程序(如ext2)。内核必须至少有一个内置模块来检测initrd的文件系统。在这篇文章中,Introducing initramfs, a new model for initial RAM disks写道:
但是ramdisk实际上由于缓存而浪费了更多的内存。Linux被设计为缓存从块设备读取或写入的所有文件和目录条目,因此Linux将数据复制到ramdisk和从ramdisk复制到“页面缓存”(用于文件数据)和“dentry缓存”(用于目录条目)。ramdisk伪装成块设备的缺点是它被当作块设备对待。
什么是page cachedentry cache?在段落中,这是否意味着数据被复制,因为ramdisk被视为块设备,因此所有数据都被缓存?
相比之下,ramfs
几年前,Linus Torvalds有一个绝妙的想法:如果Linux的缓存可以像文件系统一样挂载会怎么样?只要将文件保存在缓存中,直到它们被删除或系统重新引导时才删除它们?Linus编写了一个名为“ramfs”的小型缓存 Package 器,其他内核开发人员创建了一个名为“tmpfs”的改进版本(它可以将数据写入交换空间,并限制给定挂载点的大小,以便在消耗所有可用内存之前将其填满)。Initramfs是tmpfs的示例。
这些基于ram的文件系统会自动增长或收缩,以适应它们所包含的数据的大小。(或扩展现有文件)会自动分配更多内存,删除或截断文件会释放这些内存,块设备和缓存之间不会有重复,因为没有块设备,该高速缓存中的副本是数据的唯一副本,最棒的是这不是新代码,而是现有Linux缓存代码的新应用程序,这意味着它几乎没有增加大小,非常简单,并且基于经过良好测试的基础架构。
总之,ramfs只是打开文件并加载到内存中,不是吗?
initrdramfs都是在编译时压缩的,但不同的是,initrd是一个块设备,在引导时被内核解压,而ramfs是通过cpio解压到内存中的。我是对的吗?或者ramfs是一个非常小的文件系统?
最后,直到今天,initrd镜像仍然存在于最新的内核中。然而,initrd实际上是今天使用的ramfs吗?这个名字只是为了历史目的?

e0uiprwp

e0uiprwp1#

我认为你都是对的。
如果您遵循引导时所需的步骤,则很容易看出差异:

initrd

  • 创建一个ramdev块设备。它是一个基于ram的块设备,即使用内存而不是物理磁盘的模拟硬盘。
  • initrd文件被读取并解压缩到设备中,就像您执行zcat initrd | dd of=/dev/ram0或类似操作一样。
  • initrd包含一个文件系统的镜像,所以现在可以像往常一样挂载文件系统:文件系统自然需要一个驱动程序,所以如果使用ext 2,那么ext 2驱动程序必须在内核中编译。
  • 成交!

initramfs

  • 安装了tmpfsmount -t tmpfs nodev /root。tmpfs不需要驱动,它总是在内核中。不需要设备,不需要额外的驱动。
  • initramfs被直接解压缩到这个新文件系统中:zcat initramfs | cpio -i或类似。
  • 成交!

是的,它在许多地方仍然被称为initrd,尽管它是一个initramfs,特别是在 Boot 加载程序中,因为对他们来说它只是一个BLOB。

htrmnn0y

htrmnn0y2#

Dentry(和inode)缓存

Linux中的文件系统子系统有三层。VFS(虚拟文件系统)实现系统调用接口,处理跨挂载点和默认权限和限制检查。下面是单个文件系统的驱动程序,以及与块设备(磁盘、存储卡等)驱动程序接口的驱动程序;网络接口是例外)。
VFS和文件系统之间的接口有几个类(它是普通的C语言,所以结构包含指向函数的指针等,但它在概念上是面向对象的接口)。dentry,描述目录中的条目; file,描述进程打开的文件。当挂载时,文件系统驱动程序为它的根创建inodedentry,当进程想要访问一个文件并最终过期时,根据需要创建其他的。这是一个dentry和inode缓存。
是的,这确实意味着对于每个打开的文件和任何目录,都必须在内核内存中分配inodedentry结构来表示它。

页面缓存

在Linux中,包含用户区数据的每个内存页都由统一的page结构表示。(如果可用,可以交换到交换空间)或将其与某个文件系统上的inode关联(可能被写回到文件系统并从文件系统重新读取)并且它可以是任何数量的存储器Map的一部分,即在某个进程的地址空间中可见。当前加载到内存中的所有页面的总和就是页面缓存。
页面用于实现mmap接口,而常规的读写系统调用可以由文件系统通过其他方式实现,大多数接口使用也使用页面的通用函数。有一些通用函数,当请求文件读取时,分配页面并调用文件系统逐个填充它们。对于基于块设备的文件系统,它仅计算适当的地址并将该填充委托给块设备驱动器。

ramdev(ramdisk)

Ramdev是一个常规的块设备。它允许在它上面分层任何文件系统,但它受到块设备接口的限制。它只有填充调用者分配的页面并将其写回的方法。这正是真实的的块设备所需要的,如磁盘,存储卡,USB大容量存储器等,但对于ramdisk来说,这意味着数据在内存中存在两次,一次在RAMDEV的存储器中,一次在由调用者分配的存储器中。
这是实现initrd的旧方法,从initrd很少见的时候开始。

tmpfs

Tmpfs则不同,它是一个虚拟文件系统,它为VFS提供的方法是使其工作的绝对最低限度(因此,它是关于inode、dentry和file方法应该做什么的优秀文档)。只有在inode缓存中有相应的inode和dentry时,文件才存在。在文件创建时创建,除非文件被删除,否则永远不会过期。当写入数据时,页面与文件相关联,否则表现为匿名页面(数据可以存储到交换区,只要文件存在,page结构就一直在使用)。
这意味着内存中没有额外的数据副本,整个事情变得简单得多,并且由于这一点,速度也稍微快一些。它只是使用数据结构,作为任何其他文件系统的缓存,作为它的主存储。
这是实现initrdinitramfs,但图像仍称为initrd)的新方法。
这也是实现“posix共享内存”的方法(这简单地意味着tmpfs安装在/dev/shm上,应用程序可以自由地在那里创建文件并Map它们;简单高效),最近甚至/tmp/run(或/var/run)也经常安装tmpf,特别是在笔记本电脑上,以防止磁盘旋转或避免SSD的一些磨损。

ymzxtsji

ymzxtsji3#

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

在这个答案中,我将:

  • 提供一个最小的可运行的Buildroot + QEMU示例供您测试
  • 解释两者之间最根本的区别,为非常初学者谁可能是谷歌这一点

希望这些将作为验证和理解差异的更多内部细节的基础。
最小的设置在这里是完全自动化的,这是相应的入门。
安装程序在运行时打印出QEMU命令,正如该repo中所解释的那样,我们可以轻松地生成以下三种工作类型的引导:
1.根文件系统位于ext 2“硬盘”中:

qemu-system-x86_64 -kernel normal/bzImage -drive file=rootfs.ext2

1.根文件系统位于initrd中:

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

-drive未给出。
rootfs.cpio包含与rootfs.ext2相同的文件,除了它们是CPIO,这与.tar类似:它序列化目录而不压缩它们。
1.根文件系统在initramfs中:

qemu-system-x86_64 -kernel with_initramfs/bzImage

没有给出-drive-initrd
with_initramfs/bzImage是使用与normal/bzImage相同的选项编译的内核,除了一个:CONFIG_INITRAMFS_SOURCE=rootfs.cpio指向与-initrd示例中完全相同的CPIO。
通过比较设置,我们可以得出每个设置的最基本属性:
1.在硬盘设置中,QEMU将bzImage加载到内存中。
这项工作通常是由引导加载程序/固件在真实的硬件,如GRUB。
Linux内核引导,然后使用其驱动程序从磁盘读取根文件系统。

这一次,内核直接使用内存中的rootfs.cpio,因为没有硬盘。
写操作在重新引导时并不持久,因为所有内容都在内存中

  • 在initramfs设置中,我们构建内核的方式有点不同:我们还将rootfs.cpio提供给内核构建系统。

然后内核构建系统就知道如何将内核映像和CPIO结合到一个映像中。
因此,我们需要做的就是将bzImage传递给QEMU。QEMU将其加载到image中,就像它对其他设置所做的那样,但不需要其他任何东西:CPIO也会被加载到内存中,因为它被粘到了内核映像上!

f3temu5u

f3temu5u4#

添加initrdinitramfs之间的另一个值得注意的区别,这在上面的优秀答案中没有提到。

  • 对于initrd,内核默认情况下会在/sbin/init处移交给用户空间pid 1
  • 然而,较新的initramfs改变了这些东西,并在/init上执行pid 1

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

相关问题