Posted in

Linux 内核裁剪:NLS 模块详解

Linux 内核中的 nls_cp*.ko 不是「驱动」,而是 NLS 编码表模块。本文详细说明其作用和裁剪策略。

NLS 是什么?

NLS = Native Language Support(本地语言支持),是 Linux 内核对不同字符编码/代码页(Code Page)的翻译支持层。它主要服务于 FAT / VFAT / exFAT / ISO9660 等「文件名带非 UTF-8 编码」的文件系统,让内核能把磁盘上存储的 legacy 编码与内核使用的 UTF-8/Unicode 之间进行转换。

nls_cp*.ko 不是硬件驱动,而是字符编码转换表的可加载内核模块

nls_cp*.ko 对应什么?

cp = Code Page(Windows/DOS 体系代码页)

模块名 对应编码 典型使用场景
nls_cp437.ko IBM Code Page 437(美式 DOS/OEM) 最基础的 OEM 字符集,VFAT 默认短文件名
nls_cp850.ko CP850(西欧 DOS) 西欧多语言 DOS
nls_cp936.ko CP936(GBK 简体中文) 简体中文 Windows 的 FAT 卷常见
nls_cp950.ko CP950(Big5 繁体中文) 繁体中文环境
nls_cp1250.ko Windows-1250(中东欧) 波兰、捷克等
nls_cp1251.ko Windows-1251(西里尔) 俄语等
nls_cp1252.ko Windows-1252(西欧 Latin-1 变体) 西欧 Windows 最常见
nls_cp932.ko CP932 / Shift-JIS(日文) 日文 Windows

这些 .ko 本质上就是把一张「源编码 → Unicode (UTF-16)」的映射表编进内核模块,供 NLS 子系统查表用。

为什么 FAT/VFAT 特别需要它?

FAT 的文件名历史上有两副面孔:

  1. 短文件名(8.3):用 code page(如 CP437 / CP936)编码字节
  2. 长文件名(LFN):规范里说是 UTF-16LE,但老实现/老介质/老参数组合仍然跟 code page 关联

挂载 VFAT 时常看到:

mount -t vfat /dev/sdb1 /mnt -o codepage=936,iocharset=utf8
  • codepage= → 选一个 nls_cp*.ko(处理短文件名/8.3 的解码基准)
  • iocharset= → 选一个 NLS 作为「输出端字符集」(常见就是 utf8,对应 nls_utf8.ko

内核在内部走的是:disk bytes (CP) → Unicode → output charset 的转换路径。

最少保留组合(最稳方案)

绝对底座

  • nls_base(通常编进 vmlinux,不一定以独立 .ko 出现)
  • nls_utf8 / nls_utf8.ko

没有 nls_base + utf8,FAT/VFAT 常用挂载路径很容易出问题。

最少 Code Page 模块

至少保留这两个就覆盖了 90% 现实情况:

  • nls_cp437.ko —— VFAT/FAT 的「默认/兜底 codepage」(短文件名 8.3 解码)。内核在很多地方把它当 fallback,裁掉它经常换来一堆 warning 或直接失败
  • nls_cp936.ko(GBK/简体中文)—— 中国大陆常见存量 U 盘/老设备格式化出来的 FAT,很可能用的是 cp936(GBK)

推荐最小可工作组合

nls_base          (builtin)
nls_utf8
nls_cp437
nls_cp936         # 中国环境基本要它

如果还要支持其他区域老 U 盘:

  • 西欧常见:nls_cp850nls_cp1252
  • 日文:nls_cp932
  • 俄文:nls_cp1251

狠裁方案:两条安全线

方案 A:只求「能挂上不报错」

  • nls_base + nls_utf8 + nls_cp437
  • 其它 nls_cp*.ko 可砍
  • 挂载参数统一化:
mount -t vfat ... -o codepage=437,iocharset=utf8

可能牺牲短文件名可读性(中文文件名可能乱码)。

方案 B:确定所有 FAT 来源都是「现代 Windows 写入」

  • 只留 nls_base + nls_utf8 + nls_cp437(cp437 仍是 fallback,不建议真删)
  • CONFIG_NLS_CODEPAGE_437 编为 builtin(而非 module),其余 CONFIG_NLS_CODEPAGE_* 关掉
  • 做一次全量挂载回归测试

一句话总结

nls_cp*.ko 是 Linux 内核的 Code Page 字符编码映射表模块,属于 NLS(Native Language Support)子系统,用来让 FAT/VFAT/exFAT/ISO9660 等文件系统正确把磁盘上的 legacy 编码文件名翻译成内核认识的 Unicode/UTF-8。它不是硬件驱动,而是「编码翻译表的可加载插件」。

如果你在排查某个设备/U 盘挂载时出现 FAT: codepage xxx not foundiocharset not found 这类报错,按上面的最小组合把对应的 nls_cp*.ko 编译进去就能解决。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注