5 天学习 Linux Kernel 主要原理 | Day 1:Linux 内核基础与架构总览

一个 5 天学习 Linux Kernel 主要原理 的详细内容,目标是快速理解内核核心机制、定位问题、并能结合实际日志进行调试 。内容循序渐进,适合 SLES、RHEL、Ubuntu 等发行版,侧重原理 + 实践

下面是第一部分,含概念讲解、动手实验(跨发行版命令给到)、常见输出示例、练习与测试、FAQ 与排错提示。建议在虚拟机/测试机上操作。。


Day 1:Linux 内核基础与架构总览(实战版)

一、课前准备(10 分钟)

  • 建议环境:任一常见发行版(Ubuntu/Debian、RHEL/CentOS/Rocky、openSUSE/SLES)。

  • 需要 rootsudo 权限。

  • 安装常用工具:

    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 内核模块"(不改生产内核)

  • 新建源码目录:

    bash 复制代码
    mkdir -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)。

  • 临时修改(重启失效):

    bash 复制代码
    sudo sysctl vm.swappiness=10
    sysctl vm.swappiness
  • 永久生效(创建自定义配置):

    bash 复制代码
    echo 'vm.swappiness = 10' | sudo tee /etc/sysctl.d/99-local-tuning.conf
    sudo sysctl --system

练习(含参考做法)

  1. 查找当前系统内核版本

    bash 复制代码
    uname -r

    参考输出:6.8.0-xyz-generic

  2. 找出系统中加载的所有驱动模块

    bash 复制代码
    lsmod | less
    # 想要统计数量
    lsmod | tail -n +2 | wc -l
  3. 修改一个内核参数(vm.swappiness)并验证

    bash 复制代码
    sudo sysctl vm.swappiness=5
    sysctl vm.swappiness
    # 持久化见上文 /etc/sysctl.d/99-local-tuning.conf
  4. (加分)加载/卸载 hello 模块并观察 dmesg

    • 见 1.2 的"Hello 模块"实验。

Day 1 作业与测试

A. 画图题(开卷)

  • 画出你理解的 用户态 → 系统调用 → 内核模块 → 驱动 → 硬件 的路径图,并标注: PM / MM / VFS / NET 分别处在什么位置、谁与谁交互。

B. 日志分析

  • 运行:

    bash 复制代码
    dmesg -T | egrep -i 'error|fail|warn' | tail -n 30

    回答:本机启动过程中是否有设备初始化失败?是哪个驱动/总线报的?

C. 小测(判断/简答)

  1. 为什么需要 initramfs? 要点:为根文件系统挂载前提供必要驱动/脚本(例如存储/RAID/解密),完成早期用户空间初始化。

  2. Linux 内核能直接运行吗? 要点 :内核需要引导加载器(GRUB 等)加载到内存并跳转执行,且通常需要 initramfs 辅助完成挂载后进入 /sbin/init(或 systemd)才形成完整系统。

  3. 用户态与内核态的切换如何发生? 要点 :通过系统调用(软中断/syscall 指令)或中断/异常陷入内核,返回用 sysret/iret 等。

(可选)给出 strace ls 的几条系统调用,说明其作用。


FAQ(Day 1 常见困惑)

Q1:发行版自带内核已经很好了,为什么还要学编译? A:生产大多使用发行版内核;但理解编译流程/配置选项有助于定制驱动、调优、调试问题(如需要开启某个跟踪功能、实验新驱动)。

Q2:vmlinuzbzImagezImage 有什么关系? A:不同历史/架构下命名略有差异,本质都是可引导的压缩内核镜像 ;发行版通常命名为 vmlinuz-<ver>

Q3:System.map 有什么用? A:保存符号名到地址的映射,便于内核崩溃分析、调试(如根据地址找函数名)。

Q4:改 sysctl 会不会危险? A:大多可安全实验,建议逐步调整并记录;涉及网络、内存回收的参数要先理解含义(如 vm.overcommit_*)。

Q5:dmesgjournalctl -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 listperf top 看内核热点符号名(需要安装 perf,且版本匹配内核)。
  • 初步浏览 /proccat /proc/cpuinfo/proc/meminfo/proc/modules/proc/sys/vm/swappiness

到这里,你已经建立起 Linux 内核的"地图感",并完成了一次最小内核模块的实战 、掌握了日志和基础调参工具。 下一天(Day 2)我们将深入 进程管理与 CFS 调度 ,用 top/pidstat/perf/ftrace 做性能与可观测性实操。

相关推荐
哈喽H5 小时前
centos系统的linux环境不同用户,环境变量不同如何配置?
linux·centos
Doris_LMS5 小时前
在Linux系统中安装Jenkins(保姆级别)
java·linux·jenkins·ci
轻松Ai享生活5 小时前
用户自定义的 systemd unit 文件应该放在哪里?
linux
万添裁5 小时前
1.Linux:命令提示符,history和常用快捷键
linux·运维·服务器
轻松Ai享生活5 小时前
怎么在5天内将Linux systemd学精通
linux
悲伤小伞7 小时前
Linux_网络基础
linux·服务器·c语言·网络
KingRumn7 小时前
Linux ARP老化机制/探测机制/ip neigh使用
linux·网络·tcp/ip
学生董格8 小时前
[嵌入式embed][Qt]Qt5.12+Opencv4.x+Cmake4.x_用Qt编译linux-Opencv库 & 测试
linux·qt·opencv
我要打打代码8 小时前
wpf触发器
java·linux·wpf