1. 先搞明白:Longterm release kernel 到底是什么
你可能在 kernel.org 首页见过那个表格,里面有个分支叫 longterm,后面跟着一串版本号,比如 6.1、5.15、5.10,下面写着 "EOL: Dec, 2026" 或者类似的日期。很多人扫一眼就过去了,以为它跟 mainline 或者 stable 没本质区别,无非就是维护久一点。这个理解方向对,但远远不够。
Longterm release kernel,一般直接叫 LTS(Long Term Support)内核,是 Linux 内核社区专门挑出来做超长周期维护的版本。普通的内核版本,比如 6.13、6.14,mainline 发出来之后,stable 分支大概只会维护六到八个礼拜。也就是说,你这个版本如果没跟上节奏,过了两个月再想修 bug、打安全补丁,上游基本就不管了,你得自己想办法往回移植补丁,或者干脆升到新版本。而 LTS 内核不一样,它的维护周期短则两年,长则六六年以上。
这中间的区别不仅仅是用多久的问题,而是整条产品维护策略的根基。特别是做嵌入式、做 Android 设备、做服务器、做网关这一类场景的,选内核版本跟普通开发者选一个 Linux 发行版完全是两种逻辑。普通桌面用户追新,出什么用什么,坏了重装;产品项目不能这么搞——你总不能因为上游停止维护了,就让卖出去的几万台设备集体换内核吧?
我记得有一次跟一个做工业网关的哥们儿聊天,他说他们的产品用了一个很旧的内核版本,刚开始选型的时候看着挺新,结果项目周期拖了两年,卖出去之后第三年,内核上游早就没人管了。期间爆出几个 CVE(通用漏洞披露),他们只能自己找补丁,手动移植到老内核上,那叫一个痛苦。所以后来他们一律改成 LTS 内核,起码在上游维护周期内,安全补丁和关键 bug 修复是有人管着的,团队要做的只是跟着 LTS 更新节奏走,工作量和风险都小很多。
LTS 到底解决了什么问题?一句话:让产品团队在选内核时,不需要赌“这个版本以后会不会有人管”,而是明确知道这个版本会管到哪一天。
这也就是为什么 kernel.org 上长期维护版本的列表永远是嵌入式、移动、服务器领域的第一参考。你现在去搜 Linux 内核相关的话题,除了那些追新版本的开发动态,真正有决策价值的信息全是围绕 LTS 版本展开的。包括最近频繁被讨论的 Android kernel 选型、高通 CAF kernel 基线,底层都离不开某个 LTS 版本做底座。后面我会详细拆。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. LTS 版本是怎么挑出来的
很多人以为 LTS 版本是内核社区按固定时间节奏发布的,比如“每年固定出一个 LTS”,其实不对。LTS 版本的挑选有一套自己的逻辑,而且充满了“人”的因素,不是纯自动化的流程。
2.1 谁能决定哪个版本成为 LTS
LTS 版本的拍板人不是某个委员会,而是内核稳定版维护者,目前是 Greg Kroah-Hartman(江湖人称 Greg KH)。他在内核邮件列表上发布消息,说“我打算把 6.1 作为 longterm 版本,请大家确认”,然后经过一段时间的反馈,最后宣布确认。这个机制下来有很强的个人判断成分——既要看这个版本是不是足够稳定,也要看是否有足够的维护者和企业愿意跟进。
为什么要看“有没有人愿意跟进”?因为 LTS 版本后续的补丁维护工作虽然是 Greg KH 主导,但实际很多补丁要依赖各个子系统的维护者、发行版团队、芯片厂商一起来投入。如果一个版本发布出来没人用、没企业愿意接手,硬把它定为 LTS,后续维护力量跟不上,反而不如不定。所以 LTS 的选定实际上是社区需求、企业反馈、维护者精力三方博弈之后的结果。
2.2 LTS 的维护周期不是统一的
这里有个关键细节:不是所有 LTS 版本的维护周期都一样长。内核官方给的 LTS 维护周期最短两年,但有些版本会被延长维护。举例来说:
- v4.4 原本维护到 2022 年 2 月,后来因为 Android 生态里大量设备还在用,就延长到了 2022 年 10 月。
- v4.9 原定维护周期结束后被延长到 2023 年 1 月,同样是出于 Android 和嵌入式设备的现实需求。
- v5.10、v5.15 都有类似情况,维护周期根据实际使用情况动态调整。
- v6.1 被确定为长期维护版本,目前计划维护六年,到 2026 年 12 月。这个六年周期在官方 LTS 里算是比较长的。
所以你在 kernel.org 上看到的 EOL(End of Life)日期并不是刻在石头上的,后续完全可能因为大客户的需要而调整。这反过来也说明:LTS 的真正价值在于它有一个相对稳定的维护承诺,而不是一个绝对固定的时间表。
2.3 普通 stable 版本跟 LTS 的差别有多大
拿 6.x 时代的版本举例:6.5、6.6、6.7 这些版本,6.6 运气好被选成了 LTS,其余几个版本的 stable 维护期只有六到八个礼拜。过了维护窗口,上游就冻结了,不再接受任何 bug fix 和安全补丁。你如果在产品里用了 6.5,那么三年后可能积攒了几十个 CVE 没人管,只能自己处理,或者被审计的时候发现问题。
LTS 版本在维护窗口内,bug fix 和安全补丁都是持续流入的。虽然下个 LTS 版本发布的时候,当前这个不会立刻停止维护,但你可以清楚地规划迁移窗口,不用被上游的“停更”突袭。
3. 谁在真正依赖 LTS 内核
聊完了概念和机制,得说说现实世界里的应用。LTS 内核最大的两个下游用户,一个是 Android 生态,一个是嵌入式/工业设备。
3.1 Android 生态与 LTS 的关系
Android 的 GKI(Generic Kernel Image)项目大家可能听过,Google 在 Android 12 之后把内核模块和核心内核解耦,设备厂商可以直接基于 Google 提供的 GKI 内核来改驱动,而不是像以前那样每家厂商各搞一套完整的内核源码。GKI 的底座就是 LTS 内核版本。
比如 Android 13 搭配的 GKI 内核就是基于 android13-5.15 分支,这个分支往上追根溯源,就是 Linux 5.15 LTS。Android 14 则是 android14-5.15 和 android14-6.1。也就是说,Google 帮所有 Android 厂商选好了 LTS 基线,厂商只需要在这个基础上做驱动适配和 BSP(Board Support Package)定制,而不是从零维护一个内核。
这里就绕不开一个很多搞 Andorid 开发的人会撞上的词:高通 CAF kernel。CAF 是高通基于上游 LTS 内核(再加上部分 mainline 特性)做的下游分支,专门用于高通芯片平台(骁龙系列)。你在高通的 codeaurora 上下载的 kernel 源码,版本号经常是类似 msm-5.15 这种,本质上就是从 Linux 5.15 LTS 拉出来的定制分支。
高通为什么要基于 LTS 做 CAF?因为高通的芯片生命周期长,一款芯片从发布到退市至少三四年,如果内核版本没有长期支持,高通就得不停地做内核大版本迁移,成本极高。LTS 内核给了高通一个稳定的基线,CAF 在此基础上集成芯片驱动、功耗管理、BSP 相关代码,形成设备厂商可以直接用的“半成品”。
所以你在找工作面试 Android BSP 驱动岗的时候,面试官很可能会问一句:“你了解你们项目的内核版本是怎么选的吗?”如果你能答上来“底层是 Linux 5.15 LTS,上层是高通 CAF,再往上是厂商自己的定制”,这已经说明你不是只会在 repo 里拉代码的搬运工了。
3.2 嵌入式与工业设备的 LTS 依赖
嵌入式领域的逻辑更简单粗暴:卖出去的设备不能随便升级内核,因为设备在客户手里,你不可能像手机一样推个 OTA 就换内核版本(即使有 OTA,内核大版本升级也容易引入兼容性问题)。而且工业设备、医疗设备、车载设备的安全认证往往绑定在整个软件栈的版本组合上,随便换内核版本可能导致认证作废。
这种情况下,LTS 内核是唯一现实的选择。设备出货后,软件团队只需要盯着上游 LTS 的维护版本,定期把安全补丁拉下来验证、集成、发版。整条链路是清晰的。
3.3 服务器场景也在用 LTS
虽然服务器领域大部分发行版都会自己维护内核,比如 Ubuntu 有 HWE(Hardware Enablement)内核、企业版有自己长期维护的 5.4/5.15 内核,但这些发行版维护的内核版本绝大多数也都是从上游 LTS 选型的。Debian 的 stable 内核基本上对应的是某个 LTS 版本。
另外,最近两年很多人折腾 WSL2 手动更新内核,去 GitHub 下载那个 wsl2-linux-kernel 的 release 包,你会发现 WSL2 内核对应的上游版本也是选择了当时处于维护期的 LTS。这不奇怪——微软做的是产品,产品要的就是稳定和长期的 CLA(Cover Letter)管理,而不是追新。
4. 怎么选择和维护一个 LTS 内核
说完了 LTS 内核是什么、谁在用,接下来进入到方法论环节。如果你正在做一个新项目,或者想把手头项目的内核切换到 LTS 版本,下面这些是我个人实际踩过坑之后总结的经验。
4.1 选版本:别只挑最新的
先看 kernel.org 的 longterm 列表,找到当前处于维护期的 LTS 版本,比如 6.1、5.15、5.10、5.4 这些。这时候很多人会下意识选最新的 6.1,觉得新总比老好。但实际选型要考虑的问题比“新不新”复杂得多。
第一,你项目的软件栈跟哪个内核版本兼容性最好。比如你的 BSP 是某个芯片厂商提供的,厂商给的 SDK(软件开发套件)适配到 5.10,你自己强行换 6.1,驱动接口变化和 ABI 变动可能让你多花几周甚至几个月的时间适配。
第二,你需要的驱动和内核模块在目标版本里的成熟度。新内核的驱动框架通常更现代化,但某些老设备、老外设的驱动可能在新内核里反而支持得不好,甚至被移除。
第三,你团队对哪个版本最熟悉。这听起来不“技术”,但很现实。一个团队如果一直在 4.19 上做开发,突然跳到 6.1,光是设备树写法、驱动 API 的差异就要适应很久。选型不是选“纸面上最好的”,而是选“你能够在维护周期内真正驾驭住的”。
我自己的建议是给一个具体的参照系:如果你的产品生命周期在三到五年以内,优先选当前刚进入 LTS 周期的新版本(比如现在的 6.1);如果你的产品要跑五六年以上,可以考虑选一个新点的 LTS,比如等 6.6 确认稳定后再切过去。别用已经进入 EOL 倒计时不到两年的老 LTS 启动新项目——你产品还没出货,上游就停止维护了,等于开局就落后。
4.2 熟悉版本节奏:stable 分支的更新频率
LTS 选定之后,并不是说版本号就钉死了。LTS 的源代码仓库还在持续演进,每过几周就会出一个新的稳定版小版本,比如从 5.15.150 升到 5.15.151。这些小版本主要包含安全修复和关键 bug 修复,通常不会加新功能——这是内核 stable 机制的典型做法。
对于产品团队,这个节奏意味着:你需要有一个机制去跟踪 LTS 上游的新版本,并且定期合并到自己产品的内核分支上。完全不管上游更新,等到第二年再来一次大合并,冲突会多到你怀疑人生;每周都追着更新,又会折腾出太多无效的工作量。我个人的节奏是:每两周到一个月看一次上游 stable 更新日志,判断哪些改动跟我们的硬件平台相关,重点合入。安全补丁则另外按严重级别批量处理。
4.3 LTS 内核的配置要点
不管你是编译给 Android 用、给嵌入式设备用,还是给服务器用,LTS 内核的配置策略有一些通用原则。这里单独提三个我觉得最容易出问题的点。
内核符号导出与模块 ABI。如果你的产品涉及第三方驱动模块(比如 GPU 驱动、WiFi/BT 协议栈),这些模块往往是预编译的二进制,它们依赖内核导出的符号(EXPORT_SYMBOL)。如果你在配置内核时关掉了一些模块依赖的 symbol,或者改了内核配置导致模块 ABI(应用二进制接口)变化,预编译模块一加载就报 unknown symbol 或直接 panic(内核崩溃)。所以内核配置的变更必须遵循严格的评审流程,尤其是配置项会直接影响模块接口时。
CMA(连续内存分配器)与 DMA 配置。嵌入式设备上做视频编解码、ISP、GPU 这类需要大块连续物理内存的场景,CMA 和 DMA(直接内存访问)相关配置必须从一开始就调好,后面改起来牵一发动全身。比如很多平台要配置 CONFIG_CMA_SIZE_MBYTES 来预留 CMA 池子大小,改晚了可能整个多媒体链路跑不起来。
PREEMPT(抢占)模型与 RT 特性。如果你的设备有实时性要求,可能需要开 RT 内核补丁(PREEMPT_RT)。LTS 内核版本中的 RT 支持是单独维护的,比如 5.15 对应的 RT 补丁是 patch-5.15.x-rtXX 这样一套。选型时要确认你选的 LTS 版本是否有对应的 RT 补丁,且补丁维护是否活跃。
4.4 从老内核迁到 LTS 时容易踩的坑
我见过不少团队从老内核(比如 3.x/4.x)直接迁到新 LTS(5.10/5.15),过程中问题五花八门,列几个高频的:
设备树格式变化。4.x 时代跟 5.x 时代的 device tree 写法差异很大,很多新旧属性名称变了,甚至有些 binding 被废弃。如果你只是把老 dts(设备树源文件)拷贝到新内核里编译,大概率会报一堆 invalid property 或者显示不出设备。
驱动 API 变化。比如 clk_prepare_enable、gpiod_get 这类基础设施 API 在新内核里行为更严格,老驱动不主动适配,很可能出现启动卡死、外设不工作的问题。这不是简简单单解个编译错误就能解决的。
initramfs 与 bootloader 的不兼容。新内核在压缩格式、image 布局、boot 参数解析上可能跟老 bootloader 不匹配。你做了新内核,刷进去发现起不来,第一反应别只查内核,先确认 bootloader 分支设置的 kernel 加载地址、ramdisk 格式、DTS 加载方式是否跟新内核匹配。
5. 我在 LTS 内核上实操过的几件事
讲原理比较枯燥,下面分享几个我亲手做过的真实操作,涉及 LTS 内核的编译、更新、问题定位,你可以直接拿去参考。
5.1 从 kernel.org 拉取并编译 LTS 内核
以 6.1 为例,过程大概是这样的:
bash复制# 拉取源码,这里用 6.1.y 的 stable 分支
git clone --depth 1 --branch linux-6.1.y \
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
cd linux
# 生成默认配置(也可以用厂商提供的 defconfig/config)
make defconfig
# 或者用现有系统的配置做基础,再调整:
# cp /boot/config-$(uname -r) .config && make olddefconfig
# 调整配置
make menuconfig
# 编译,-j 后面的数字根据 CPU 核心数来
make -j$(nproc)
# 安装模块和内核
sudo make modules_install
sudo make install
这里有个小点值得提:如果只是做交叉编译,要提前设置好交叉编译工具链,比如:
bash复制export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make defconfig
make -j$(nproc) Image dtbs
编译 LTS 内核本身不复杂,复杂的是背后那套配置管理和维护流程。建议从一开始就把内核配置文件纳管到版本控制里,别每次编译都手动调 menuconfig,不然过两周你自己都忘记改过什么了。
5.2 Android GKI 场景下的 LTS 更新流程
我实际接触过一个基于 android13-5.15 GKI 内核的项目,Google 会定期发布新的 GKI 版本,里面同步了上游 5.15 LTS 的更新。我们这边的做法是:
- 关注 Google 的 android common kernel 分支发布节奏,每个里程碑(如
android13-5.15-release)发布后,先看 release note,了解这个版本主要合入了什么内容。 - 用
repo把整个项目的内核源码同步到新 tag,然后只跑一遍编译,不做代码改动,先确认基础编译是否通过。 - 编译通过后,把生成的 boot image(boot.img)刷到一台测试机上,跑一轮冒烟测试,重点看开机、网络、存储、传感器、显示这些基础外设是否正常。
- 如果冒烟没问题,再往深了跑 WiFi、蓝牙、Camera、GPU 这些跟厂商 BSP 强相关的场景,一般问题都出在这一步,因为 CAF 的驱动模块跟 GKI 内核之间的接口可能有细微的 ABI 变化。
有一回在升级一个 GKI 小版本后,WiFi 驱动编出来的内核模块在 insmod 时直接报 Unknown symbol,排查了半天,最后发现是 GKI 在某个版本里改了内核符号导出表,把几个 WiFi 驱动依赖的符号给砍了。这个坑的教训就是:升级内核版本时,内核模块的符号依赖变化比代码冲突更隐蔽,需要提前做一次模块 ABI 比对。
5.3 用 scripts/checkstack.pl 分析内核栈溢出
有一次遇到设备莫名其妙重启,dmesg 里全是 BUG: stack overflow 的错误。当时用的就是 LTS 内核,5.10 分支。排查工具我推荐内核源码自带的 scripts/checkstack.pl,它能分析内核镜像里函数调用栈占用情况,帮你找出栈使用过深的函数。
bash复制# 基于 vmlinux 分析
perl scripts/checkstack.pl arch/arm64/boot/Image
输出会列出每个函数的栈帧大小,找栈帧异常大的函数重点排查。那次发现是一个 GPU 驱动里的函数栈帧到了 2KB 以上,加上中断嵌套,直接把内核栈顶爆了。这个工具在嵌入式设备上很实用,强烈推荐加进你的问题排查工具箱。
5.4 内核 panic 打印的解析思路
LTS 内核上遇到 panic,第一件事别慌,先把 panic 信息里的函数调用栈完整拷下来。内核 panic 输出的 Calling 栈每一行格式大概是 [<地址>] 函数名+偏移/长度,通过 scripts/faddr2line 可以解析出具体的源码行号:
bash复制./scripts/faddr2line vmlinux do_page_fault+0x30/0x50
这个工具能帮你把函数地址映射回精确的源码位置,省去大量在汇编里翻来翻去的时间。说实话,我见过很多同事遇到 panic 只会去搜索引擎复制粘贴关键词,其实内核源码树里已经给了你一堆调试图工具,关键是要知道它们的存在。
6. 常见问题与坑位速查
把我在 LTS 内核维护中遇到的典型问题整理成一张表,方便你排查时快速对照。
| 现象 | 可能原因 | 排查思路 |
|---|---|---|
| 编译出的内核启动后设备树外设没挂载 | dts 里属性与当前内核 binding 不匹配 | 用 dt-validate 验证设备树;对照内核文档里的 binding 说明 |
模块加载提示 Unknown symbol |
内核配置符号导出变化,或模块与内核 ABI 不匹配 | `nm vmlinux |
| 启动过程中反复重启,无日志输出 | bootloader 加载内核地址错误,或 initramfs 格式不受支持 | 确认 boot 分区地址、ramdisk 解压方式;尝试关掉 quiet 参数看启动早期日志 |
dmesg 出现 soft lockup 或 hard lockup |
死锁、中断处理过久、或抢占配置不当 | 结合 nmi_watchdog 和 ftrace 抓调用栈;检查调度策略和中断优先级 |
| 性能不稳定,吞吐量波动明显 | CPU 调频、idle 策略或 NUMA(非统一内存访问)配置不优 | 检查 cpufreq 策略;尝试 idle=pool 等不同启动参数做对比测试 |
| 升级 stable 小版本后外设驱动异常 | 新内核合入的某项改动与驱动行为不兼容 | 用 git log 查看两次版本间的提交,重点看驱动子系统和设备树相关提交 |
编译时提示 No rule to make target |
配置项引用了不存在的问题,通常是老内核配置直接用于新内核 | 先 make olddefconfig 自动修正,再人工检查被废弃的配置项 |
7. 最后分享一个跟 LTS 内核相关的实用建议
说到 WSL2,很多人可能不知道,Windows 里跑的 WSL2 内核其实也是一个定制的内核分支,它始终跟随 LTS 版本更新。如果你平时在 WSL2 里做内核相关开发,有个小技巧是手动更新 WSL2 内核到官方仓库的最新 release 包,对应的是经过更多测试的 LTS 版本。做法很简单:去 microsoft/WSL2-Linux-Kernel 仓库把最新的 release 包下载下来,然后以管理员身份运行 wsl --update --in 加上对应的包路径就行。这不只是追新,LTS 的 bug 修复对 WSL2 的稳定运行有实打实的帮助。
在我个人做内核维护和选型的这些年里,最大的体会是:LTS 内核不是一个技术选项,而是一个产品决策。技术上无论哪个版本你都能编译出能跑的镜像,但产品要的是接下来三五年有人帮你兜底安全、修复关键问题。选 LTS、跟 LTS、守住 LTS 的节奏,这比看几个内核版本的性能对比要重要得多。
如果你的项目也正处于内核选型阶段,我建议按这样的顺序评估:先看目标产品的生命周期,再确认芯片/硬件平台的 BSP 基线,再看上游 LTS 版本是否覆盖你的硬件驱动需求,最后结合团队的维护能力做决定。把这一整套想清楚了,项目后半程的内核维护才不会变成天天救火。
如果你已经在用 LTS 内核,记得定时去 kernel.org 看 longterm 列表里你那个版本的 EOL 日期,给自己留出足够的安全迁移窗口。别等到 EOL 了才开始准备,那时候你的产品可能已经卖到用户手里了,再想动内核就来不及了。
