一个 5 天学习 Linux Kernel 主要原理 的详细内容,目标是快速理解内核核心机制、定位问题、并能结合实际日志进行调试 。内容循序渐进,适合 SLES、RHEL、Ubuntu 等发行版,侧重原理 + 实践。
下面是第一部分,含概念讲解、动手实验(跨发行版命令给到)、常见输出示例、练习与测试、FAQ 与排错提示。建议在虚拟机/测试机上操作。。
Day 1:Linux 内核基础与架构总览(实战版)
一、课前准备(10 分钟)
-
建议环境:任一常见发行版(Ubuntu/Debian、RHEL/CentOS/Rocky、openSUSE/SLES)。
-
需要
root
或sudo
权限。 -
安装常用工具:
bash# Debian/Ubuntu sudo apt update && sudo apt install -y build-essential git gcc make pkg-config \ linux-tools-$(uname -r) linux-tools-common linux-headers-$(uname -r) # RHEL/CentOS/Rocky(先启用 CodeReady Builder/PowerTools 视版本而定) sudo dnf groupinstall -y "Development Tools" sudo dnf install -y kernel-devel kernel-tools kernel-tools-libs # openSUSE/SLES sudo zypper refresh sudo zypper install -y gcc make kernel-default-devel kernel-source \ kernel-firmware-tools
1.1 内核基础概念(40 分钟)
1)什么是 Linux 内核,用户态 vs 内核态
- 内核(Kernel):操作系统的"发动机",负责进程调度、内存、文件系统、驱动、网络等。
- 用户态(User space):应用程序运行区域(如 bash、Python、Nginx)。
- 内核态(Kernel space):内核代码和驱动运行的特权区域。
- 系统调用(syscall) :用户态进入内核态的"门"(例:
read(2)
,write(2)
,open(2)
)。
直观比喻:用户态像"车内的按钮",内核态是"发动机舱"。按钮发出指令(系统调用),发动机执行实际操作(访问磁盘/网卡/内存)。
2)内核主要功能模块(认识地图)
- 进程管理(PM):调度算法、上下文切换、优先级。
- 内存管理(MM):虚拟内存、页表、分配器(buddy/SLAB/SLUB)、swap。
- VFS(虚拟文件系统):统一抽象,支持 ext4/xfs/btrfs 等。
- 设备驱动(Drivers):与硬件对接,模块化可按需加载。
- 网络栈(NET):socket、TCP/IP 协议栈、路由、netfilter。
- 系统调用(Syscalls):提供标准接口给用户态。
3)分层示意(记忆用)
diff
+---------------------------+
| 用户态 (glibc) |
+---------------------------+
| 系统调用接口 (Syscall) |
+---------------------------+
| PM | MM | VFS | NET | ...|
+---------------------------+
| 设备驱动 / 总线层 |
+---------------------------+
| 硬件抽象层 (HAL) |
+---------------------------+
| 硬件 |
+---------------------------+
4)快速动手:用 strace
看系统调用(感知"门")
bash
sudo apt install -y strace 2>/dev/null || true
strace -o /tmp/ls.strace ls >/dev/null 2>&1
head -n 10 /tmp/ls.strace
观察到大量 openat
, read
, write
, mmap
, close
:这就是用户态向内核发起的系统调用路径。
1.2 Kernel Release 与配置(40 分钟)
1)版本命名与分支
-
语义 :
X.Y.Z
X
主版本(架构性变更)Y
次版本(功能迭代,当前"主线 mainline/stable"一般是 6.y)Z
修订(Bug/安全修复)
-
分支类型:
- mainline:最新开发主线(Linus 合并窗口)
- stable:从主线回传稳定修复(6.y.z)
- LTS:长期维护(数年维护)
- 发行版内核:带厂商补丁(SUSE、Red Hat、Ubuntu 等)
结论:生产上多选 发行版 LTS;内核新特性/驱动调试可用 mainline/stable。
2)配置与编译流程(概念 + 演示)
Day 1 以"了解流程"为主,真编译可在 Day 4/5 深入。
基本流程:
bash
make menuconfig # 配置内核选项(图形化菜单)
make -j$(nproc) # 并行编译内核与模块
sudo make modules_install # 安装模块到 /lib/modules/<ver>
sudo make install # 安装内核/vmlinuz/initramfs/引导项
更安全的 Day 1 实战:编译一个"Hello 内核模块"(不改生产内核)
-
新建源码目录:
bashmkdir -p ~/khello && cd ~/khello cat > hello.c <<'EOF' #include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("GPL"); static int __init hello_init(void){ pr_info("hello: module loaded\n"); return 0; } static void __exit hello_exit(void){ pr_info("hello: module unloaded\n"); } module_init(hello_init); module_exit(hello_exit); EOF cat > Makefile <<'EOF' obj-m += hello.o KDIR ?= /lib/modules/$(shell uname -r)/build all: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: $(MAKE) -C $(KDIR) M=$(PWD) clean EOF make sudo insmod hello.ko dmesg -T | tail -n 5 sudo rmmod hello dmesg -T | tail -n 5
-
你将看到
hello: module loaded/unloaded
的内核日志。这一步让你真正在内核态执行了代码,但对系统风险很小。
3)/boot 关键文件详解(配合命令认识)
vmlinuz-<ver>
:压缩的内核映像(可引导)。initramfs
/initrd
:早期用户空间(驱动、挂载根分区等的最小系统)。System.map-<ver>
:内核符号表(地址到符号名映射)。config-<ver>
:此内核编译时采用的.config
(可以对比选项)。
快速查看:
bash
ls -lh /boot
grep -E 'CONFIG_INITRAMFS|CONFIG_MODULES' /boot/config-$(uname -r) || true
file /boot/vmlinuz-$(uname -r)
1.3 基础调试命令(40 分钟)
命令/路径 | 核心用途与常用技巧 | ||
---|---|---|---|
uname -r |
查看运行的内核版本;对比 /boot 下版本是否匹配引导项。 |
||
dmesg -T |
启动与内核日志;-T 显示可读时间,配合 grep -i error 。 |
||
journalctl -k |
仅看内核日志;-b 只看本次开机,-b -1 看上次开机。 |
||
lsmod |
当前加载的内核模块;`lsmod | sort -k2 -nr | head` 看引用计数高的模块。 |
modinfo <模块名> |
查看模块来源、参数、别名(如 modinfo e1000e )。 |
||
sysctl |
查看/调整运行时内核参数;`sysctl -a | grep vm.swappiness`。 |
演示命令(复制即用):
bash
echo "版本:" && uname -r
echo -e "\n最近内核日志(末尾10行):" && dmesg -T | tail
echo -e "\n上一轮启动的内核日志错误统计:" && journalctl -k -b -1 -p 3 --no-pager 2>/dev/null | wc -l || true
echo -e "\n已加载模块 Top10(按依赖计数):" && lsmod | sort -k2 -nr | head
echo -e "\n模块信息示例(nvme):"; modinfo nvme_core 2>/dev/null | sed -n '1,20p'
echo -e "\n当前 vm.swappiness:" && sysctl vm.swappiness
修改一个内核参数(vm.swappiness
示例)
该参数控制内存压力下使用 swap 的积极程度(0~100)。
-
临时修改(重启失效):
bashsudo sysctl vm.swappiness=10 sysctl vm.swappiness
-
永久生效(创建自定义配置):
bashecho 'vm.swappiness = 10' | sudo tee /etc/sysctl.d/99-local-tuning.conf sudo sysctl --system
练习(含参考做法)
-
查找当前系统内核版本
bashuname -r
参考输出:
6.8.0-xyz-generic
-
找出系统中加载的所有驱动模块
bashlsmod | less # 想要统计数量 lsmod | tail -n +2 | wc -l
-
修改一个内核参数(
vm.swappiness
)并验证bashsudo sysctl vm.swappiness=5 sysctl vm.swappiness # 持久化见上文 /etc/sysctl.d/99-local-tuning.conf
-
(加分)加载/卸载 hello 模块并观察 dmesg
- 见 1.2 的"Hello 模块"实验。
Day 1 作业与测试
A. 画图题(开卷)
- 画出你理解的 用户态 → 系统调用 → 内核模块 → 驱动 → 硬件 的路径图,并标注: PM / MM / VFS / NET 分别处在什么位置、谁与谁交互。
B. 日志分析
-
运行:
bashdmesg -T | egrep -i 'error|fail|warn' | tail -n 30
回答:本机启动过程中是否有设备初始化失败?是哪个驱动/总线报的?
C. 小测(判断/简答)
-
为什么需要 initramfs? 要点:为根文件系统挂载前提供必要驱动/脚本(例如存储/RAID/解密),完成早期用户空间初始化。
-
Linux 内核能直接运行吗? 要点 :内核需要引导加载器(GRUB 等)加载到内存并跳转执行,且通常需要 initramfs 辅助完成挂载后进入
/sbin/init
(或 systemd)才形成完整系统。 -
用户态与内核态的切换如何发生? 要点 :通过系统调用(软中断/
syscall
指令)或中断/异常陷入内核,返回用sysret/iret
等。
(可选)给出
strace ls
的几条系统调用,说明其作用。
FAQ(Day 1 常见困惑)
Q1:发行版自带内核已经很好了,为什么还要学编译? A:生产大多使用发行版内核;但理解编译流程/配置选项有助于定制驱动、调优、调试问题(如需要开启某个跟踪功能、实验新驱动)。
Q2:vmlinuz
与 bzImage
、zImage
有什么关系? A:不同历史/架构下命名略有差异,本质都是可引导的压缩内核镜像 ;发行版通常命名为 vmlinuz-<ver>
。
Q3:System.map
有什么用? A:保存符号名到地址的映射,便于内核崩溃分析、调试(如根据地址找函数名)。
Q4:改 sysctl
会不会危险? A:大多可安全实验,建议逐步调整并记录;涉及网络、内存回收的参数要先理解含义(如 vm.overcommit_*
)。
Q5:dmesg
与 journalctl -k
有何区别? A:dmesg
读的是当前内核环形缓冲区 ;journalctl -k
从 systemd-journald 的持久/易检索日志查看内核日志 ,可跨重启检索(-b -1
查看上次启动)。
常见问题排错(Cheatsheet)
-
make
编译模块失败 : 确认已安装kernel headers / kernel-devel
,并与uname -r
匹配。 -
insmod
报 "invalid module format" : 模块与当前运行内核版本不匹配(modinfo hello.ko
查看vermagic
)。 -
dmesg
没有时间戳 : 用dmesg -T
,或看journalctl -k
。 -
sysctl
持久化不生效 : 确认配置文件在/etc/sysctl.conf
或/etc/sysctl.d/*.conf
,执行sudo sysctl --system
应用并观察无报错。
课后延伸(为 Day 2/3 埋伏笔)
- 试着用
perf list
和perf top
看内核热点符号名(需要安装 perf,且版本匹配内核)。 - 初步浏览
/proc
:cat /proc/cpuinfo
、/proc/meminfo
、/proc/modules
、/proc/sys/vm/swappiness
。
到这里,你已经建立起 Linux 内核的"地图感",并完成了一次最小内核模块的实战 、掌握了日志和基础调参工具。 下一天(Day 2)我们将深入 进程管理与 CFS 调度 ,用
top/pidstat/perf/ftrace
做性能与可观测性实操。