首页/目录/全部文章

全部文章

八个专题的源码、算法与协议笔记都在这里。

笔记列表

Linux 6.1 文件系统源码文档索引(RK3588)

Linux 6.1 文件系统源码文档索引(RK3588)

源码:rk3588/kernel-6.1/fs/,共约 2100 个文件,包含 VFS 核心、通用文件 I/O 基础设施和数十种具体文件系统。

新增总览与专题

编号 文档 内容
总览 Linux文件系统架构与源码总览.md VFS 分层、核心对象与系统调用
索引 源码目录与文件系统索引.md Makefile/Kconfig、目录分类
01 VFS核心对象与生命周期.md super/inode/dentry/file
02 路径解析打开与元数据操作.md namei、open、create、rename
03 文件描述符读写与零拷贝.md fdtable、read/write、splice、pipe
04 挂载命名空间与fs_context.md mount tree、新挂载 API
05 页缓存写回与块IO.md address_space、writeback、buffer/mpage
06 权限ACL-Xattr锁与配额.md permission、ACL、xattr、locks、quota
07 事件通知与异步IO接口.md epoll、eventfd、aio、inotify/fanotify
08 Iomap-DirectIO与DAX.md iomap、direct I/O、DAX
09 加密完整性与文件系统安全.md fscrypt、fs-verity、安全边界
10 内存伪文件系统与Overlay-FUSE.md proc/sysfs/tmpfs/overlay/fuse
11 本地磁盘文件系统对比.md ext4/f2fs/xfs/btrfs
12 只读与闪存文件系统.md EROFS/SquashFS/UBIFS/JFFS2
13 网络与分布式文件系统.md NFS/SMB/Ceph/9P/AFS
14 并发缓存一致性与故障恢复.md 锁、RCU、引用、fsync、崩溃一致性
15 RK3588存储部署与排障.md eMMC/NVMe/闪存/容器调优
16 可执行文件加载与Coredump.md exec、binfmt、ELF、脚本、core

已有深度文档

  • fs总线/:VFS 单文件和主调用链分析。
  • ext4/:ext4 各模块深度分析。
  • 网文博客/:文件系统原理背景资料,内容不等同于本内核源码结论。

推荐阅读顺序

总览01 VFS 对象02 路径与打开03 fd 与读写04 挂载与 namespace05 页缓存与块 IO08 iomap/DIO/DAX06 权限与元数据07 通知与异步接口11 本地文件系统12 只读/闪存10 伪文件系统13 网络文件系统14 一致性15 RK3588

快速观测

1
2
3
4
5
6
7
8
cat /proc/filesystems
findmnt
cat /proc/self/mountinfo
cat /proc/meminfo
cat /proc/vmstat
cat /proc/diskstats
df -hT
df -i

fs/ 源码目录与文件系统索引

fs/ 源码目录与文件系统索引

1. VFS 核心编译单元

fs/Makefile 无条件编入的主要模块:

主题 文件
打开/读写 open.c, read_write.c, file.c, file_table.c
路径与名称 namei.c, dcache.c, d_path.c
inode/super inode.c, super.c, bad_inode.c
mount namespace.c, pnode.c, fs_context.c, fsopen.c
元数据 stat.c, attr.c, xattr.c, readdir.c, utimes.c
fd/control fcntl.c, ioctl.c, select.c
I/O splice.c, sync.c, fs-writeback.c, remap_range.c
注册/解析 filesystems.c, fs_parser.c, fs_types.c
工具 seq_file.c, libfs.c, stack.c, fs_pin.c, nsfs.c

CONFIG_BLOCK=y 时加入 buffer.cdirect-io.cmpage.c;否则使用 no-block.c

2. 通用子系统

目录/文件 功能
iomap/ extent 映射、buffered/direct I/O
notify/ dnotify/inotify/fanotify/fsnotify
quota/ 用户/组/project quota
crypto/ fscrypt 文件级加密
verity/ fs-verity 文件数据认证
netfs/ 网络文件系统读缓存辅助
fscache/, cachefiles/ 网络数据本地缓存
exportfs/ NFS export file handle
nls/, unicode/ 字符集与 Unicode
jbd2/ ext4 日志层

3. 本地块文件系统

文件系统 目录 特点
ext4 ext4/ 通用、JBD2、extent、成熟
f2fs f2fs/ flash-friendly、segment/SSR
XFS xfs/ allocation group、延迟日志、iomap
Btrfs btrfs/ CoW、checksum、snapshot、RAID
ext2 ext2/ 无日志、简单
NILFS2 nilfs2/ log-structured + checkpoint
zonefs zonefs/ zoned block device 暴露
GFS2/OCFS2 对应目录 共享磁盘集群文件系统

