Ramfs, rootfs and initramfs — The Linux Kernel documentationhttps://www.kernel.org/doc/html/latest/filesystems/ramfs-rootfs-initramfs.html?highlight=initramfs

什么是 ramfs?

Ramfs 是一个非常简单的文件系统,它将 Linux 的磁盘缓存机制(页面缓存和 dentry 缓存)导出为一个可动态调整大小的基于 RAM 的文件系统。

通常所有文件都被 Linux 缓存在内存中。从后备存储(通常是挂载文件系统的块设备)读取的数据页会被保留,以防再次需要它,但标记为干净(可释放)以防虚拟内存系统需要内存用于其他用途。类似地,写入文件的数据在写入后备存储后立即标记为干净,但保留用于缓存目的,直到 VM 重新分配内存。类似的机制(dentry 缓存)大大加快了对目录的访问速度。

使用 ramfs,没有后备存储。写入 ramfs 的文件像往常一样分配 dentry 和页面缓存,但无处可写。这意味着页面永远不会被标记为干净的,因此当 VM 寻求回收内存时,它们不能被释放。

实现 ramfs 所需的代码量很少,因为所有工作都由现有的 Linux 缓存基础设施完成。基本上,您将磁盘缓存安装为文件系统。因此,ramfs 不是可通过 menuconfig 移除的可选组件,因为节省的空间可以忽略不计。

ramfs 和 ramdisk:

较旧的“ram 磁盘”机制从 RAM 区域创建了一个合成块设备,并将其用作文件系统的后备存储。这个块设备是固定大小的,所以安装在它上面的文件系统是固定大小的。使用 ram 磁盘还需要将内存从伪造的块设备不必要地复制到页面缓存中(并将更改复制回来),以及创建和销毁 dentry。此外,它需要一个文件系统驱动程序(例如 ext2)来格式化和解释这些数据。

与 ramfs 相比,这会浪费内存(和内存总线带宽),为 CPU 创造不必要的工作,并污染 CPU 缓存。(有一些技巧可以通过使用页表来避免这种复制,但它们非常复杂,而且无论如何都与复制一样昂贵。)更重要的是,ramfs 所做的所有工作都必须_无论如何_ ,因为所有文件访问都通过页面和 dentry 缓存。RAM 磁盘根本没有必要;ramfs 在内部要简单得多。

ramdisks 半过时的另一个原因是环回设备的引入提供了一种更灵活和方便的方式来创建合成块设备,现在从文件而不是从内存块。有关详细信息,请参阅 Lostup (8)。

ramfs 和 tmpfs:

ramfs 的一个缺点是您可以继续向其中写入数据,直到填满所有内存,并且 VM 无法释放它,因为 VM 认为文件应该写入后备存储(而不是交换空间),但 ramfs 没有没有任何后备商店。因此,应该只允许 root(或受信任的用户)对 ramfs 挂载进行写访问。

创建了一个名为 tmpfs 的 ramfs 衍生物,以增加大小限制以及将数据写入交换空间的能力。可以允许普通用户对 tmpfs 挂载进行写访问。有关更多信息,请参阅Tmpfs。

什么是rootfs?

Rootfs 是 ramfs(或 tmpfs,如果已启用)的一个特殊实例,它始终存在于 2.6 系统中。您无法卸载 rootfs 的原因与您无法终止 init 进程的原因大致相同;与使用特殊代码来检查和处理空列表相比,内核确保某些列表不会变空更小更简单。

大多数系统只是在 rootfs 上挂载另一个文件系统并忽略它。一个空的 ramfs 实例占用的空间很小。

如果启用了 CONFIG_TMPFS,rootfs 将默认使用 tmpfs 而不是 ramfs。要强制使用 ramfs,请在内核命令行中添加“rootfstype=ramfs”。

什么是initramfs?

