我的问题是关于从单独的 /boot 分区启动 Linux 系统。如果大多数配置文件位于单独的 / 分区上,那么内核如何在启动时正确挂载它?
对此的任何详细说明都会很棒。我觉得我好像缺少一些基本的东西。我最关心的是操作的过程和顺序。
谢谢!
编辑:我认为我需要问的是更多关于根内核参数中使用的开发文件的内容。例如,假设我将根参数指定为 root=/dev/sda2。内核如何拥有/dev/sda2文件的映射?
答案1
在古代,内核被硬编码以了解根文件系统的设备主/次编号,并在初始化所有内置于内核中的设备驱动程序后安装该设备。该rdev
实用程序可用于修改内核映像中的根设备号,而无需重新编译它。
最终引导加载程序出现了,并且可以将命令行传递给内核。如果root=
传递了参数,则告诉内核根文件系统在哪里,而不是内置值。需要访问的驱动程序仍然必须内置到内核中。虽然参数看起来像/dev
目录中的普通设备节点,但在挂载 root fs 之前显然没有/dev
目录,因此内核无法在那里查找 dev 节点。相反,某些众所周知的设备名称被硬编码到内核中,因此可以将字符串转换为设备编号。因此,内核可以识别诸如 之类的东西/dev/sda1
,但不能识别诸如/dev/mapper/vg0-root
卷 UUID 之类的更奇特的东西。
后来,它initrd
出现在画面中。引导加载程序将与内核一起加载initrd
映像,该映像是某种压缩文件系统映像(gzipped ext2 映像、gzipped romfs 映像、squashfs 最终占据主导地位)。内核会将这个镜像解压到一个 ramdisk 中,并将该 ramdisk 作为 root fs 挂载。该映像包含一些额外的驱动程序和启动脚本,而不是真正的init
.这些引导脚本执行各种任务来识别硬件、激活 raid 阵列和 LVM 等内容、检测 UUID 并解析内核命令行以查找真正的根目录,现在可以通过 UUID、卷标和其他高级内容来指定根目录。然后,它将真正的根文件系统挂载到 中/initrd
,然后执行pivot_root
系统调用以交换内核/
,/initrd
然后/sbin/init
在真正的根上执行 exec,然后卸载/initrd
并释放 ramdisk。
最后,今天我们有了initramfs
.这与 类似initrd
,但它不是加载到 ramdisk 中的压缩文件系统映像,而是压缩的 cpio 存档。 tmpfs 作为根挂载,并在那里提取存档。引导脚本没有使用pivot_root
被认为是肮脏的黑客,而是initramfs
将真正的根目录挂载到/root
,删除 tmpfs 根目录中的所有文件,然后chroot
进入/root
,并执行/sbin/init
。
答案2
Linux 最初使用 ramdisk(称为initrd
“INITial RamDisk”)作为启动/
。该磁盘上的空间足以找到真正的根分区(包括所需的任何驱动程序和文件系统模块)。它将根分区挂载到 上的临时挂载点上initrd
,然后调用pivot_root(8)
交换根挂载点和临时挂载点,使 处于待编辑initrd
位置umount
,而实际根文件系统位于 上/
。
答案3
听起来你在问内核如何“知道”哪个分区是根分区,而无需访问 /etc 上的配置文件。
内核可以像任何其他程序一样接受命令行参数。 GRUB 或大多数其他引导加载程序可以接受命令行参数作为用户输入,或者存储它们并通过菜单提供命令行参数的各种组合。引导加载程序在加载内核时将命令行参数传递给内核(我不知道此约定的名称或机制,但它可能类似于应用程序从正在运行的内核中的调用进程接收命令行参数的方式)。
这些命令行选项之一是root
,您可以在其中指定根文件系统,即root=/dev/sda1
。
如果内核使用 initrd,则引导加载程序负责告诉内核它在哪里,或者将 initrd 放在标准内存位置(我认为)——这至少是它在我的 Guruplug 上的工作方式。
完全有可能不指定一个,然后在开始抱怨找不到根文件系统后立即让内核发生恐慌。
可能还有其他方法可以将此选项传递给内核。
答案4
来吧,GRUB 不会“挂载”/boot,它只是读取“menu.lst”和一些模块,它也不是 LINUX 内核的一部分。当您调用内核时,您将传递带有根分区的“root”参数。最坏的情况是,内核知道只安装了 /boot(笑)。
接下来: geekosaur 是对的,Linux 使用压缩镜像格式的初始 ramdisk,然后通过调用 挂载真正的根文件系统pivot_root
。因此,Linux 从映像开始运行,然后从本地磁盘驱动器运行。