4. 可移动介质和兼容文件系统

  • fat/, exfat/
  • ntfs/(旧只读/有限写)与 ntfs3/
  • isofs/, udf/
  • hfs/, hfsplus/
  • minix/, sysv/, ufs/ 等。

5. 闪存与只读镜像

文件系统 后端
EROFS 块设备,只读、可压缩
SquashFS 块设备,只读压缩镜像
CramFS/RomFS 简单只读镜像
UBIFS UBI/raw NAND
JFFS2 MTD/raw flash

UBIFS/JFFS2 不是普通 eMMC/NVMe 的首选;raw NAND 需结合 MTD/UBI。

6. 伪、内存和叠加

  • ramfs/(同时提供 tmpfs/shmem mount glue)
  • proc/, kernfs/, sysfs/
  • debugfs/, tracefs/, configfs/
  • devpts/, efivarfs/, pstore/
  • overlayfs/
  • fuse/
  • autofs/

7. 网络与分布式

  • NFS client/server:nfs/, nfsd/, nfs_common/
  • SMB/CIFS:smb/client/, smb/server/
  • CephFS:ceph/
  • 9P、AFS、Coda、OrangeFS。

其 socket/RPC 基础可能位于 net/,不应把 fs/ 当作全部网络协议实现。

8. 条件编译

fs/Kconfig 汇总各文件系统 Kconfig。关键公共选项:

  • CONFIG_BLOCK
  • CONFIG_FS_IOMAP
  • CONFIG_FILE_LOCKING
  • CONFIG_FS_ENCRYPTION
  • CONFIG_FS_VERITY
  • CONFIG_FS_DAX
  • CONFIG_FS_POSIX_ACL
  • CONFIG_PROC_FS, CONFIG_SYSFS, CONFIG_CONFIGFS_FS
  • CONFIG_FSCACHE, CONFIG_CACHEFILES
  • CONFIG_AIO, CONFIG_EPOLL, CONFIG_USERFAULTFD

源码存在不表示 RK3588 产品配置已启用,应以最终 .config/proc/filesystems 为准。

start_kernel 早期初始化机制与实现详解

start_kernel 早期初始化机制与实现详解

源码路径rk3588/kernel-6.1/init/main.cstart_kernel
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录linuxDoc/init/


目录


一、原理

1.1 角色

start_kernel()架构无关 的内核主初始化函数:在 boot CPU、中断关闭 的早期环境中,依次建立内存管理、调度器、中断与时间子系统的基础,再打开中断并完成进程/VFS/cgroup 等“晚期”初始化,最后交给 rest_init() 进入多任务世界。

1.2 与 arch 的分工

层次 典型工作
arch/arm64 页表、异常向量、setup_arch、DT、SMP 表
start_kernel 通用子系统顺序、命令行解析、调用 mm_init

二、实现方式

2.1 入口与早期安全

