ARM64 Linux 6.10内核启动流程2-rootfs 怎么挂上

§1.1 rootfs 怎么挂上

平台:QEMU virt + ARM64。当前命令:

bash 复制代码
qemu-system-aarch64 \
  -M virt \
  -cpu cortex-a57 \
  -m 1024 \
  -kernel linux-6.10/arch/arm64/boot/Image \
  -initrd initramfs.cpio.gz \
  -nographic \
  -append "console=ttyAMA0 nokaslr" \
  -s -S

0. 这条命令和根有关的部分

QEMU 和根的关系
-initrd initramfs.cpio.gz cpio initramfs ,解进已经存在的内存 /。不是 root=/dev/ram,不是 Root_RAM0
-append "console=ttyAMA0 nokaslr" 没有 root= ,saved_root_name 为空
包里的 /init busybox 脚本,最后 exec /bin/sh。有它就不会进 prepare_namespace
sh 复制代码
#!/bin/busybox sh
/bin/busybox --install -s /bin
mount -t proc proc /proc
mount -t sysfs sys /sys
exec /bin/sh

1. 在 main.c 里和挂根相关的挂钩

内核一开始 没有磁盘 /。先有一个空的内存根,再决定要不要切成真根。

复制代码
start_kernel
  vfs_caches_init → mnt_init
       init_rootfs()              // do_mounts.c:tmpfs 还是 ramfs
       init_mount_tree()          // 空的 "/" 挂上          【会走】

kernel_init → kernel_init_freeable
  populate_rootfs(initramfs.c)  // 异步把 cpio 解进 "/"
  wait_for_initramfs()            // 等解压完;不是 do_mounts 入口
  console_on_rootfs()
  if (init_eaccess("/init") != 0)
      prepare_namespace()         // do_mounts.c 主戏      【本套不走】
  kernel_execve("/init" 或 /sbin/init)

wait_for_initramfs() 在 init/initramfs.c,只等 cpio 铺完。

进 do_mounts.c 读挂真根,入口是 prepare_namespace() ,不是 wait_for_initramfs。


2. 核心抽象(读 prepare_namespace 盯这三句)

  1. / 可以换 :启动用空 rootfs 当容器;真根先挂到 /root,再 MS_MOVE + chroot 换成 /。这是挂载命名空间,不是驱动总线。
  2. 根由 cmdline 策略选定 :root= / rootfstype= / ro/rw / rootdelay / rootwait。硬件只是被查表。
  3. 挂根是消费者:块设备由 probe 异步造出;挂之前必须等「这一波 probe」结束。

3. 路 A ------ 你现在:initramfs 铺进空根(不切根)

复制代码
空的内存 /(init_rootfs + init_mount_tree)
    → rootfs_initcall(populate_rootfs)
        unpack_to_rootfs(cpio)          // init/initramfs.c
    → wait_for_initramfs()
    → init_eaccess("/init") 成功
    → 跳过 prepare_namespace / mount_root
    → kernel_execve("/init") → exec /bin/sh

/ 从头到尾就是那块内存盘:先空,再被 initramfs.cpio.gz 填上 busybox。没有第二块盘。

不是 Root_RAM0。 那个是 root=/dev/ram 时 parse_root_device() 返回的老式 ramdisk 块设备。你没有 root=,也进不了 parse_root_device。


4. 路 B ------ BSP 常卡:prepare_namespace 切真根

仅当 没有可 exec 的 /init 时:

c 复制代码
ramdisk_execute_command = NULL;
prepare_namespace();

流水线:

复制代码
rootdelay                         给慢速 USB/MMC 多等几秒
  → wait_for_device_probe()       等已经触发的 probe / deferred / async
  → md_run_setup()
  → parse_root_device(root=)      填 ROOT_DEV;找不到则为 0
  → initrd_load()                 老式块设备 initrd;cpio 路径通常 false
  → rootwait                      ROOT_DEV==0 时轮询设备出现
  → mount_root(saved_root_name)   真根挂到 /root(还不是 /)
  → devtmpfs_mount
  → MS_MOVE + chroot              「/」换身份

mount_root() 按 ROOT_DEV 分发:NFS / CIFS / mtd·ubi / 普通块设备。

块设备:mknod /dev/root → do_mount_root(..., "/root")。

源 = root= 那个设备;目标 = 空 rootfs 里的 /root;fstype = rootfstype= 或逐个试。

之后 MS_MOVE 才把这棵子树变成 /。

你这条命令 没有 root=、有 /init,整段 B 不执行。

以后真板要复现:加盘 + root=/dev/vda,并且让 /init 不存在(或 rdinit= 指到无效路径)。

和 probe 的关系(栅栏,不是本条主模型)

wait_for_device_probe()(drivers/base/dd.c)只保证「已经排队/正在跑的 probe」结束,不管以后还会不会有新设备。

  1. flush_work(deferred_probe_work) --- -EPROBE_DEFER 那一轮
  2. wait_event(probe_waitqueue, probe_count==0) --- PID 1 睡在这里,schedule() 在 wait.h
  3. async_synchronize_full() --- 异步 probe

叫醒:driver_probe_device() 里每次 probe 结束 probe_count-- + wake_up_all。

设备和驱动谁后上总线,谁触发这次 probe(device_add 或 driver_register)。匹配算法属 §1.2。


5. 按你这条命令:会走 / 不走

步骤 走?
init_rootfs / 空 / 走
populate_rootfs 解 cpio 走
wait_for_initramfs 走
prepare_namespace / mount_root / parse_root_device 不走
execve("/init") → exec /bin/sh 走

gdb:断 prepare_namespace / mount_root 不该命中。看根相关断 populate_rootfs、unpack_to_rootfs、kernel_execve。


相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
未济3 天前
linux 配置环境变量
linux
傲世仙尊3 天前
目录即文件-Ext文件系统收尾篇
linux·c语言
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
虎头金猫3 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁4 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
_艾伦 耶格尔.4 天前
进程间通信
linux