据我所知,initrd
作为一个块设备,因此需要一个文件系统驱动程序(如ext2
)。内核必须至少有一个内置模块来检测initrd
的文件系统。在这篇文章中,Introducing initramfs, a new model for initial RAM disks写道:
但是ramdisk实际上由于缓存而浪费了更多的内存。Linux被设计为缓存从块设备读取或写入的所有文件和目录条目,因此Linux将数据复制到ramdisk和从ramdisk复制到“页面缓存”(用于文件数据)和“dentry缓存”(用于目录条目)。ramdisk伪装成块设备的缺点是它被当作块设备对待。
什么是page cache
和dentry cache
?在段落中,这是否意味着数据被复制,因为ramdisk
被视为块设备,因此所有数据都被缓存?
相比之下,ramfs
:
几年前,Linus Torvalds有一个绝妙的想法:如果Linux的缓存可以像文件系统一样挂载会怎么样?只要将文件保存在缓存中,直到它们被删除或系统重新引导时才删除它们?Linus编写了一个名为“ramfs”的小型缓存 Package 器,其他内核开发人员创建了一个名为“tmpfs”的改进版本(它可以将数据写入交换空间,并限制给定挂载点的大小,以便在消耗所有可用内存之前将其填满)。Initramfs是tmpfs的示例。
这些基于ram的文件系统会自动增长或收缩,以适应它们所包含的数据的大小。(或扩展现有文件)会自动分配更多内存,删除或截断文件会释放这些内存,块设备和缓存之间不会有重复,因为没有块设备,该高速缓存中的副本是数据的唯一副本,最棒的是这不是新代码,而是现有Linux缓存代码的新应用程序,这意味着它几乎没有增加大小,非常简单,并且基于经过良好测试的基础架构。
总之,ramfs
只是打开文件并加载到内存中,不是吗?initrd
和ramfs
都是在编译时压缩的,但不同的是,initrd
是一个块设备,在引导时被内核解压,而ramfs
是通过cpio解压到内存中的。我是对的吗?或者ramfs
是一个非常小的文件系统?
最后,直到今天,initrd
镜像仍然存在于最新的内核中。然而,initrd
实际上是今天使用的ramfs
吗?这个名字只是为了历史目的?
4条答案
按热度按时间e0uiprwp1#
我认为你都是对的。
如果您遵循引导时所需的步骤,则很容易看出差异:
initrd
ramdev
块设备。它是一个基于ram的块设备,即使用内存而不是物理磁盘的模拟硬盘。initrd
文件被读取并解压缩到设备中,就像您执行zcat initrd | dd of=/dev/ram0
或类似操作一样。initrd
包含一个文件系统的镜像,所以现在可以像往常一样挂载文件系统:文件系统自然需要一个驱动程序,所以如果使用ext 2,那么ext 2驱动程序必须在内核中编译。initramfs
tmpfs
:mount -t tmpfs nodev /root
。tmpfs不需要驱动,它总是在内核中。不需要设备,不需要额外的驱动。initramfs
被直接解压缩到这个新文件系统中:zcat initramfs | cpio -i
或类似。是的,它在许多地方仍然被称为
initrd
,尽管它是一个initramfs
,特别是在 Boot 加载程序中,因为对他们来说它只是一个BLOB。htrmnn0y2#
Dentry(和inode)缓存
Linux中的文件系统子系统有三层。VFS(虚拟文件系统)实现系统调用接口,处理跨挂载点和默认权限和限制检查。下面是单个文件系统的驱动程序,以及与块设备(磁盘、存储卡等)驱动程序接口的驱动程序;网络接口是例外)。
VFS和文件系统之间的接口有几个类(它是普通的C语言,所以结构包含指向函数的指针等,但它在概念上是面向对象的接口)。
dentry
,描述目录中的条目;file
,描述进程打开的文件。当挂载时,文件系统驱动程序为它的根创建inode
和dentry
,当进程想要访问一个文件并最终过期时,根据需要创建其他的。这是一个dentry和inode缓存。是的,这确实意味着对于每个打开的文件和任何目录,都必须在内核内存中分配
inode
和dentry
结构来表示它。页面缓存
在Linux中,包含用户区数据的每个内存页都由统一的
page
结构表示。(如果可用,可以交换到交换空间)或将其与某个文件系统上的inode
关联(可能被写回到文件系统并从文件系统重新读取)并且它可以是任何数量的存储器Map的一部分,即在某个进程的地址空间中可见。当前加载到内存中的所有页面的总和就是页面缓存。页面用于实现mmap接口,而常规的读写系统调用可以由文件系统通过其他方式实现,大多数接口使用也使用页面的通用函数。有一些通用函数,当请求文件读取时,分配页面并调用文件系统逐个填充它们。对于基于块设备的文件系统,它仅计算适当的地址并将该填充委托给块设备驱动器。
ramdev(ramdisk)
Ramdev是一个常规的块设备。它允许在它上面分层任何文件系统,但它受到块设备接口的限制。它只有填充调用者分配的页面并将其写回的方法。这正是真实的的块设备所需要的,如磁盘,存储卡,USB大容量存储器等,但对于ramdisk来说,这意味着数据在内存中存在两次,一次在RAMDEV的存储器中,一次在由调用者分配的存储器中。
这是实现
initrd
的旧方法,从initrd很少见的时候开始。tmpfs
Tmpfs则不同,它是一个虚拟文件系统,它为VFS提供的方法是使其工作的绝对最低限度(因此,它是关于inode、dentry和file方法应该做什么的优秀文档)。只有在inode缓存中有相应的inode和dentry时,文件才存在。在文件创建时创建,除非文件被删除,否则永远不会过期。当写入数据时,页面与文件相关联,否则表现为匿名页面(数据可以存储到交换区,只要文件存在,
page
结构就一直在使用)。这意味着内存中没有额外的数据副本,整个事情变得简单得多,并且由于这一点,速度也稍微快一些。它只是使用数据结构,作为任何其他文件系统的缓存,作为它的主存储。
这是实现
initrd
(initramfs
,但图像仍称为initrd
)的新方法。这也是实现“posix共享内存”的方法(这简单地意味着tmpfs安装在
/dev/shm
上,应用程序可以自由地在那里创建文件并Map它们;简单高效),最近甚至/tmp
和/run
(或/var/run
)也经常安装tmpf,特别是在笔记本电脑上,以防止磁盘旋转或避免SSD的一些磨损。ymzxtsji3#
最小可运行QEMU示例和新手解释
在这个答案中,我将:
希望这些将作为验证和理解差异的更多内部细节的基础。
最小的设置在这里是完全自动化的,这是相应的入门。
安装程序在运行时打印出QEMU命令,正如该repo中所解释的那样,我们可以轻松地生成以下三种工作类型的引导:
1.根文件系统位于ext 2“硬盘”中:
1.根文件系统位于initrd中:
-drive
未给出。rootfs.cpio
包含与rootfs.ext2
相同的文件,除了它们是CPIO,这与.tar
类似:它序列化目录而不压缩它们。1.根文件系统在initramfs中:
没有给出
-drive
和-initrd
。with_initramfs/bzImage
是使用与normal/bzImage
相同的选项编译的内核,除了一个:CONFIG_INITRAMFS_SOURCE=rootfs.cpio
指向与-initrd
示例中完全相同的CPIO。通过比较设置,我们可以得出每个设置的最基本属性:
1.在硬盘设置中,QEMU将bzImage加载到内存中。
这项工作通常是由引导加载程序/固件在真实的硬件,如GRUB。
Linux内核引导,然后使用其驱动程序从磁盘读取根文件系统。
rootfs.cpio
加载到内存中这一次,内核直接使用内存中的
rootfs.cpio
,因为没有硬盘。写操作在重新引导时并不持久,因为所有内容都在内存中
rootfs.cpio
提供给内核构建系统。然后内核构建系统就知道如何将内核映像和CPIO结合到一个映像中。
因此,我们需要做的就是将bzImage传递给QEMU。QEMU将其加载到image中,就像它对其他设置所做的那样,但不需要其他任何东西:CPIO也会被加载到内存中,因为它被粘到了内核映像上!
f3temu5u4#
添加
initrd
和initramfs
之间的另一个值得注意的区别,这在上面的优秀答案中没有提到。initrd
,内核默认情况下会在/sbin/init
处移交给用户空间pid 1
/init
上执行pid 1
因为它可能成为一个陷阱(参见https://unix.stackexchange.com/a/147688/24394)