Linux文件系统映像:Initranfs 和 Initrd
initramfs 和 initrd 介紹
??在/boot目錄下,一般都有一個/boot/initrd.img文件或一個/boot/initramfs.img文件。
??現在有兩個問題。第一個問題就是為什么要有 initrd 或者 initramfs?答案是,為了減小 Linux 內核(Kernel)的大小。Linux內核在初始化之后會執行init進程,而init進程會掛載根文件系統,但由于init程序也是在根文件系統上的,所以這就有了悖論(有關Linux開機過程可以看本系列第一篇)。Linux采用兩步走的方法來解決這個問題。Linux2.6版以前的方法是:除了內核vmlinuz之外還有一個獨立的initrd.img映像文件,其實它就是一個文件系統映像,linux內核在初始化后會mount initrd.img作為一個臨時的根文件系統,而init進程就是在initrd.img里的,然后init進程會掛載真正的根文件系統,然后umount initrd.img。但Linux2.6內核的實現方式卻不太一樣,雖然完成的功能是一樣的。Linux2.6采用initramfs。initramfs:init ram filesystem,它是一個cpio格式的內存文件系統。
??第二個問題就是 initrd 文件和 initramfs 文件是什么格式的,怎么創建和打開。其實在 Linux 的歷史中,內存中的文件系統使用的技術還不一樣。在很老的系統中,是將某一塊內存模擬成磁盤,稱之為 RamDisk,這個技術效率不高,因為將內存模擬成磁盤后,依然需要像對待磁盤一樣對待它,需要給它創建特定格式的文件系統,讀取或寫入文件的時候還是要用到內核的緩存系統,這樣同一份數據就在內存中存在了兩份(套娃),所以很浪費。老系統中使用的 initrd 文件其實就相當于是一個磁盤的鏡像,所以要讀取或寫入它的內容,就需要將它掛在到系統中,然后進行讀寫。就如上一條提到的,在Linux2.6上,initrd 已經被 initramfs 取代了,雖然很多系統中仍然用initrd.img作為文件名,其實使用的是 initramfs 技術。initramfs 技術不使用 RamDisk,而是使用 tempfs,也就是復用了內核中的緩存系統,所以 tempfs 中的內容在內存中只存在一份,那就是在內核的緩存中,不僅節約了內存開銷,也提高了效率。
??在GRUB把控制權交給內核后,通常的步驟是先啟動內核,再內核掛載initrd.img,執行initrd.img中的init進程掛在真正的根文件系統,然后執行其中的/sbin/init。如果沒有initrd.img,計算機的啟動時第一個進程(/sbin/init)都啟動不起來。
?
打開觀察 initramfs 文件
??initramfs文件在系統中以經過壓縮的CPIO格式保存,使用 cat initramfs.img | cpio -imd 打開后文件夾結構如下:whichrpm
??發現只有少許的幾個文件,但是解壓后的文件大小比原文件的要小得多,所以猜測并沒有完全解壓出來。
??網上的文章全都是先用 cp 把.img拷貝并加一個 .gz 后綴,然后用 gunzip 解壓這個文件,然后用 cpio -imd 來解壓 .img 文件,但是這樣解壓結果和我上面的一樣,都不是完全解壓!!!
??我嘗試使用which mkinitramfs 發現ubuntu有這個 mkinitramfs 指令,所以它的內核文件應該就是用這個指令創建的,所以嘗試用 unmkinitramfs 來解壓這個.img文件,但是發現ubuntu沒有這個指令。。。。
??試圖在網上找辦法,在一篇文章中看見了類似的問題,網友的 Fedora 21系統采用了最新的 Early User Space 技術導致cpio無法完全解壓出文件,所以他使用dracut 軟件包中提供的lsinitrd工具可以查看 initramfs 中的內容,發現它需要用到一個skipcpio程序,跳過 initramfs 文件的頭部后,再將剩下的部分當成壓縮的 CPIO 文件進行解包。最后使用 sudo /usr/lib/dracut/skipcpio initramfs.img | zcat | cpio -imd 指令完成解壓。但是我是ubuntu16.04,也沒有這個指令。。。。
??最后無奈發現是ubuntu版本的鍋,我從16.04升級到18.04后就有 unmkinitramfs 指令了!
??解壓后的完整文件夾結構如下:
initrdramfs/ ├── bin ├── conf │ └── conf.d ├── etc │ ├── console-setup │ ├── default │ ├── dhcp │ │ └── dhclient-enter-hooks.d │ ├── fonts │ │ └── conf.d │ ├── ld.so.conf.d │ ├── lvm │ ├── modprobe.d │ ├── plymouth │ └── udev ├── lib │ ├── brltty │ ├── modprobe.d │ ├── modules │ │ └── initramfs.img-0.1 │ ├── systemd │ │ └── network │ ├── udev │ │ └── rules.d │ └── x86_64-linux-gnu ├── lib64 ├── run ├── sbin ├── scripts │ ├── init-bottom │ ├── init-premount │ ├── init-top │ ├── local-block │ ├── local-bottom │ ├── local-premount │ ├── local-top │ └── panic ├── usr │ ├── lib │ │ └── x86_64-linux-gnu │ │ └── plymouth │ │ └── renderers │ └── share │ ├── fonts │ │ └── truetype │ │ └── dejavu │ └── plymouth │ └── themes │ ├── details │ ├── ubuntu-logo │ └── ubuntu-text └── var├── cache│ └── fontconfig└── lib└── dhcp??可以看出這幾乎就是一個小型文件系統的根目錄。
??通過 systemctl list-dependencies initrd.target 指令來觀察系統內默認的initrd.target相依的配置數據如下:
initrd.target ● ├─initrd-parse-etc.service ● ├─basic.target ● │ ├─-.mount ● │ ├─tmp.mount ● │ ├─paths.target ● │ │ ├─acpid.path ● │ │ └─apport-autoreport.path ● │ ├─slices.target ● │ │ ├─-.slice ● │ │ └─system.slice ● │ ├─sockets.target ● │ │ ├─acpid.socket ● │ │ ├─apport-forward.socket ● │ │ ├─avahi-daemon.socket ● │ │ ├─cups.socket ● │ │ ├─dbus.socket ● │ │ ├─dm-event.socket ● │ │ ├─snapd.socket ● │ │ ├─systemd-initctl.socket ● │ │ ├─systemd-journald-audit.socket ● │ │ ├─systemd-journald-dev-log.socket ● │ │ ├─systemd-journald.socket ● │ │ ├─systemd-udevd-control.socket ● │ │ ├─systemd-udevd-kernel.socket ● │ │ └─uuidd.socket ● │ ├─sysinit.target ● │ │ ├─apparmor.service ● │ │ ├─blk-availability.service ● │ │ ├─dev-hugepages.mount ● │ │ ├─dev-mqueue.mount ● │ │ ├─finalrd.service ● │ │ ├─keyboard-setup.service ● │ │ ├─kmod-static-nodes.service ● │ │ ├─lvm2-lvmpolld.socket ● │ │ ├─lvm2-monitor.service ● │ │ ├─plymouth-read-write.service ● │ │ ├─plymouth-start.service ● │ │ ├─proc-sys-fs-binfmt_misc.automount ● │ │ ├─resolvconf.service ● │ │ ├─setvtrgb.service ● │ │ ├─sys-fs-fuse-connections.mount ● │ │ ├─sys-kernel-config.mount ● │ │ ├─sys-kernel-debug.mount ● │ │ ├─sys-kernel-tracing.mount ● │ │ ├─systemd-ask-password-console.path ● │ │ ├─systemd-binfmt.service ● │ │ ├─systemd-boot-system-token.service ● │ │ ├─systemd-hwdb-update.service ● │ │ ├─systemd-journal-flush.service ● │ │ ├─systemd-journald.service ● │ │ ├─systemd-machine-id-commit.service ● │ │ ├─systemd-modules-load.service ● │ │ ├─systemd-pstore.service ● │ │ ├─systemd-random-seed.service ● │ │ ├─systemd-sysctl.service ● │ │ ├─systemd-sysusers.service ● │ │ ├─systemd-timesyncd.service ● │ │ ├─systemd-tmpfiles-setup-dev.service ● │ │ ├─systemd-tmpfiles-setup.service ● │ │ ├─systemd-udev-trigger.service ● │ │ ├─systemd-udevd.service ● │ │ ├─systemd-update-utmp.service ● │ │ ├─cryptsetup.target ● │ │ ├─local-fs.target ● │ │ │ ├─-.mount ● │ │ │ ├─systemd-fsck-root.service ● │ │ │ └─systemd-remount-fs.service ● │ │ └─swap.target ● │ │ └─dev-disk-by\x2duuid-6b5d98c0\x2dcd6e\x2d4a35\x2db8ef\x2dd7743df35ed4.sw… ● │ └─timers.target ● │ ├─anacron.timer ● │ ├─apt-daily-upgrade.timer ● │ ├─apt-daily.timer ● │ ├─e2scrub_all.timer ● │ ├─fstrim.timer ● │ ├─fwupd-refresh.timer ● │ ├─logrotate.timer ● │ ├─man-db.timer ● │ ├─motd-news.timer ● │ ├─snapd.snap-repair.timer ● │ ├─systemd-tmpfiles-clean.timer ● │ └─ua-messaging.timer ● ├─initrd-fs.target ● ├─initrd-root-device.target ● └─initrd-root-fs.target??可以看出這個小型根文件系統也是通過systemd來進行管理的,同時觀察 default.target 的鏈接,會發現其實這個小型系統就是通過initrd.target 來開機,而initrd.target 也是需要讀入一堆例如 basic.target、sysinit.target 等等的硬件偵測、核心功能啟用的流程, 然后開始讓系統順利運行。最終才又卸載 initramfs 的小型文件系統,實際掛載系統的根目錄。此外initramfs并沒有包含各種龐多的驅動文件,而是僅帶入開機過程會用到的核心模塊而已,例如SCSI、cirto、RAID等和磁盤相關性高的模塊。
總結
以上是生活随笔為你收集整理的Linux文件系统映像:Initranfs 和 Initrd的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PIC单片机 IIC通信及实现
- 下一篇: Systemd 入门及常用命令