요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
=======================
initramfs buffer format
=======================
Al Viro, H. Peter Anvin
With kernel 2.5.x, the old "initial ramdisk" protocol was complemented
with an "initial ramfs" protocol. The initramfs content is passed
using the same memory buffer protocol used by initrd, but the content
is different. The initramfs buffer contains an archive which is
expanded into a ramfs filesystem; this document details the initramfs
buffer format.
The initramfs buffer format is based around the "newc" or "crc" CPIO
formats, and can be created with the cpio(1) utility. The cpio
archive can be compressed using gzip(1), or any other algorithm provided
via CONFIG_DECOMPRESS_*. One valid version of an initramfs buffer is
thus a single .cpio.gz file.
The full format of the initramfs buffer is defined by the following
grammar, where::
* 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)
In human terms, the initramfs buffer contains a collection of
compressed and/or uncompressed cpio archives (in the "newc" or "crc"
formats); arbitrary amounts zero bytes (for padding) can be added
between members.
The cpio "TRAILER!!!" entry (cpio end-of-archive) is optional, but is
not ignored; see "handling of hard links" below.
The structure of the cpio_header is as follows (all fields contain
hexadecimal ASCII numbers fully padded with '0' on the left to the
full width of the field, for example, the integer 4780 is represented
by the ASCII string "000012ac"):
============= ================== ==============================================
Field name Field size Meaning
============= ================== ==============================================
c_magic 6 bytes The string "070701" or "070702"
c_ino 8 bytes File inode number
c_mode 8 bytes File mode and permissions
c_uid 8 bytes File uid
c_gid 8 bytes File gid
c_nlink 8 bytes Number of links
c_mtime 8 bytes Modification time
c_filesize 8 bytes Size of data field
c_maj 8 bytes Major part of file device number
c_min 8 bytes Minor part of file device number
c_rmaj 8 bytes Major part of device node reference
c_rmin 8 bytes Minor part of device node reference
c_namesize 8 bytes Length of filename, including final \0
c_chksum 8 bytes Checksum of data field if c_magic is 070702;
otherwise zero
============= ================== ==============================================
The c_mode field matches the contents of st_mode returned by stat(2)
on Linux, and encodes the file type and file permissions.
c_mtime is ignored unless CONFIG_INITRAMFS_PRESERVE_MTIME=y is set.
The c_filesize should be zero for any file which is not a regular file
or symlink.
c_namesize may account for more than one trailing '\0', as long as the
value doesn't exceed PATH_MAX. This can be useful for ensuring that a
subsequent file data segment is aligned, e.g. to a filesystem block
boundary.
The c_chksum field contains a simple 32-bit unsigned sum of all the
bytes in the data field. cpio(1) refers to this as "crc", which is
clearly incorrect (a cyclic redundancy check is a different and
significantly stronger integrity check), however, this is the
algorithm used.
If the filename is "TRAILER!!!" this is actually an end-of-archive
marker; the c_filesize for an end-of-archive marker must be zero.
Handling of hard links
======================
When a nondirectory with c_nlink > 1 is seen, the (c_maj,c_min,c_ino)
tuple is looked up in a tuple buffer. If not found, it is entered in
the tuple buffer and the entry is created as usual; if found, a hard
link rather than a second copy of the file is created. It is not
necessary (but permitted) to include a second copy of the file
contents; if the file contents is not included, the c_filesize field
should be set to zero to indicate no data section follows. If data is
present, the previous instance of the file is overwritten; this allows
the data-carrying instance of a file to occur anywhere in the sequence
(GNU cpio is reported to attach the data to the last instance of a
file only.)
c_filesize must not be zero for a symlink.
When a "TRAILER!!!" end-of-archive marker is seen, the tuple buffer is
reset. This permits archives which are generated independently to be
concatenated.
To combine file data from different sources (without having to
regenerate the (c_maj,c_min,c_ino) fields), therefore, either one of
the following techniques can be used:
a) Separate the different file data sources with a "TRAILER!!!"
end-of-archive marker, or
b) Make sure c_nlink == 1 for all nondirectory entries.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
initramfs buffer 형식 개요
1-19문서 제목은 `initramfs buffer format`이며 Al Viro와 H. Peter Anvin이 작성했습니다.
kernel 2.5.x에서 기존 `initial ramdisk` protocol에 `initial ramfs` protocol이 추가되었습니다. initramfs 내용은 initrd와 같은 memory buffer protocol로 전달되지만 내용 형식은 다릅니다. initramfs buffer에는 ramfs filesystem으로 펼칠 archive가 들어 있으며, 이 문서는 그 buffer format을 규정합니다.
initramfs buffer format은 CPIO의 `newc` 또는 `crc` format을 기반으로 하며 `cpio(1)` utility로 만들 수 있습니다. cpio archive는 `gzip(1)` 또는 `CONFIG_DECOMPRESS_*`가 제공하는 다른 algorithm으로 압축할 수 있으므로, 단일 `.cpio.gz` file도 유효한 initramfs buffer입니다.
initramfs grammar
20-54전체 initramfs buffer format은 다음 grammar로 정의됩니다. `*`는 0회 이상 반복, `(|)`는 대안, `+`는 이어 붙이기, `GZIP()`·`BZIP2()`·`LZMA()`·`XZ()`·`LZO()`·`LZ4()`·`ZSTD()`는 operand 압축, `ALGN(n)`은 n-byte boundary까지 null byte로 padding함을 뜻합니다.
* 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 buffer는 `newc` 또는 `crc` format의 압축되거나 압축되지 않은 cpio archive 모음입니다. member 사이에는 padding 목적으로 임의 개수의 zero byte를 넣을 수 있습니다.
cpio end-of-archive를 나타내는 `TRAILER!!!` entry는 선택 사항이지만, 존재할 때 무시되지는 않습니다. hard link 처리에서 tuple buffer를 reset하는 의미가 있습니다.
압축 여부와 archive 내부 구성의 계층을 정리했습니다.
cpio_header 구조와 field 규칙
55-103`cpio_header`의 모든 field는 field width 전체를 왼쪽의 `0`으로 채운 hexadecimal ASCII number입니다. 예를 들어 integer 4780은 ASCII string `000012ac`로 표현합니다.
============= ================== ==============================================
Field name Field size Meaning
============= ================== ==============================================
c_magic 6 bytes The string "070701" or "070702"
c_ino 8 bytes File inode number
c_mode 8 bytes File mode and permissions
c_uid 8 bytes File uid
c_gid 8 bytes File gid
c_nlink 8 bytes Number of links
c_mtime 8 bytes Modification time
c_filesize 8 bytes Size of data field
c_maj 8 bytes Major part of file device number
c_min 8 bytes Minor part of file device number
c_rmaj 8 bytes Major part of device node reference
c_rmin 8 bytes Minor part of device node reference
c_namesize 8 bytes Length of filename, including final \0
c_chksum 8 bytes Checksum of data field if c_magic is 070702;
otherwise zero
============= ================== ==============================================
`c_magic`은 `070701` 또는 `070702`이고, `c_ino`는 inode number, `c_mode`는 file type·mode·permission, `c_uid`와 `c_gid`는 owner ID, `c_nlink`는 link count, `c_mtime`은 modification time, `c_filesize`는 data field 크기입니다.
`c_maj`와 `c_min`은 file device number의 major/minor 부분이고, `c_rmaj`와 `c_rmin`은 device node reference의 major/minor 부분입니다. `c_namesize`는 마지막 `\0`을 포함한 filename 길이이며, `c_chksum`은 `c_magic`이 `070702`일 때 data field checksum이고 그 외에는 0입니다.
`c_mode`는 Linux의 `stat(2)`가 반환하는 `st_mode` 내용과 일치하며 file type과 permission을 encode합니다. `c_mtime`은 `CONFIG_INITRAMFS_PRESERVE_MTIME=y`가 아니면 무시됩니다.
regular file이나 symlink가 아닌 file의 `c_filesize`는 0이어야 합니다. `c_namesize`는 `PATH_MAX`를 넘지 않는 한 trailing `\0`을 둘 이상 포함할 수 있습니다. 이를 이용해 뒤따르는 file data segment를 filesystem block boundary 같은 정렬 경계에 맞출 수 있습니다.
`c_chksum`은 data field의 모든 byte를 더한 단순 32-bit unsigned sum입니다. `cpio(1)`은 이를 `crc`라고 부르지만 cyclic redundancy check와는 다른, 훨씬 약한 방식입니다. 이름이 부정확해도 실제로 사용하는 algorithm은 이 합계입니다.
filename이 `TRAILER!!!`이면 실제 file이 아니라 end-of-archive marker이며, 이 marker의 `c_filesize`는 반드시 0이어야 합니다.
모든 field는 hexadecimal ASCII이며 magic만 6 bytes, 나머지는 8 bytes입니다.
hard link 처리
104-123directory가 아니면서 `c_nlink > 1`인 entry를 만나면 `(c_maj,c_min,c_ino)` tuple을 tuple buffer에서 찾습니다. tuple이 없으면 buffer에 추가하고 평소처럼 entry를 생성합니다. 이미 있으면 file의 두 번째 copy 대신 hard link를 만듭니다.
file contents의 두 번째 copy를 넣을 필요는 없지만 넣어도 됩니다. contents를 넣지 않으면 뒤에 data section이 없음을 나타내도록 `c_filesize`를 0으로 설정합니다. data가 있으면 앞서 생성된 file instance를 덮어쓰므로, data를 가진 instance는 sequence의 어느 위치에나 올 수 있습니다. GNU cpio는 data를 file의 마지막 instance에만 붙이는 것으로 알려져 있습니다.
symlink에서는 `c_filesize`가 0이면 안 됩니다. `TRAILER!!!` end-of-archive marker를 만나면 tuple buffer를 reset하므로 독립적으로 생성한 archive들을 서로 이어 붙일 수 있습니다.
c_nlink가 2 이상인 nondirectory entry를 처리하는 순서입니다.
서로 다른 source의 file data 결합
124-132서로 다른 source의 file data를 `(c_maj,c_min,c_ino)` field 재생성 없이 결합하려면 두 방법 중 하나를 사용합니다.
- 서로 다른 file data source 사이에 `TRAILER!!!` end-of-archive marker를 둡니다.
- 모든 nondirectory entry에서 `c_nlink == 1`이 되도록 보장합니다.
요약과 해설
buffer-format.rst:1-132initramfs는 압축 또는 비압축 newc/crc CPIO archive를 이어 붙인 buffer입니다. 각 entry는 4-byte alignment, fixed-width hexadecimal ASCII header, NUL-terminated filename과 data로 구성되며 `TRAILER!!!`은 archive 경계와 hard-link tuple reset을 나타냅니다.
구현 시에는 `c_filesize`, `c_namesize`, `c_chksum`의 특수 규칙과 `(c_maj,c_min,c_ino)` 기반 hard-link 재사용을 정확히 지켜야 합니다.