所有 2.6 Linux 内核都包含一个 gzip 压缩的“cpio”格式存档,当内核启动时,它会被提取到 rootfs 中。解压后,内核检查 rootfs 是否包含文件“init”,如果是,则以 PID 1 执行它。 如果找到,则此 init 进程负责使系统运行其余部分,包括定位和挂载真正的根设备(如果有的话)。如果在嵌入的 cpio 归档文件被提取到 rootfs 之后,它不包含一个 init 程序,内核将使用旧代码来定位和挂载一个根分区,然后执行 /sbin/init 的一些变体。

所有这些在几个方面与旧的 initrd 不同:

  • 旧的 initrd 始终是一个单独的文件,而initramfs存档链接到 linux 内核映像。(该目录linux-*/usr专门用于在构建期间生成此存档。)

  • 旧的 initrd 文件是一个 gzipped 文件系统映像(某些文件格式,例如 ext2,需要内核内置驱动程序),而新的 initramfs存档是 gzipped cpio 存档(就像 tar 只是更简单,请参阅 cpio(1)和initramfs 缓冲区格式)。内核的cpio提取代码不仅极小,而且还有__init文本和在引导过程中可以丢弃的数据。

  • 由旧的 initrd(称为 /initrd,而不是 /init)运行的程序做了一些设置然后返回到内核,而来自initramfs的 init 程序 预计不会返回到内核。(如果 /init 需要移交控制权,它可以使用新的根设备过载 / 并执行另一个 init 程序。请参阅下面的 switch_root 实用程序。)

  • 当切换另一个根设备时,initrd 将 pivot_root 然后卸载 ramdisk。但是initramfs是 rootfs:您既不能 pivot_root rootfs,也不能卸载它。而是删除 rootfs 中的所有内容以释放空间(find -xdev / -exec rm '{}' ';'),使用新根目录(cd /newmount; mount –move . /; chroot .)重载 rootfs,附加stdin/stdout/stderr 到新的 /dev/console,然后执行新的 init。

    由于这是一个非常挑剔的过程(并且涉及在您可以运行之前删除命令),因此 klibc 包引入了一个帮助程序 (utils/run_init.c) 来为您完成所有这些工作。大多数其他软件包(例如busybox)将此命令命名为“switch_root”。

填充initramfs的:

2.6 内核构建过程总是创建一个 gzipped cpio 格式的initramfs 存档并将其链接到生成的内核二进制文件中。默认情况下,此存档为空(在 x86 上消耗 134 字节)。

配置选项 CONFIG_ INITRAMFS _SOURCE(在 menuconfig 的 General Setup 中,位于 usr/Kconfig 中)可用于指定 initramfs 存档的源,它将自动合并到生成的二进制文件中。此选项可以指向现有的 gzip cpio 存档、包含要存档的文件的目录或文本文件规范,例如以下示例:

dir /dev 755 0 0
nod /dev/console 644 0 0 c 5 1
nod /dev/loop0 644 0 0 b 7 0
dir /bin 755 1000 1000
slink /bin/sh busybox 777 0 0
file /bin/busybox initramfs/busybox 755 0 0
dir /proc 755 0 0
dir /sys 755 0 0
dir /mnt 755 0 0
file /init initramfs/init.sh 755 0 0

运行“usr/gen_init_cpio”(在内核构建之后)以获取记录上述文件格式的使用消息。

配置文件的优点之一是无需 root 访问权限即可在新存档中设置权限或创建设备节点。(请注意,这两个示例“文件”条目期望在 linux-2.6.* 目录下名为“ initramfs ”的目录中找到名为“init.sh”和“busybox”的文件。有关更多详细信息,请参阅 早期用户空间支持。)

内核不依赖于外部 cpio 工具。如果指定目录中的配置文件,而不是,内核的构建基础设施从目录中创建一个配置文件(USR / Makefile文件调用USR / gen_ initramfs的.SH),并进行使用配置文件(通过喂养它打包该目录到 usr/gen_init_cpio,它是从 usr/gen_init_cpio.c 创建的)。内核的构建时 cpio 创建代码是完全自包含的,并且内核的引导时提取器(显然)也是自包含的。

