4、内核模块裁剪(上):文件系统驱动与网络协议栈裁剪
好,咱们进入内核裁剪的实战环节。这一章我先带你搞定两个大头——文件系统驱动和网络协议栈。为什么先说它们?因为这两块是内核里体积最大、但也是很多嵌入式场景下最容易被过度裁剪的部分。
我刚开始做裁剪时,总想着“多留点总没错”,结果编译出来的内核镜像比原版还大。后来被老板骂了一顿才明白——裁剪的核心不是“留什么”,而是“砍什么”。你想想看,一个只跑 ext4 的 IoT 设备,留着 XFS 和 btrfs 的驱动干嘛?占地方不说,还增加安全攻击面。
核心原则:只保留目标系统实际使用的文件系统和网络协议。不要“以防万一”地保留未使用的功能。
4.1 文件系统驱动裁剪
文件系统驱动是内核里最占地方的模块之一。一个完整的 ext4 驱动大概 300KB~500KB,btrfs 更夸张,能到 1MB 以上。如果你的设备只用一种文件系统,其他全是冗余。
4.1.1 常见文件系统对比
| 文件系统 | 典型大小 | 适用场景 | 裁剪建议 |
|---|---|---|---|
| ext4 | ~400KB | 通用 Linux、嵌入式 | 保留(最常用) |
| btrfs | ~1.2MB | 桌面/服务器、快照需求 | 可裁剪(嵌入式极少用) |
| XFS | ~500KB | 大文件存储、高性能场景 | 可裁剪(除非需要) |
| F2FS | ~300KB | NAND Flash 设备 | 按需保留 |
| squashfs | ~100KB | 只读根文件系统 | 推荐保留(体积小) |
我个人习惯是:先确定目标设备的存储介质和根文件系统类型。比如用 NAND Flash 的设备,我一般只保留 ext4 和 squashfs;如果是 SD 卡启动,可能再加个 F2FS。其他的,砍掉。
4.1.2 裁剪操作步骤
在 make menuconfig 中,文件系统驱动位于:
File systems --->
[ ] Btrfs filesystem support
[ ] XFS filesystem support
[ ] F2FS filesystem support
[ ] Ext4 filesystem support (保留)
[ ] Squashfs 4.0 filesystem support (推荐保留)
嗯,这里要注意:不要直接取消 ext4,除非你确定你的根文件系统不是 ext4。我曾经见过一个同事,为了省空间把 ext4 关了,结果内核启动到一半就 panic 了——因为根分区就是 ext4 格式的。
⚠ 重要:裁剪文件系统驱动前,务必确认以下三点:
- 根文件系统(rootfs)使用的文件系统类型
- 数据分区使用的文件系统类型
- 是否有只读文件系统(如 squashfs)需求
建议先用 df -T 查看当前挂载的文件系统类型。
4.1.3 实战案例:裁剪 ext4 子功能
即使你保留了 ext4,它内部也有很多子功能可以裁剪。比如:
- ext4 加密:如果你的设备不需要文件级加密,可以关掉
- ext4 配额:嵌入式设备很少用配额功能
- ext4 日志:如果设备可以容忍断电丢失数据,可以关掉 journal
在 menuconfig 中,这些选项通常在:
File systems --->
[*] Ext4 filesystem support
[ ] Ext4 encryption
[ ] Ext4 quota support
[ ] Ext4 POSIX Access Control Lists
[ ] Ext4 Security Labels
我做过一个项目,设备只用 ext4 做只读根文件系统。我把加密、配额、ACL 全关了,ext4 驱动从 420KB 降到了 280KB。省了 30% 的空间。
💡 小技巧:如果你不确定某个子功能是否需要,可以先保留,编译后用 size 命令查看模块大小。然后关掉再编译一次,对比差异。这样你就知道每个子功能占了多少空间。
4.2 网络协议栈裁剪
网络协议栈是另一个“体积大户”。完整的 IPv4+IPv6+TCP/UDP+Netfilter 加起来,轻松超过 1MB。但很多嵌入式设备只需要最基本的网络功能。
4.2.1 IPv4 vs IPv6
说实话,现在 IPv6 的普及率还没那么高。很多嵌入式设备只跑在内网,用 IPv4 就够了。IPv6 协议栈大概占 200KB~300KB,如果你不需要,直接关掉。
在 menuconfig 中:
Networking support --->
Networking options --->
[*] TCP/IP networking
[ ] IPv6 protocol (关掉)
我曾经在一个智能家居项目里,设备只需要通过 IPv4 连接本地服务器。我把 IPv6 关了,内核体积直接少了 250KB。客户验收时完全没发现问题。
4.2.2 TCP/UDP 裁剪
TCP 和 UDP 是网络通信的基础,一般不能全关。但你可以裁剪它们的子功能:
| 子功能 | 典型大小 | 裁剪条件 |
|---|---|---|
| TCP 拥塞控制算法 | ~50KB | 只保留 cubic,其他可关 |
| TCP 窗口缩放 | ~10KB | 低带宽场景可关 |
| UDP Lite | ~20KB | 极少使用,可关 |
| IP 多播 | ~30KB | 不需要多播时关掉 |
在 menuconfig 中:
Networking support --->
Networking options --->
[ ] IP: multicasting (关掉)
[ ] IP: UDP Lite (关掉)
TCP: advanced congestion control --->
[ ] BIC TCP
[ ] Westwood+
[*] CUBIC TCP (只保留这个)
注意:TCP 拥塞控制算法至少保留一个(通常是 cubic),否则 TCP 连接会出问题。我见过有人把所有算法都关了,结果网络完全不通。
4.2.3 Netfilter 裁剪
Netfilter 是 Linux 的防火墙框架,功能非常强大,但也很占空间。完整的 Netfilter 模块大概 300KB~500KB。如果你的设备不需要防火墙功能,可以直接关掉。
在 menuconfig 中:
Networking support --->
Networking options --->
[ ] Network packet filtering framework (Netfilter) (关掉)
但要注意:关掉 Netfilter 后,iptables、nftables 等工具都无法使用。如果你的设备需要做 NAT、端口转发、包过滤,那就不能关。
我个人的经验是:对于纯数据采集类的 IoT 设备,Netfilter 基本用不上。设备只负责发送数据,不需要做任何网络过滤。这种情况下,关掉 Netfilter 能省下不少空间。
⚠ 避坑指南:我曾经在一个项目里关掉了 Netfilter,结果发现设备无法通过 DHCP 获取 IP 地址。排查了半天才发现,DHCP 客户端依赖 Netfilter 的某些功能。所以裁剪前一定要测试网络基本功能是否正常。
4.3 裁剪效果验证
裁剪完成后,建议用以下方法验证效果:
- 对比内核镜像大小:裁剪前后分别编译,用
ls -lh vmlinux查看 - 检查模块列表:用
lsmod查看加载的模块,确认不需要的模块没有被加载 - 功能测试:挂载文件系统、建立网络连接,确保核心功能正常
我一般会写一个简单的测试脚本,自动执行这些验证步骤。毕竟手动检查太容易漏了。
💡 建议:裁剪不是一次性的工作。建议先做一次“激进裁剪”——只保留最核心的功能,然后逐步添加。这样你能清楚地知道每个模块对系统的影响。