initramfs 缓冲区格式¶
Al Viro, H. Peter Anvin
对于内核 2.5.x,旧的“初始 ramdisk”协议被“初始 ramfs”协议补充。 initramfs 内容使用与 initrd 相同的内存缓冲区协议传递,但内容不同。 initramfs 缓冲区包含一个存档,该存档被扩展到 ramfs 文件系统中;本文档详细介绍了 initramfs 缓冲区格式。
initramfs 缓冲区格式基于 “newc” 或 “crc” CPIO 格式,可以使用 cpio(1) 实用程序创建。 cpio 存档可以使用 gzip(1) 或通过 CONFIG_DECOMPRESS_* 提供的任何其他算法进行压缩。 因此,initramfs 缓冲区的一个有效版本是单个 .cpio.gz 文件。
initramfs 缓冲区的完整格式由以下语法定义,其中
* is used to indicate "0 or more occurrences of"
(|) indicates alternatives
+ indicates concatenation
GZIP() indicates gzip compression of the operand
BZIP2() indicates bzip2 compression of the operand
LZMA() indicates lzma compression of the operand
XZ() indicates xz compression of the operand
LZO() indicates lzo compression of the operand
LZ4() indicates lz4 compression of the operand
ZSTD() indicates zstd compression of the operand
ALGN(n) means padding with null bytes to an n-byte boundary
initramfs := ("\0" | cpio_archive | cpio_compressed_archive)*
cpio_compressed_archive := (GZIP(cpio_archive) | BZIP2(cpio_archive)
| LZMA(cpio_archive) | XZ(cpio_archive) | LZO(cpio_archive)
| LZ4(cpio_archive) | ZSTD(cpio_archive))
cpio_archive := cpio_file* + (<nothing> | cpio_trailer)
cpio_file := ALGN(4) + cpio_header + filename + "\0" + ALGN(4) + data
cpio_trailer := ALGN(4) + cpio_header + "TRAILER!!!\0" + ALGN(4)
用通俗的话说,initramfs 缓冲区包含压缩的和/或未压缩的 cpio 存档的集合(采用 “newc” 或 “crc” 格式);可以在成员之间添加任意数量的零字节(用于填充)。
cpio “TRAILER!!!” 条目(cpio 存档结束)是可选的,但不会被忽略;请参阅下面的“硬链接处理”。
cpio_header 的结构如下(所有字段都包含十六进制 ASCII 数字,并在左侧用 ‘0’ 完全填充到字段的完整宽度,例如,整数 4780 由 ASCII 字符串 “000012ac” 表示)
字段名称 |
字段大小 |
含义 |
---|---|---|
c_magic |
6 字节 |
字符串 “070701” 或 “070702” |
c_ino |
8 字节 |
文件 inode 编号 |
c_mode |
8 字节 |
文件模式和权限 |
c_uid |
8 字节 |
文件 uid |
c_gid |
8 字节 |
文件 gid |
c_nlink |
8 字节 |
链接数 |
c_mtime |
8 字节 |
修改时间 |
c_filesize |
8 字节 |
数据字段的大小 |
c_maj |
8 字节 |
文件设备编号的主要部分 |
c_min |
8 字节 |
文件设备编号的次要部分 |
c_rmaj |
8 字节 |
设备节点引用的主要部分 |
c_rmin |
8 字节 |
设备节点引用的次要部分 |
c_namesize |
8 字节 |
文件名长度,包括最后的 0 |
c_chksum |
8 字节 |
如果 c_magic 为 070702,则为数据字段的校验和;否则为零 |
c_mode 字段与 Linux 上 stat(2) 返回的 st_mode 的内容匹配,并编码文件类型和文件权限。
除非设置了 CONFIG_INITRAMFS_PRESERVE_MTIME=y,否则将忽略 c_mtime。
对于任何不是常规文件或符号链接的文件,c_filesize 应为零。
c_chksum 字段包含数据字段中所有字节的简单 32 位无符号和。 cpio(1) 将其称为 “crc”,这显然是不正确的(循环冗余校验是一种不同的且明显更强的完整性检查),但是,这是使用的算法。
如果文件名为 “TRAILER!!!”,则实际上是存档结束标记;存档结束标记的 c_filesize 必须为零。
硬链接处理¶
当看到 c_nlink > 1 的非目录时,将在元组缓冲区中查找 (c_maj,c_min,c_ino) 元组。 如果未找到,则将其输入到元组缓冲区中,并像往常一样创建条目;如果找到,则创建硬链接而不是文件的第二个副本。 不需要(但允许)包含文件的第二个副本;如果未包含文件内容,则应将 c_filesize 字段设置为零,以指示后面没有数据部分。 如果存在数据,则会覆盖该文件的先前实例;这允许文件的携带数据的实例出现在序列中的任何位置(据报道,GNU cpio 仅将数据附加到文件的最后一个实例。)
对于符号链接,c_filesize 不能为零。
当看到 “TRAILER!!!” 存档结束标记时,元组缓冲区将被重置。 这允许将独立生成的存档连接起来。
因此,要组合来自不同来源的文件数据(而不必重新生成 (c_maj,c_min,c_ino) 字段),可以使用以下任一技术
使用 “TRAILER!!!” 存档结束标记分隔不同的文件数据源,或者
确保所有非目录条目的 c_nlink == 1。