您可能需要安装外部 cpio 实用程序的一件事是创建或提取您自己准备好的 cpio 文件以提供给内核构建(而不是配置文件或目录)。

以下命令行可以将 cpio 映像(通过上述脚本或内核构建)提取回其组件文件:

cpio -i -d -H newc -F initramfs_data.cpio --no-absolute-filenames

以下 shell 脚本可以创建一个预构建的 cpio 存档,您可以使用它来代替上述配置文件:

#!/bin/sh# Copyright 2006 Rob Landley <rob@landley.net> and TimeSys Corporation.
# Licensed under GPL version 2if [ $# -ne 2 ]
thenecho "usage: mkinitramfs directory imagename.cpio.gz"exit 1
fiif [ -d "$1" ]
thenecho "creating $2 from $1"(cd "$1"; find . | cpio -o -H newc | gzip) > "$2"
elseecho "First argument must be a directory"exit 1
fi

笔记

cpio 手册页包含一些不好的建议, 如果您遵循这些建议,将会破坏您的initramfs存档。它说“生成文件名列表的典型方法是使用 find 命令;你应该给 find -depth 选项,以尽量减少不可写或不可搜索目录的权限问题。” 创建 initramfs.cpio.gz 图像时不要这样做,它不起作用。Linux 内核 cpio 提取器不会在不存在的目录中创建文件,因此目录条目必须位于进入这些目录的文件之前。上面的脚本以正确的顺序获取它们。

外部initramfs映像:

如果内核启用了 initrd 支持,也可以将外部 cpio.gz 归档文件传递到 2.6 内核中以代替 initrd。在这种情况下,内核将自动检测类型(initramfs,而不是 initrd ),并在尝试运行 /init 之前将外部 cpio 存档提取到 rootfs 中。

这具有initramfs(无 ramdisk 块设备)的内存效率优势,但 initrd 的单独包装(如果您有非 GPL 代码希望从 initramfs 运行,这很好,而不会将其与 GPL 许可的 Linux 内核二进制文件混为一谈)。

它还可用于补充内核的内置initramfs映像。外部存档中的文件将覆盖内置 initramfs 存档中的任何冲突文件。一些发行商还喜欢使用特定于任务的 initramfs 映像自定义单个内核映像,而无需重新编译。

initramfs 的内容:

一个initramfs的档案是用于Linux的完全独立的根文件系统。如果您还不了解启动和运行最小根文件系统所需的共享库、设备和路径,以下是一些参考资料:

  • The Linux Bootdisk HOWTO

  • From Power Up To Bash Prompt

  • Linux From Scratch

“klibc”包 ( Index of /pub/linux/libs/klibc/ ) 被设计为一个微型 C 库,用于静态链接早期用户空间代码以及一些相关实用程序。它是 BSD 许可的。

