저는 Linux 커널이 부팅 시 필요한 rootfs의 위치를 어떻게 아는지 이해하려고 노력하고 있습니다.
나는 이 문서를 읽었습니다.
https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt
관심 있는 내용은 다음과 같습니다.
모든 2.6 Linux 커널에는 커널 부팅 시 rootfs로 추출되는 gzip으로 압축된 "cpio" 형식 아카이브가 포함되어 있습니다. 내장된 cpio 아카이브가 추출된 후 rootfs에 init 프로그램이 포함되어 있지 않으면 커널이 실패합니다. 이전 코드 루트 파티션을 찾고 마운트하기 위해
우리 커널은 4.X이지만 이것이 여전히 적용되는 것 같나요? 모든 커널에 "cpio" rootfs가 내장되어 있는 것 같습니다.
실제로 우리가 읽은 바와 같이:
2.6 커널 빌드 프로세스는 항상 gzip으로 압축된 cpio 형식의 initramfs 아카이브를 생성하고 이를 생성된 커널 바이너리에 연결합니다. 기본적으로 이 아카이브는 비어 있습니다... 구성 옵션 CONFIG_INITRAMFS_SOURCE...를 사용하여 initramfs 아카이브의 소스를 지정할 수 있습니다.
이로 인해 몇 가지 질문이 더 제기됩니다.
CONFIG_INITRAMFS_SOURCE
따라서 내 rootfs를 RAM에 두려면 내 rootfs(아마도 cpio 형식)를 가리키도록 설정해야 합니다 .
하지만 이것이 내 커널과 rootfs가 이제 분리될 수 없다는 뜻인가요? 재구축하지 않고 RootFS를 약간 조정하려면 어떻게 해야 합니까? 내 rootfs를 커널과 별도로 저장하려면 어떻게 해야 합니까? 내 rootfs의 위치를 커널에 어떻게 알립니까?
- 또한 내 rootfs를 RAM 대신 물리적 저장소(예: eMMC, 플래시 드라이브 등)에 두려면 어떻게 해야 합니까?
앞서 말한 내용은 다음과 같습니다.
내장된 cpio 아카이브를 rootfs로 추출한 후 rootfs에 init 프로그램이 없으면 커널은 이전 코드를 사용하여 루트 파티션을 찾아 마운트합니다.
그런데...어떡하지? rootfs가 어디에 있는지 어떻게 알 수 있나요? eMMC에 있다면 어떻게든 커널에 알려줘야겠죠?
제가 사용하는 부트로더는 U-boot 입니다. U-boot 환경 변수를 검사하여 어떻게든 rootfs 위치를 커널에 부팅 인수로 전달하고 있는지 확인했지만 그렇지 않은 것 같습니다...
편집하다:
주석에서 지적했듯이 rootfs의 위치는 boot arg를 통해 커널에 전달됩니다. 내 경우에는 u-boot가 root=/dev/mmcblk0p4 rw
부팅 인수로 커널에 전달됩니다. 이것은 내 질문 중 하나에 대한 답변입니다. 압축이 풀린 rootfs에 부팅 인수로 위치를 전달할 수 있습니다.
rootfs.tar.gz
커널과 별개의 것을 고려할 때 커널에 이를 RAM에 압축을 풀고 rootfs로 사용하도록 지시하는 방법은 아직 명확하지 않습니다 . 어쩌면 이것은 불가능할 수도 있고 그냥 사용해야합니까 CONFIG_INITRAMFS_SOURCE
? 어쨌든 4.X 문서를 읽어보겠습니다.
답변1
첫째, 커널 문서의 "2.6" 참조에 겁먹지 마세요. 현재 커널은 여전히 "2.6" 시리즈의 구성원이지만 "마케팅 목적"을 위해 두 차례에 걸쳐 번호를 다시 매겼습니다(따라서 2.6.40은 3.0이 되었고, 3.20은 4.0이 되었습니다). 4.19 커널에는 일반적으로 2.6.79라는 라벨이 붙어 있습니다.
여기서 "rootfs"의 의미에 대해 약간의 혼란이 있는 것 같습니다. "rootfs"는 커널에서 내부적으로 사용되는 특수 RAM 기반 파일 시스템입니다. 이는 일반적 으로 에 마운트되는 "tmpfs" 파일 시스템과 완전히 동일합니다 /run
. (글쎄, "tmpfs" 기능이 커널로 컴파일되지 않는 한, 이 경우 "ramfs"라고 불리는 간단한 "tmpfs"가 사용됩니다.) 이러한 파일 시스템은 페이지 캐시에만 존재하며 장치 ramfs를 지원하지 않습니다. tmpfs는 스왑(사용 가능한 경우)으로 지원됩니다./dev/shm
/tmp
따라서 커널은 "rootfs"를 "찾는" 것에 대해 걱정할 필요가 없지만 시작 시 전체 페이지 캐시가 비어 있으므로 어떻게든 이를 채워야 합니다. 여기가 "initramfs 파일"이 작동하는 곳입니다. 이것은 커널에 의해 빈 "rootfs"로 압축이 풀린 cpio
( tar
문서에 언급된 이유 때문이 아닌) 단지 (압축된) 아카이브입니다 . 이 아카이브는 CONFIG_INITRAMFS_SOURCE
빌드 중 설정을 통해 커널 이미지에 직접 포함되거나 부트 로더에서 제공될 수 있습니다( initrd
GRUB의 옵션이 수행하는 작업). 아카이브는 일반적으로 dracut
또는 (혼란스럽게도) 와 같은 사용자 공간 도구를 사용하여 생성됩니다 mkinitrd
.
cpio 이미지를 사용할 수 없거나 실행 파일이 포함되어 있지 않으면 /init
커널은 명령줄 인수를 보고 root=
이를 실제 루트 파일 시스템의 위치로 해석하고 마운트 /
하고 직접 실행하는 다른 방법으로 대체합니다 init
. 그러나 이 접근 방식은 필요한 모든 저장소 및 파일 시스템 드라이버를 커널에 직접 컴파일해야 하기 때문에 요즘에는 거의 사용되지 않습니다. 대부분의 시스템에서 이 root=
매개변수는 커널에서 사용되지 않고 /init
initramfs에서 처리됩니다. 이는 /init
(일반적으로 systemd
쉘 스크립트) 필수 모듈 로드, 실제 루트 파일 시스템 마운트 및 전환을 담당합니다.
오래 전에 "initrd"라는 다른 메커니즘이 현대의 "initramfs"를 대체하는 데 사용되었습니다. "initrd"("init ramdisk")는 실제 파일 시스템(예: ext2)으로 초기화되고 해당 이미지가 최신 아카이브처럼 제공되는 RAM 기반 블록 장치입니다 cpio
. 이것이 바로 많은 곳에서 이러한 초기 시작 항목을 지칭하기 위해 여전히 "initrd" 이름을 사용하는 이유입니다.
답변2
따라서 내 rootfs를 RAM에 저장하려면 CONFIG_INITRAMFS_SOURCE가 내 rootfs(아마도 cpio 형식)를 가리키도록 설정해야 합니다.
그건하나여러 가지 방법이 있습니다. 예, 하지만 이건 아닙니다.오직방법.
CONFIG_INITRAMFS_SOURCE
커널과 initramfs를 별도의 파일로 로드하도록 구성할 수 있는 부트로더가 있는 경우 커널을 빌드할 때 이는 필요하지 않습니다. CONFIG_BLK_DEV_INITRD
커널 구성에서 설정하는 것으로 충분합니다. (initramfs 이전에는 initramfs라는 이전 버전의 기술이 있었고 initrd
이전 이름이 여전히 일부 위치에 나타납니다.) 부트로더는 initramfs 파일을 로드한 다음 메모리 위치 및 크기에 대한 일부 정보로 데이터 구조를 채웁니다. 로드된 커널 이미지의 위치입니다. 커널에는 이 정보를 사용하여 시스템 RAM에서 initramfs를 찾고 압축을 푸는 내장 루틴이 있습니다.
initramfs를 별도의 파일로 사용하면 initramfs 파일을 더 쉽게 수정할 수 있으며, 부트로더가 사용자의 입력을 받아들일 수 있으면 부팅 시 로드되는 일반 파일 대신 로드할 다른 initramfs 파일을 지정할 수 있습니다. (이것은 사용자 정의 initramfs를 생성하려고 시도하고 실수를 하는 경우 매우 편리합니다. 거기에 가봤습니다.)
기존 BIOS 기반 x86 시스템의 경우 다음에서 이러한 세부 정보를 찾을 수 있습니다.(커널 소스 코드)/Documentation/x86/boot.txt. UEFI 기반 시스템은 이 작업을 약간 다르게 수행하는 반면(동일한 문서에도 설명되어 있음) 다른 아키텍처(예: ARM)에는 부트로더에서 커널로 정보를 전달하는 방법에 대한 고유한 세부 정보 세트가 있습니다.
또한 내 rootfs를 RAM 대신 물리적 저장소(예: eMMC, 플래시 드라이브 등)에 두려면 어떻게 해야 합니까?
일반적인 비임베디드 시스템에서 initramfs에는 일반적으로 기본 하위 시스템을 활성화하는 데 충분한 기능만 포함되어 있습니다. 일반 PC에서 이러한 드라이버는 일반적으로 키보드, 모니터 및 루트 파일 시스템 저장소 컨트롤러용 드라이버는 물론 LVM, 디스크 암호화 및/또는 소프트웨어 RAID와 같은 하위 시스템을 활성화하는 데 필요한 커널 모듈 및 도구입니다. 이러한 기능을 사용하세요.
기본 하위 시스템이 활성화되고 루트 파일 시스템에 액세스할 수 있게 되면 일반적으로 initramfs는 pivot_root(8)
initramfs에서 실제 루트 파일 시스템으로 전환을 수행합니다. 하지만 임베디드 시스템이나 다음과 같은 특수 유틸리티는데이터베이스 관리 네트워크, 필요한 모든 것을 initramfs에 담을 수 있지만 절대 그렇게 하지 마십시오 pivot_root
.
일반적으로 initramfs의 스크립트 및/또는 도구는 커널 명령줄의 옵션에서 실제 루트 파일 시스템을 찾는 데 필요한 정보를 얻습니다. 하지만 당신은 그렇지 않습니다가지다이를 수행하려면: 사용자 정의 initramfs를 사용하면 부팅 시퀀스 중 특정 시간에 특정 키나 마우스 버튼을 누르면 다른 루트 파일 시스템으로 전환하는 등의 작업을 수행할 수 있습니다.
복잡한 저장소 구성(예: 중복 다중 경로 SAN 저장소를 사용하는 시스템의 소프트웨어 RAID 위에 암호화된 LVM)의 경우 루트 파일 시스템을 활성화하는 데 필요한 모든 정보가 커널 명령줄에 맞지 않을 수 있으므로 더 많은 정보를 포함할 수 있습니다. 부분은 initramfs에 배치됩니다.
최신 배포판은 일반적으로 다음을 사용합니다.initramfs 생성기설치된 각 커널에 대해 사용자 정의 initramfs를 빌드하십시오. 자체 initramfs 생성기를 사용하는 다양한 배포판: RedHat은 하나를 사용했고 mkinitrd
Debian은 이를 사용했습니다 update-initramfs
. 하지만 systemd
도입된 후에는 많은 배포판이 표준화되고 있는 것 같습니다.dracut
initramfs 생성기로.
최신 initramfs 파일은 여러 아카이브를 연결할 수 있으며 .cpio
각 아카이브의 각 부분은 압축되거나 압축되지 않을 수 있습니다. 최신 x86_64 시스템의 일반적인 initramfs 파일은 첫 번째 구성 요소로 "초기 마이크로코드 업데이트" 파일을 가질 수 있습니다(일반적으로 마이크로코드 파일은 암호화되어 압축성이 떨어지기 때문에 압축되지 않은 cpio 아카이브의 단일 파일입니다. 그 이후에는 일반 initramfs 콘텐츠(압축 .cpio
파일)
시스템을 더 깊이 이해하려면 initramfs 파일을 임시 디렉터리에 추출하고 그 내용을 살펴보는 것이 좋습니다. 데비안에는 unmkinitramfs(8)
initramfs 파일을 쉽게 추출하는 데 사용할 수 있는 도구 가 있습니다 . RedHat 7에서는 Skip Microcode를 사용하여 /usr/lib/dracut/skipcpio <initramfs file>
파일을 업데이트한 다음 결과 출력을 파이프하고 initramfs 콘텐츠를 현재 작업 디렉터리로 gzcat
계속 추출할 수 있습니다. cpio -i -d
우분투 lzcat
는 gzcat
.