1
2
3
4
5
6
7
8
9
10
11
12
asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
{
// ...
local_irq_disable();
early_boot_irqs_disabled = true;
boot_cpu_init();
page_address_init();
setup_arch(&command_line);
setup_boot_config();
setup_command_line(command_line);
build_all_zonelists(NULL);
page_alloc_init();
  • set_task_stack_end_magic(&init_task):栈溢出检测魔数
  • cgroup_init_early():最早 cgroup 钩子
  • setup_boot_config():可选 bootconfig blob

2.2 命令行与早期参数

  1. setup_command_line 合并 DT / 内置 / 用户 cmdline → saved_command_line
  2. RK:分段 pr_cont 打印(见第四节)
  3. parse_early_param()__setupearly 标记的选项
  4. parse_args:内核模块参数表 __param-- 之后交给 init 的 argv

2.3 内存与陷阱

调用 作用
mm_init() slab、vmalloc、buddy 相关晚期 mm 初始化
trap_init() 陷阱/异常表(架构相关实现)
sort_main_extable() 内核异常表排序

须在 kmem_cache_init() 之前完成大块 bootmem 分配(如 setup_log_buf)。

2.4 调度、RCU、中断、时间

1
2
3
4
5
6
7
8
9
10
11
sched_init();
// ...
rcu_init();
early_irq_init();
init_IRQ();
tick_init();
init_timers();
hrtimers_init();
softirq_init();
timekeeping_init();
time_init();

注意:完整 CPU 拓扑与 SMP 负载均衡在 kernel_init_freeablesmp_init() / sched_init_smp(),此处仅为 单 CPU 可调度 的最小环境。

2.5 开中断后的“晚期”初始化

1
2
3
4
5
6
7
8
9
10
11
local_irq_enable();
kmem_cache_init_late();
console_init();
lockdep_init();
// ...
cred_init();
fork_init();
vfs_caches_init();
cgroup_init();
// ...
arch_call_rest_init();
  • calibrate_delay():BogoMIPS(见 06
  • arch_call_rest_init():通常直接调用 rest_init(),且 不再返回

三、关键接口与顺序

setup_arch + memparse paramsmm_init sched_initIRQ timerslocal_irq_enableconsole vfs cgrouparch_call_rest_init
全局状态 设置时机
system_state rest_init 中设为 SYSTEM_SCHEDULING
gfp_allowed_mask kernel_init_freeable 开头放开

四、RK3588 平台说明

CONFIG_ARCH_ROCKCHIP 时,首次 pr_notice 打印 cmdline 后,用循环 pr_cont 输出剩余字符,避免 单条日志长度限制 导致启动参数截断(排查 root=console= 时很重要)。


五、调试与观测

手段 说明
earlyprintk / console= console_init 前后观察
initcall_debug 对 initcall 更有效,但 start_kernel 末尾可开 trace
ignore_loglevel 强制打印级别
启动 stall 对比 printk 时间戳,定位卡在 calibrate_delayconsole_init

附录:源码索引

符号 文件 约行
start_kernel init/main.c 939
parse_early_options init/main.c 755
arch_call_rest_init arch 或 weak 默认

下一篇02 rest_init 与 kernel_init

rest_init 与 kernel_init 机制与实现详解

rest_init 与 kernel_init 机制与实现详解

源码路径rk3588/kernel-6.1/init/main.c
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录linuxDoc/init/


目录


一、原理

1.1 为何需要 rest_init

start_kernel() 运行在 init_task 上且长期关抢占。再继续在同一上下文里挂根、exec init 会阻塞 boot CPU。rest_init() 的职责是:

  1. 创建 将变为 PID 1kernel_init 内核线程
  2. 创建 kthreadd(其它内核线程的父线程)
  3. 让当前 boot 线程进入 idle

1.2 kernel_init 两阶段

阶段 函数 内容
可释放 init 内存前 kernel_init_freeable SMP、initcall、initramfs、挂根
之后 kernel_init 本体 free_initmemSYSTEM_RUNNINGkernel_execve

二、实现方式

2.1 rest_init()

1
2
3
4
5
6
7
8
9
10
noinline void __ref rest_init(void)
{
pid = user_mode_thread(kernel_init, NULL, CLONE_FS);
// PF_NO_SETAFFINITY,绑 boot CPU
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
complete(&kthreadd_done);
system_state = SYSTEM_SCHEDULING;
schedule_preempt_disabled();
cpu_startup_entry(CPUHP_ONLINE);
}

顺序约束:必须先有 kthreadd,否则 kernel_init 里创建 kthread 会 OOPS;因此 kernel_init 开头 wait_for_completion(&kthreadd_done)

2.2 kernel_init_freeable()

典型顺序:

1
2
3
4
5
6
7
8
9
10
11
gfp_allowed_mask = __GFP_BITS_MASK
smp_prepare_cpus → workqueue_init → init_mm_internals
do_pre_smp_initcalls()
smp_init() → sched_init_smp()
[可选] kthread_run(defer_free_memblock) // RK Thunder Boot
page_alloc_init_late()
do_basic_setup() // driver_init + do_initcalls
wait_for_initramfs()
console_on_rootfs()
若 ramdisk_execute_command 不可执行 → prepare_namespace()
integrity_load_keys()

2.3 kernel_init() 收尾

1
2
3
4
5
6
7
8
9
system_state = SYSTEM_FREEING_INITMEM;
free_initmem();
mark_readonly();
pti_finalize();
system_state = SYSTEM_RUNNING;
// exec 顺序:
// ramdisk_execute_command → init= → CONFIG_DEFAULT_INIT
// → /sbin/init → /etc/init → /bin/init → /bin/sh
panic("No working init found...");

run_init_process() 内部 kernel_execve,使用 argv_init / envp_init(含 init=-- 后参数)。

2.4 早期用户态 init(initramfs)

ramdisk_execute_command(默认常为 /init)存在且可访问,可能prepare_namespace 之前由 initramfs 脚本完成挂根;否则走 prepare_namespace()。逻辑在 kernel_init_freeable

1
2
3
4
if (init_eaccess(ramdisk_execute_command) != 0) {
ramdisk_execute_command = NULL;
prepare_namespace();
}

三、关键数据结构与接口

符号 含义
kthreadd_done completion,同步 kthreadd 就绪
execute_command init= 启动参数
ramdisk_execute_command initramfs 中 init 路径
system_state SYSTEM_SCHEDULINGFREEING_INITMEMRUNNING
cad_pid Ctrl-Alt-Del 处理用 pid(在 freeable 中设置)
kthreaddkernel_initboot 线程kthreaddkernel_initboot 线程user_mode_threadkernel_threadcpu_idlewait kthreadd_donekernel_init_freeablefree_initmem exec init

四、RK3588 平台说明

CONFIG_ROCKCHIP_THUNDER_BOOT_DEFER_FREE_MEMBLOCK 时,在 smp_init() / sched_init_smp() 之后启动 defer_mem 内核线程,将 memblock 延迟释放与 buddy 初始化并行。详见 07

编解码板卡上 PID 1 多为 systemd 或 busybox;内核只负责 exec,服务编排不在 init/


五、调试与观测

现象 排查
卡在 Freeing unused kernel memory 之前 initcall、wait_for_initramfs
No working init found init= 路径、rootfs 是否含 /sbin/init
重复挂根 initramfs /init 是否已 pivot_root
Failed to execute ... (error -2) ENOENT,检查 initramfs 或根分区

ps 不可用时,用 printkRun ... as init process 确认 exec 目标。


附录:源码索引

符号 约行 main.c
rest_init 687
kernel_init 1713
kernel_init_freeable 1803
run_init_process 1626

相关03 initcall04 挂根

initcall 驱动初始化机制与实现详解

initcall 驱动初始化机制与实现详解

源码路径rk3588/kernel-6.1/init/main.cinclude/linux/init.h
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录linuxDoc/init/


目录


一、原理

1.1 设计目标

内核与子系统在编译期通过 __define_initcall(level, fn) 把初始化函数放入链接器段;启动时 按级别顺序 调用,无需中央注册表。执行完毕后,__init 代码随 free_initmem() 回收。

1.2 与 module_init 的关系

可加载模块的 module_init()insmod 时执行;内置驱动等价逻辑通常落在 devicelate 级 initcall。


二、实现方式

2.1 调用链

1
2
3
4
5
6
7
kernel_init_freeable()
do_pre_smp_initcalls() // early: __initcall_start .. __initcall0_start
smp_init()
do_basic_setup()
driver_init()
do_ctors() // CONFIG_CONSTRUCTORS
do_initcalls() // level 0..7

2.2 七级划分

Level 名称 段边界
0 pure __initcall0_start
1 core __initcall1_start
7 late __initcall7_start__initcall_end

do_initcall_level() 每级:

  1. 用该级名解析 级别相关 内核参数(parse_args + level 匹配)
  2. 遍历该级段内所有 entry,调用 do_one_initcall()

2.3 do_one_initcall()

1
2
3
4
5
6
7
8
int __init_or_module do_one_initcall(initcall_t fn)
{
if (initcall_blacklisted(fn))
return -EPERM;
ret = fn();
// 检查 preempt_count、irqs_disabled,WARN
return ret;
}
  • initcall_blacklist=:跳过指定符号(需 CONFIG_KALLSYMS
  • initcall_debug:打印每个函数耗时(tracepoint 或 printk)

2.4 异步 initcall(CONFIG_INITCALL_ASYNC

  • 启动参数 initcall_nr_threads= 控制 worker 数(默认约 2 * num_online_cpus
  • 每级内部分 initcall 在 init/%d kthread worker 上并行
  • __initcallNs_start__initcallN_start 区分 sync/async 边界
  • 级末 kthread_flush_worker 保证该级完成后再进下一级

三、关键数据结构与宏

宏(init.h) 级别
pure_initcall(fn) 0
core_initcall(fn) 1
postcore_initcall(fn) 2
arch_initcall(fn) 3
subsys_initcall(fn) 4
fs_initcall(fn) 5
device_initcall(fn) 6
late_initcall(fn) 7

rootfs 相关:rootfs_initcall(在 initramfs populate 等中使用,与上述七级并列概念,见 05)。

early initcallspure..corearch subsysfs devicelatefree_initmem

四、RK3588 平台说明

RK3588 上 eMMC/UFS/PCIe/DRM/VPU 等驱动 probe 主要在 subsys / fs / device 级完成。prepare_namespace() 之前的 wait_for_device_probe()(在 do_mounts.c)会等待异步 probe,因此 initcall 慢的驱动 会直接拉长 挂根时间(见 04)。

Thunder Boot 路径上,部分内存初始化被推迟,不改变 initcall 级别顺序,但可能改变 内存分配压力 的时间分布。


五、调试与观测

1
2
3
4
# 内核命令行
initcall_debug
initcall_blacklist=some_init_func
initcall_nr_threads=4 # 若启用 CONFIG_INITCALL_ASYNC
工具 用途
dmesgcalling ... / returned 定位慢 initcall
cat /proc/interrupts 之后 确认 device 级 IRQ 注册

附录:源码索引

符号 文件
do_initcalls init/main.c ~1574
do_initcall_level ~1552
do_one_initcall ~1304
initcall_levels[] ~1345

相关02 kernel_init

根文件系统挂载机制与实现详解

根文件系统挂载机制与实现详解

源码路径rk3588/kernel-6.1/init/do_mounts.cdo_mounts_initrd.cdo_mounts_rd.c
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录linuxDoc/init/


目录


一、原理

1.1 目标

initramfs 早期环境(若存在)之后,将 真正的根文件系统 挂载到合适位置,并通过 MS_MOVE + chroot 使之成为全局 /,使后续 kernel_execve 的 init 运行在最终根上。

1.2 rootfs 与真实根

类型 说明
rootfs fs 启动时内存中的初始根(ramfs/tmpfs),用于解 cpio
块设备/NFS 根 mount_root() 挂载的最终根

init_rootfs() 可根据配置选择 rootfs 为 tmpfs(无 root= 时常见)。


二、实现方式

2.1 prepare_namespace() 流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void __init prepare_namespace(void)
{
if (root_delay) ssleep(root_delay);
wait_for_device_probe();
md_run_setup();
// 解析 saved_root_name → ROOT_DEV
if (initrd_load()) goto out;
if (ROOT_DEV == 0 && root_wait) { /* 轮询 name_to_dev_t */ }
mount_root();
out:
devtmpfs_mount();
init_mount(".", "/", NULL, MS_MOVE, NULL);
init_chroot(".");
}

要点:

  1. root_delay:故意延迟挂根
  2. wait_for_device_probe():等待驱动异步 probe(常见数秒级延迟
  3. initrd_load():传统 initrd 路径(与内置 initramfs 不同机制)
  4. rootwait:设备未就绪时轮询 name_to_dev_t
  5. mount_root():NFS/CIFS/nodev/块设备
  6. devtmpfs_mount():填充 /dev
  7. . 移到 / 并 chroot

2.2 mount_root()

  • ROOT_DEV == 0 且配置了 root_fs_namesmount_nodev_root(如 nfs4)
  • 否则 create_dev("/dev/root", ROOT_DEV) + mount_block_root

2.3 root= 解析

  • PARTUUID=:遍历块设备分区元数据 UUID(devt_from_partuuid
  • /dev/mmcblk0pNname_to_dev_t
  • mtd / ubi 前缀:直接 mount_block_root 路径名

默认挂载标志:MS_RDONLY | MS_SILENTro/rw 内核参数可改。

2.4 与 kernel_init_freeable 的衔接

仅当 ramdisk_execute_command 不可执行 时才调用 prepare_namespace();否则 initramfs 内 /init 可能已完成 switch_root。


三、关键变量与启动参数

参数/变量 作用
root= saved_root_name
rootwait 等待块设备出现
rootflags= 文件系统挂载选项
rootfstype= 强制 fs 类型列表
ro / rw 只读/读写根
root_delay= 秒级延迟

四、RK3588 平台说明

典型产品配置:

  • eMMCroot=PARTUUID=xxxxroot=/dev/mmcblk0pN,文件系统 ext4/f2fs
  • rootwait:存储控制器或 regulator 晚就绪时避免挂根失败
  • AB 分区 / AVB:用户态 updater 处理;内核层仍依赖 root= 指向当前 slot 分区

挂根慢时优先查 Waiting for root devicewait_for_device_probe 之前的驱动 probe 日志,而非仅看 mount 错误。


五、调试与观测

日志 含义
Waiting for root device rootwait 轮询中
VFS: Unable to mount root fs 类型/设备/权限错误
Failed to create /dev/root ROOT_DEV 无效
1
2
3
# 用户态(启动后)
findmnt /
lsblk -f

启动阶段可加 rootfstype=ext4debug(若文件系统支持)缩小失败面。


附录:源码索引

符号 文件
prepare_namespace do_mounts.c ~600
mount_root ~566
rootfs_fs_type ~660
init_rootfs ~666

相关05 initramfs

initramfs 与早期用户态机制与实现详解

initramfs 与早期用户态机制与实现详解

源码路径rk3588/kernel-6.1/init/initramfs.cnoinramfs.cdo_mounts_initrd.c
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录linuxDoc/init/


目录


一、原理

1.1 initramfs vs initrd

机制 实现 特点
initramfs initramfs.c,cpio 解到 rootfs 常内置进内核镜像(INITRAMFS_SOURCE
initrd do_mounts_initrd.c 旧式内存盘镜像,可能 pivot 到真实根

RK 产品多数使用 内置 initramfs 携带固件、模块或最小 /init 脚本。

1.2 早期用户态

若 rootfs 中存在可执行的 ramdisk_execute_command(默认常指向 /init),可在 prepare_namespace 之前由该程序完成存储驱动加载、挂根、switch_root


二、实现方式

2.1 解包流程(initramfs.c

  1. populate_rootfs(rootfs initcall):读取内置 cpio 或外部 blob
  2. unpack_to_rootfs:解析 cpio 项(目录、文件、符号链接、devnode)
  3. 支持 多种压缩(gzip、xz 等,取决于 decompress_method 配置)
  4. wait_for_initramfs()kernel_init_freeable 中等待解包完成

2.2 RK 硬件解压

1
2
3
#if defined(CONFIG_ROCKCHIP_THUNDER_BOOT) && defined(CONFIG_ROCKCHIP_HW_DECOMPRESS)
wait_initrd_hw_decom_done();
#endif

在 Thunder Boot + 硬件解压驱动场景下,解包前等待 HW 完成,与 CPU 软件解压路径互斥配置。详见 07

2.3 noinramfs.c

CONFIG_BLK_DEV_INITRD=n 时链接,提供空 rootfs 占位,避免缺少符号。

2.4 do_mounts_initrd.c

处理 bios/initrd 传入 的 initrd 镜像:initrd_load()prepare_namespace 中调用;若成功可能 不再 走常规 mount_rootgoto out)。


三、关键接口

符号 作用
populate_rootfs 注册解包 initcall
unpack_to_rootfs cpio + 解压主循环
wait_for_initramfs 同步点
ramdisk_execute_command 早期 init 路径(main.crdinit= 设置)
rootfs_fs_type rootfs 文件系统类型(ramfs/tmpfs)
populate_rootfs initcallunpack cpio to rootfswait_for_initramfsramdisk_execute_command 可执行?早期 /init 用户态prepare_namespace

四、RK3588 平台说明

  • 编解码固件:部分 BSP 通过 initramfs 释放到 /lib/firmware
  • 快启:HW decompress + 延迟 memblock 组合缩短 可见启动时间
  • KconfigINITRAMFS_SOURCE 指向 cpio 列表;与 CONFIG_BLK_DEV_INITRD 配合 Makefile 选 initramfs.onoinitramfs.o

五、调试与观测

问题 检查
compression method ... not configured 内核未编进对应 decompressor
initramfs 空 INITRAMFS_SOURCE、构建是否更新 cpio
早期 /init 未运行 rdinit=ramdisk_execute_commandinit_eaccess
解压 stall RK HW decompress 是否超时(dmesg 驱动日志)
1
2
# 从构建产物查看
ls -la usr/initramfs_data.cpio*

附录:源码索引

文件 说明
initramfs.c cpio 解包、populate
noinramfs.c 无 initrd 桩
do_mounts_initrd.c initrd 加载
main.c wait_for_initramfsramdisk_execute_command

相关02 kernel_init04 挂根

init_task、版本与校准机制与实现详解

init_task、版本与校准机制与实现详解

源码路径rk3588/kernel-6.1/init/init_task.cversion.ccalibrate.cMakefile
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录linuxDoc/init/


目录


一、原理

1.1 init_task

内核启动时 当前任务init_taskrest_init 创建的 kernel_init 线程最终 exec 为 PID 1,但模板来自对 init_task 的复制与演化。必须预先配置好信号、调度、namespace、cred 等静态字段。

1.2 版本字符串

UTS_VERSION 出现在 uname -a 与 Oops 信息中,由构建系统生成,区分 SMP/PREEMPT/构建时间。

1.3 calibrate_delay

历史遗留的 loops per jiffy(lpj) 用于 udelay 等粗粒度忙等;ARM64 现代平台多依赖 arch timer,但仍可能调用 calibrate_delay() 打印 BogoMIPS。


二、实现方式

2.1 init_task.c

  • init_signals / init_sighand:PID 1 级信号结构模板
  • init_taskPF_KTHREAD 起始,栈为 init_stack
  • CONFIG_THREAD_INFO_IN_TASK:thread_info 嵌入 task_struct
  • CONFIG_SHADOW_CALL_STACK:SCS 栈魔数

新进程通过 copy_process 继承/调整这些字段;不要随意改 init_task 布局(架构依赖)。

2.2 版本构建(Makefile + version.c

  1. 编译 version.o 时使用临时 utsversion-tmp.hUTS_VERSION 截断 64 字节)
  2. 最终 version-timestamp.o 使用 include/generated/utsversion.h
  3. 标志位:SMPPREEMPTPREEMPT_DYNAMICPREEMPT_RT
  4. build-version 脚本:可被 KBUILD_BUILD_VERSION 覆盖

2.3 calibrate.c

  • calibrate_delay():在 start_kernelsched_clock_init 之后调用
  • 启动参数 lpj= 可跳过校准
  • CONFIG_GENERIC_CALIBRATE_DELAY 控制是否编译 calibrate.o

ARM64 RK3588 上 BogoMIPS 数值 不代表 实际 CPU 性能,仅作兼容与日志。


三、关键数据结构

符号 文件
init_task init_task.c
init_stack 同文件或 arch
linux_banner main.c(版本横幅与 UTS_RELEASE
UTS_VERSION version.c / 生成头

四、RK3588 平台说明

  • init_task.c 平台专用分支;SMP 8 核(4+4)体现在 CONFIG_SMPUTS_VERSIONSMP 标记
  • 产品版本号常在 Android/BSP 构建脚本KBUILD_BUILD_VERSION,而非改 init_task.c
  • lpj= 在极慢串口调试时可用于 缩短 start_kernel 尾部耗时(少见)

五、调试与观测

1
2
uname -a
cat /proc/version
说明
linux_banner 启动首行 确认内核 6.1 与编译主机
BogoMIPS 行 来自 calibrate_delay
init_task 栈溢出 CONFIG_STACK_VALIDATION / KASAN 报告

附录:源码索引

文件 职责
init/init_task.c init_task
init/version.c UTS_VERSION
init/calibrate.c calibrate_delay
init/Makefile UTS_VERSION 规则

相关01 start_kernel

RK3588 启动优化与平台关联详解

RK3588 启动优化与平台关联详解

源码路径rk3588/kernel-6.1/init/main.cinit/initramfs.cmm/memblock.c
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录linuxDoc/init/


目录


一、原理

Rockchip 在 通用 Linux 启动路径 上增加少量钩子,目标集中在:

  1. 可观测性:长 bootargs 完整打印
  2. 时延:Thunder Boot 下 推迟大块 memblock→buddy硬件解压 initramfs
  3. 与 mm 协同:延迟释放在独立线程执行,不阻塞 kernel_init_freeable 关键路径上的 initcall/挂根

init/ 本身 不包含 clock、pinctrl、display 驱动;这些仍通过 initcall 在 drivers/ 注册。


二、实现方式

2.1 分段打印命令行(CONFIG_ARCH_ROCKCHIP

1
2
3
4
#ifdef CONFIG_ARCH_ROCKCHIP
const char *s = saved_command_line;
// pr_notice 首段后 pr_cont 循环输出
#endif

场景:DT chosen/bootargs 很长(多路摄像头、内存预留、调试开关)时,单次 printk 无法完整记录,影响现场分析。

2.2 延迟释放 memblock(CONFIG_ROCKCHIP_THUNDER_BOOT_DEFER_FREE_MEMBLOCK

触发点kernel_init_freeablesmp_init 之后):

1
kthread_run(defer_free_memblock, NULL, "defer_mem");

实现mm/memblock.c):

1
2
3
4
5
6
int __init defer_free_memblock(void *unused)
{
for (i = 0; i < rk_dhpi_num; i++)
nr_pages += rk_deferred_init_pages(zone, start_pfn, end_pfn);
// __free_pages_memory、totalram_pages_add ...
}

原理:引导期登记的部分物理页 不立即 全部交给 buddy,而在 defer_mem 线程 中批量 __free_pages_memory,使 start_kernel→userspace 关键路径上的 页分配初始化 更短。

linuxDoc/mm/01 中 Rockchip memblock 钩子同一特性链。

2.3 initramfs 硬件解压等待

1
2
3
#if defined(CONFIG_ROCKCHIP_THUNDER_BOOT) && defined(CONFIG_ROCKCHIP_HW_DECOMPRESS)
wait_initrd_hw_decom_done();
#endif

解压由 Rockchip 硬件引擎 完成时,CPU 侧 cpio 解析前必须同步,避免读到未完成缓冲区。

2.4 启动链总览(RK 钩子标注)

start_kernelRK: 分段 cmdlinerest_initkernel_init_freeableRK: defer_mem 线程do_initcallswait_for_initramfsRK: HW decompress waitprepare_namespaceexec init

三、配置项对照

Kconfig 影响文件
ARCH_ROCKCHIP main.c cmdline 打印
ROCKCHIP_THUNDER_BOOT 快启总开关(与 BSP 相关)
ROCKCHIP_THUNDER_BOOT_DEFER_FREE_MEMBLOCK main.c + memblock.c
ROCKCHIP_HW_DECOMPRESS initramfs.c + 驱动

具体是否启用以 RK3588 defconfig / 设备树 为准,不同产品(编解码盒、平板)可能只开子集。


四、与 SeagullYpcEncode 场景

关注点 说明
启动到编码服务 defer_mem 缩短内核态时间;用户态 systemd 启动 VPU/RGA 服务仍占主要时延
内存可见性 延迟释放期间 MemTotal 可能稍后增长;监控脚本勿在极早瞬间采内存
根文件系统 仍依赖 04root= / initramfs
安全启动 AVB/dm-verity 在 init 之前或 initramfs 完成;integrity_load_keyskernel_init_freeable 末尾

五、调试与观测

1
dmesg | grep -E 'defer_mem|defer_free|Kernel command line|initrd|populate_rootfs'
现象 方向
MemTotal 启动后跳变 defer_free_memblock 日志
initramfs 损坏 关闭 HW decompress 对比软件解压
cmdline 仍不全 检查串口工具缓冲,非内核问题

线程名defer_memps 仅在 userspace 后可见;此前用 dmesg)。


附录:关联文档

文档 内容
01 start_kernel cmdline 打印位置
05 initramfs HW decompress
linuxDoc/mm/01 memblock 延迟释放细节
linuxDoc/certs integrity_load_keys

init/ 内核启动机制与原理详解

init/ 内核启动机制与原理详解

源码路径rk3588/kernel-6.1/init/
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录linuxDoc/init/

init/ 负责内核从 架构入口进入 C 环境之后,到 用户态 PID 1(init/systemd/busybox) 运行之前的总控逻辑。体量集中在 main.c(约 1800+ 行),其余文件处理根挂载、initramfs、初始任务与版本信息。


目录


一、子系统职责

职责 主要实现
早期单线程初始化总控 start_kernel()
创建 init 线程与 kthreadd rest_init()
SMP 就绪后驱动与子系统 initcall do_basic_setup()do_initcalls()
内置 initramfs 解包 initramfs.c
真实根文件系统挂载 do_mounts.cprepare_namespace()
执行用户态 init kernel_init()run_init_process()
释放 __init 段、只读内核 free_initmem()mark_readonly()
0 号任务静态模板 init_task.c

不在 init/setup_arch()、设备树解析、时钟/电源驱动主体 → arch/drivers/


二、启动阶段划分

阶段 0: arch阶段 1: start_kernel阶段 2: rest_init阶段 3: kernel_init_freeable阶段 4: kernel_init 收尾head.S → start_kernel 之前setup_arch mm_init sched_init IRQ 时间console cgroup vfs_cacheskernel_init 线程kthreaddboot CPU idlesmp_init do_initcallsinitramfs prepare_namespacefree_initmem SYSTEM_RUNNINGkernel_execve init

2.1 start_kernel(仍多为 __init,关中断早期)

  • 架构:setup_archbuild_all_zonelistspage_alloc_initmm_init
  • 参数:parse_early_paramparse_argsinit= 等)
  • 调度/RCU/IRQ/时间:sched_initinit_IRQtime_inithrtimers_init
  • 开中断后:console_initfork_initvfs_caches_initcgroup_init
  • 结尾:arch_call_rest_init()rest_init()(不再返回)

详见 01

2.2 rest_init + kernel_init

  • user_mode_thread(kernel_init):将来 exec 成用户态,目标 pid 1
  • kernel_thread(kthreadd):内核线程工厂
  • boot 线程:schedule_preempt_disabled()cpu_idle
  • kernel_initkernel_init_freeable() → 释放 init 内存 → 按序尝试 exec init

详见 02

2.3 initcall 与挂根

  • do_pre_smp_initcalls:linker 段 __initcall_start .. __initcall0_start
  • do_initcalls:pure → core → … → late(七级)
  • wait_for_initramfs()console_on_rootfs()prepare_namespace() 或早期 initramfs 脚本

详见 030405


三、与相邻子系统边界

子系统 与 init 的衔接点
arch/arm64 setup_arch 填充 memblock、cmdline、SMP 信息;start_kernel 之前由 head.S 进入
mm mm_initpage_alloc_init;RK defer_free_memblocksmp_init 后由 main.c 拉起
sched sched_initstart_kernel;完整 SMP 调度在 sched_init_smpkernel_init_freeable
drivers 大量 device_initcall / module_init 映射到 initcall device
VFS vfs_caches_init(早期+晚期)、prepare_namespace 挂根
certs integrity_load_keys()kernel_init_freeable 末尾

四、RK3588 平台说明

特性 位置 作用
长命令行分段打印 main.c + CONFIG_ARCH_ROCKCHIP 避免单次 printk 截断 bootargs
Thunder Boot 延迟 memblock main.c + mm/memblock.c 后台线程释放大块内存给 buddy,缩短关键路径
initrd 硬件解压等待 initramfs.c 与快启、HW decompress 驱动配合

产品常见启动参数:root=PARTUUID=...rootwaitinit=/sbin/initro/rw

详见 07


五、总结

init/“内核活起来” 的调度中心:不实现具体设备驱动,但决定 何时 跑 initcall、何时 等设备 probe、何时 挂根并 exec 用户态。RK3588 定制点少而关键,主要影响 启动日志内存交给伙伴分配器的时机


功能组专题文档

编号 文档
01 start_kernel早期初始化机制与实现详解.md
02 rest_init与kernel_init机制与实现详解.md
03 initcall驱动初始化机制与实现详解.md
04 根文件系统挂载机制与实现详解.md
05 initramfs与早期用户态机制与实现详解.md
06 init_task版本与校准机制与实现详解.md
07 RK3588启动优化与平台关联详解.md