我自己使用 uClibc ( https://www.uclibc.org ) 和 busybox ( https://www.busybox.net )。它们分别是 LGPL 和 GPL。(一个独立的initramfs 包计划用于 busybox 1.3 版本。)

从理论上讲,您可以使用 glibc,但这不太适合像这样的小型嵌入式用途。(一个与 glibc 静态链接的“hello world”程序超过 400k。使用 uClibc 是 7k。还要注意 glibc dlopens libnss 进行名称查找,即使在其他情况下静态链接也是如此。)

一个好的第一步是让initramfs作为 init 运行一个静态链接的“hello world”程序,并在像 qemu (www.qemu.org) 或用户模式 ​​Linux 这样的模拟器下测试它,如下所示:

cat > hello.c << EOF
#include <stdio.h>
#include <unistd.h>int main(int argc, char *argv[])
{printf("Hello world!\n");sleep(999999999);
}
EOF
gcc -static hello.c -o init
echo init | cpio -o -H newc | gzip > test.cpio.gz
# Testing external initramfs using the initrd loading mechanism.
qemu -kernel /boot/vmlinuz -initrd test.cpio.gz /dev/zero

当调试一个普通的根文件系统时,能够用“init=/bin/sh”引导是很好的。该initramfs的相当于是“rdinit = / bin / sh的”,它只是作为有用的。

为什么是cpio而不是tar?

这个决定是在 2001 年 12 月做出的​​。讨论从这里开始:

http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1538.html

并产生了第二个线程(特别是在 tar 与 cpio 上),从这里开始:

http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1587.html

快速而肮脏的摘要版本(不能替代阅读上述线程)是:

  1. cpio 是一个标准。它已经有几十年的历史(从 AT&T 时代开始),并且已经广泛用于 Linux(在 RPM 中,Red Hat 的设备驱动程序磁盘)。这是 1996 年关于它的 Linux Journal 文章:

    cpio | Linux Journal

    它不如 tar 流行,因为传统的 cpio 命令行工具需要 _truly_hideous_ 命令行参数。但这并没有说明存档格式,还有其他工具,例如:

    afio – Freecode

  2. 内核选择的 cpio 存档格式比任何(实际上是几十种)各种 tar 存档格式都更简单、更清晰(因此更容易创建和解析)。完整的initramfs归档格式在 buffer-format.txt 中有解释,在 usr/gen_init_cpio.c 中创建,在 init/initramfs.c 中提取。这三者加起来总共不到 26k 的人类可读文本。

  3. 对 tar 进行标准化的 GNU 项目与对 zip 进行标准化的 Windows 大致相同。Linux 不属于这两者,可以自由地做出自己的技术决策。

  4. 由于这是内核内部格式,因此很容易成为全新的东西。内核提供了自己的工具来创建和提取这种格式。使用现有标准是可取的,但不是必需的。

  5. Al Viro 做出了决定(引用:“tar 非常丑陋,不会在内核方面得到支持”):

    http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1540.html

    解释了他的理由:

    • http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1550.html

    • http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1638.html

    最重要的是,设计并实现了initramfs代码。

未来发展方向:

今天(2.6.16),initramfs总是被编译进来,但并不总是被使用。只有当 initramfs 不包含 /init 程序时,内核才会回退到旧的引导代码。回退是遗留代码,以确保平稳过渡并允许早期启动功能逐渐转移到“早期用户空间”(IE initramfs)。

迁移到早期用户空间是必要的,因为查找和安装真正的根设备很复杂。根分区可以跨越多个设备(raid 或单独的日志)。它们可以在网络上(需要 dhcp、设置特定的 MAC 地址、登录服务器等)。它们可以存在于可移动媒体上,具有动态分配的主要/次要编号和持续的命名问题,需要完整的 udev 实现来解决。它们可以被压缩、加密、写时复制、环回挂载、奇怪的分区等等。

这种复杂性(不可避免地包括策略)在用户空间中得到了正确处理。klibc 和 busybox/uClibc 都在处理简单的initramfs 包以放入内核构建。

klibc 包现在已被 Andrew Morton 的 2.6.17-mm 树接受。内核当前的早期启动代码(分区检测等)可能会迁移到默认的initramfs 中,由内核构建自动创建和使用。

下一个 以前的

Ramfs、rootfs 和initramfs相关推荐

  1. ramfs, rootfs and initramfs

    Ramfs.rootfs 和initramfs_RToax-CSDN博客Ramfs, rootfs and initramfs - The Linux Kernel documentationhttp ...

  2. linux ramdisk swap,ramdisk和initramfs比较

    Linux内核下的关于ramdisk核ramfs的文档Linux Kernel Documentation  filesystems  ramfs-rootfs-initramfs.txt Linux ...

  3. 介绍-fs、ramdisk、ramfs、tmpfs、initramfs和rootfs

    看了一些关于Linux根文件系统.initramfs的帖子和文档,这里写一下自己的理解. 1.文件系统fs 什么是文件系统,我自己的理解就是数据的组织结构.要理解一个概念,首先应该知道为什么会\提出这 ...

  4. linux 内核启动Initramfs与initrd 及其挂载

    Initramfs/initrd则是填充(仅仅是释放文件到rootfs根目录)/扩充(通过挂载其他文件系统类型到rootfs指定目录)rootfs的关键,以保证Linux系统的后续启动. 1.init ...

  5. initramfs详解-----初识initramfs

    为什么需要initramfs 在Linux内核被加载到内存并运行后,内核进程最终需要切换到用户太的进程来使用计算机,而用户进程又存在于外存储设备上,比如systemd进程,通常systemd进程所在的 ...

  6. openwrt+linux编译,openwrt x86 编译部署

    0.背景 前段时间看到C1037u多网口版本,很是喜欢,替换的4530r,发现玩openwrt x86的人比较少,写一篇日记,以备后用,有错误之处请指出. 1.配置编译环境 Linux 2.获取源代码 ...

  7. Linux-2.6.32.2内核在mini2440上的移植(四)---根文件系统制作(1)

    移植环境(红色粗字体字为修改后内容,蓝色粗体字为特别注意内容) 1,主机环境:VMare下CentOS 5.5 ,1G内存. 2,集成开发环境:Elipse IDE 3,编译编译环境:arm-linu ...

  8. 嵌入式系统中的文件系统以及MTD

    节介绍File System和MTD技术 一 FS 熟知的FS有ext2,3,4.但是这些都是针对磁盘设备的.而ES中一般的存储设备为Flash,由于Flash的特殊性: Flash存储按照Block ...

  9. linux ariod 的总结

    ·ChinaUnix首页 ·论坛 ·博客      Linux首页 | Linux新闻 | Linux论坛 | Linux文档 | Linux下载 | Linux博客 | Linux搜索 | 开源项目 ...

最新文章

  1. BZOJ 3994: [SDOI2015]约数个数和 [莫比乌斯反演 转化]
  2. 文件流下载到本地 - 待完成
  3. 如何写好一份工程师简历
  4. python类和对象实例_python的类和实例化对象
  5. c51 嵌入汇编语言,在C51中嵌入汇编
  6. linux docker 分配资源,Docker 容器资源限制
  7. JS传值中文乱码解决方案
  8. IAP上线后查不到product id
  9. 五种经典网页布局设计
  10. 年末总结 | 音视频开发进阶 2021 干货合集
  11. 27000系列标准族谱
  12. 聚类算法评价指标python实现_聚类算法及其评估指标
  13. 数学家们是怎么玩趣味拼图游戏的?
  14. vue-pdf插件import引入时报错
  15. 机器学习系列(五) -- 逻辑回归(莺尾花数据集)
  16. 商务汇报PPT制作的七堂课-第五课:图片排版
  17. t20171215a1BILL的账单
  18. Ubuntu 10.04内核源码树的编译和安装
  19. 公司申请微信订阅号需要的材料及注意事项
  20. 颜色的前世今生19·外传之PPI、LPI、DPI疑难问题解答

热门文章

  1. 关于SQL Server 2005服务无法启动,报3417错误。(附带重装SQL时解决COM+目录问题)(转帖)
  2. c 读取mysql 并显示_c/c++ mysql读取操作实现简单操控电脑
  3. 有函数就可以实现面向对象
  4. Surface Pro电磁笔故障
  5. Java修炼之道--集合框架
  6. python初学 数据分叉情况下的函数递归
  7. 关于代码控制管理的一些想法
  8. [No00009E]几种常见的命名规则
  9. Arcgis for Android解决中文字体乱码的问题
  10. 3-1-Servlet技术