2014-05-22

How does a kernel mount the root partition?

非常值得參考的一份文件為 Jserv 所寫的深入理解 Linux 2.6 的 initramfs 機制 (上). 以下是對 initrd 與 initramfs 的概念性比較:

  initrd initramfs
Image 壓縮過的檔案系統 (如 ext2 + gzip) 封裝過的檔案 (cpio + gzip)
實做途徑 block device (RAM disk) tmpfs
首先執行的程式 /linuxrc /init

掛載 rootfs 方式

將欲載入的 rootfs 掛載於某個目錄,再 pivot_root 切換 rootfs 使用 switch_root

 

In ancient times, the kernel was hard coded to know the device major/minor number of the root fs and mounted that device after initializing all device drivers, which were built into the kernel. The rdev utility could be used to modify the root device number in the kernel image without having to recompile it.

Eventually boot loaders came along and could pass a command line to the kernel. If the init= argument was passed, that told the kernel where the root fs was instead of the built in value. The drivers needed to access that still had to be built into the kernel. While the argument looks like a normal device node in the /dev directory, there obviously is no /dev directory before the root fs is mounted, so the kernel can not look up a dev node there. Instead, certain well known device names are hard coded into the kernel so the string can be translated to the device number. Because of this, the kernel can recognize things like /dev/sda1, but not more exotic things like /dev/mapper/vg0-root or a volume UUID.

Later, the initrd came into the picture. Along with the kernel, the boot loader would load the initrdimage, which was some kind of compressed filesystem image ( gzipped ext2 image, gzipped romfs image, squashfs finally became dominant ). The kernel would decompress this image into a ramdisk and mount the ramdisk as the root fs. This image contained some additional drivers and boot scripts instead of a real init. These boot scripts performed various tasks to recognize hardware, activate things like raid arrays and LVM, detect UUIDs, and parse the kernel command line to find the real root, which could now be specified by UUID, volume label and other advanced things. It then mounted the real root fs in /initrd, then executed the pivot_root system call to have the kernel swap / and /initrd, then exec /sbin/init on the real root, which would then unmount /initrd and free the ramdisk.

Finally, today we have the initramfs. This is similar to the initrd, but instead of being a compressed filesystem image that is loaded into a ramdisk, it is a compressed cpio archive. A tmpfs is mounted as the root, and the archive is extracted there. Instead of using pivot_root, which was regarded as a dirty hack, the initramfs boot scripts mount the real root in /root, delete all files in the tmpfs root, then chroot into /root, and exec /sbin/init.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.