4、内核模块裁剪(上):文件系统驱动与网络协议栈裁剪

好,咱们进入内核裁剪的实战环节。这一章我先带你搞定两个大头——文件系统驱动和网络协议栈。为什么先说它们?因为这两块是内核里体积最大、但也是很多嵌入式场景下最容易被过度裁剪的部分。

我刚开始做裁剪时,总想着“多留点总没错”,结果编译出来的内核镜像比原版还大。后来被老板骂了一顿才明白——裁剪的核心不是“留什么”,而是“砍什么”。你想想看,一个只跑 ext4 的 IoT 设备,留着 XFS 和 btrfs 的驱动干嘛?占地方不说,还增加安全攻击面。

核心原则:只保留目标系统实际使用的文件系统和网络协议。不要“以防万一”地保留未使用的功能。

内核模块裁剪总览(第4章) 文件系统驱动裁剪 ext4 保留(常用) btrfs 可裁剪 XFS 可裁剪 F2FS 按需保留 → 裁剪后体积减少约 40%~60% → 仅保留目标设备使用的文件系统 网络协议栈裁剪 IPv4 保留(常用) IPv6 可裁剪 TCP/UDP 保留 Netfilter 按需裁剪 → 裁剪后体积减少约 30%~50% → 仅保留实际使用的协议族 ⚠ 裁剪前务必确认目标系统的实际需求,避免功能缺失 建议先做最小系统验证,再逐步裁剪

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 裁剪效果验证

裁剪完成后,建议用以下方法验证效果:

  1. 对比内核镜像大小:裁剪前后分别编译,用 ls -lh vmlinux 查看
  2. 检查模块列表:用 lsmod 查看加载的模块,确认不需要的模块没有被加载
  3. 功能测试:挂载文件系统、建立网络连接,确保核心功能正常

我一般会写一个简单的测试脚本,自动执行这些验证步骤。毕竟手动检查太容易漏了。

💡 建议:裁剪不是一次性的工作。建议先做一次“激进裁剪”——只保留最核心的功能,然后逐步添加。这样你能清楚地知道每个模块对系统的影响。