这次我们来看的,不是某个新的开源模型或一键启动包,而是 Linux 内核开发社区里正在被认真讨论的一个命题:LLM 生成的代码,未来还能不能进 drivers/staging,进入时应该按什么标准来评估。标题直译就是 “drivers/staging 目录后续的 LLM 策略”。它讨论的边界很清晰,但波及面很大——内核维护者、驱动开发者、AI 辅助编码工具的使用者都会受到影响。
先把结论放在前面:这不是一个已经成文的官方规则,而是一个仍在讨论中的治理话题。真正决定你的 LLM 驱动能不能被接受的,不是“有没有用 AI”,而是“代码能不能编译、有没有遵守内核开发规范、有没有完整测试、提交者能不能对版权和可靠性负责”。这篇文章会拆解这个议题背后的技术背景、争议点,给出一个从 LLM 生成到 checkpatch 验证、再到补丁提交的完整工作流。
如果你正在用 LLM 写 Linux 驱动,或者想把自己训练的代码模型接入内核补丁流程,这篇可以直接收藏。
1. 议题速览:LLM 与 drivers/staging 碰撞的核心点
先把这个话题的核心维度整理成一张表,方便快速判断这个议题和你有没有关系。
| 维度 | 说明 |
|---|---|
| 议题范围 | Linux 内核 drivers/staging 目录后续接收补丁时,如何处理 LLM 辅助生成的代码 |
| 相关角色 | 内核维护者、子系统 reviewer、驱动作者、本地 LLM 工具使用者 |
| 核心争议 | 代码质量门槛、版权归属与 DCO、长期维护成本、测试验证是否充分 |
| 可落地的工具 | checkpatch.pl、clang-format、sparse、smatch、KUnit、kernel test robot |
| 当前状态 | 社区以讨论为主,尚未形成固定成文规则;实际操作按代码质量标准评估 |
| 最容易踩的坑 | 伪造作者、未授权代码来源、只求能编译就提交、批量提交无测试的补丁 |
这个议题很容易被误解成“内核要禁止 AI 写代码”。从社区讨论的倾向看,更准确的理解是:内核本来就不关心代码由谁生成,只关心代码是否达到可接受的质量标准。LLM 只是把“代码产出速度”拉高了,但“代码责任归属”和“长期可维护性”这两个问题也被放大了。
2. 背景:drivers/staging 是什么,为什么 LLM 问题会在这里爆发
drivers/staging 是 Linux 内核中用于存放“代码质量还不够进入主线、但有明确合并价值”的驱动程序的暂存区域。很多新的、实验性的、缺少长期维护的驱动会先进入这个目录,经过几轮 review 和重构后,再移动到正式子系统。相比之下,staging 的门槛会比主线低一档,但不代表没有门槛。
staging 目录里的代码仍然必须满足几个硬性条件:可以正常编译、不存在明显安全漏洞、有明确的维护计划、不会长期烂在 staging 里。换句话说,staging 并不是“垃圾场”,而是“待完善区域”。
那么问题来了:为什么 LLM 和 drivers/staging 的碰撞会这么集中?
一个原因是驱动代码本身的结构化程度高。注册接口、文件操作集合、电源管理回调、设备树匹配表,这些内容高度模板化,非常适合 LLM 生成。你给模型一段参考驱动的代码,它完全可以生成一个结构像模像样的新驱动框架,甚至能帮你补全大部分 boilerplate。
另一个原因是驱动对信息精确度的要求极高。设备驱动要面对硬件手册里的具体寄存器地址、位域含义、时序要求。LLM 擅长“看起来合理”的文本生成,但也同样擅长一本正经地编造一个根本不存在的寄存器。这类错误在应用层代码里可能只是功能不对,在驱动代码里可能导致设备挂死、内存踩踏,甚至系统崩溃。这也是内核社区对 LLM 补丁格外谨慎的根本原因。
所以,drivers/staging 成为了一个非常典型的矛盾集中地:它允许代码不完美,但绝不允许代码不可维护;它欢迎新驱动,但绝不欢迎无法追责的代码来源。
3. 争议点拆解:LLM 生成代码进入内核,卡在哪几个问题上
3.1 版权与 DCO:谁对 AI 生成的代码负责
Linux 内核的贡献者需要签署 Signed-off-by,它对应 Developer’s Certificate of Origin(DCO),表示提交者确认自己有合法权利提交这份代码,并且这份代码遵循开源协议。
这里的关键点是:LLM 本身不是法律意义上的作者,它无法签署 DCO。真正签署签名的是提交补丁的人。如果开发者使用 LLM 生成代码,那么开发者必须对代码的出处负责。尤其是当训练数据里可能包含大量 GPL 代码时,模型输出的代码片段是否有版权风险,目前没有明确的判据。
这是内核社区讨论中反复出现的问题之一。即使不讨论最终会形成什么规则,任何准备用 LLM 提交驱动的开发者也应该先想清楚:如果维护者问你“这份代码是从哪来的”,你能不能给出清晰、可信、可追查的答案。
3.2 代码质量:不是能不能跑,而是能不能维护
LLM 生成的内核代码常见问题并不少。比较典型的有:
- 内存生命周期处理错误,比如申请了内存但释放路径不完整。
- errno 使用不规范,返回错误码和实际失败原因对不上。
- 并发访问没有锁保护,或者锁的粒度明显不合理。
- 依赖不存在的宏、函数或头文件。
- 盲目仿照某个架构的驱动写法,但换到一个不一样的硬件平台,逻辑就完全错位。
staging 允许代码在开发早期存在瑕疵,但不允许“看起来合理但实际上危险”。判断代码是否危险,需要 review 的人对硬件有理解,这恰恰是 LLM 最难替代的部分。
3.3 补丁洪泛:批量生成会不会压垮维护者
如果一个人用 LLM 一天生成几十个补丁,然后全部丢到邮件列表上,维护者会非常头痛。review 一个内核补丁不是几分钟的事,尤其是驱动代码,要结合硬件手册、子系统的既有约定、长期维护成本来判断。
所以,把 LLM 用于驱动开发,重点不在于“能不能生成”,而在于“生成之后如何筛选”。真正有效的工作流是:LLM 负责生成候选代码,开发者负责验证、筛选和提交,而不是把生成结果原封不动推给维护者。
4. 一个能落地的流程:从 LLM 生成到进入 staging
这一节给出一个可操作的完整流程。它不是一个已经发布的一键工具,而是一套你可以直接执行的通用做法。
完整流程分六步:
- 明确驱动目标和硬件范围。
- 准备数据手册、寄存器定义和参考实现。
- 用 LLM 生成代码骨架。
- 人工补全硬件差异和细节逻辑。
- 本地编译、静态检查、模块加载测试。
- 通过 get_maintainer.pl 找到维护者,提交补丁。
4.1 生成一个最小 misc 设备骨架
下面是一个用于演示的 misc 设备示例。它可以用 LLM 辅助生成,然后人工补齐细节。这个例子不准备进入内核主线,只是展示一个“看起来符合内核风格、实际上还需要继续打磨”的代码长什么样。
// SPDX-License-Identifier: GPL-2.0-only #include <linux/init.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/uaccess.h> #define STAGING_DEMO_IOCTL_MAGIC 'S' #define STAGING_DEMO_GET_VERSION _IOR(STAGING_DEMO_IOCTL_MAGIC, 1, int) static int staging_demo_open(struct inode *inode, struct file *filp) { return 0; } static long staging_demo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int version = 1; if (cmd == STAGING_DEMO_GET_VERSION) { if (copy_to_user((void __user *)arg, &version, sizeof(version))) return -EFAULT; return 0; } return -ENOTTY; } static const struct file_operations staging_demo_fops = { .owner = THIS_MODULE, .open = staging_demo_open, .unlocked_ioctl = staging_demo_ioctl, }; static struct miscdevice staging_demo_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "staging_demo", .fops = &staging_demo_fops, }; static int __init staging_demo_init(void) { return misc_register(&staging_demo_dev); } static void __exit staging_demo_exit(void) { misc_deregister(&staging_demo_dev); } module_init(staging_demo_init); module_exit(staging_demo_exit); MODULE_LICENSE("GPL");这个骨架已经能通过基本的内核风格检查,但距离“可提交”还差很多:没有错误路径测试、没有设备树兼容性考虑、没有并发场景验证、也没有文档。注意,让 LLM 把这种骨架代码拼出来并不难,难的是后面这些没有体现在代码里的工作。
4.2 本地编译检查
在真实的内核源码树中,示例目录需要先有 Kconfig 和 Makefile,然后才能编译。
config STAGING_DEMO tristate "Staging demo misc device" depends on MISC_DEVICES help Demo driver for LLM-assisted development.obj-$(CONFIG_STAGING_DEMO) += staging_demo.o编译命令示例,假设当前在内核源码根目录:
# 在内核源码目录下执行 make ARCH=x86_64 -j$(nproc) M=drivers/staging/staging_demo modules如果驱动需要放进 drivers/staging,还要考虑它是否适合 staging 的定位。只把一段代码放进目录不算完成,必须说明这个驱动为什么暂时进不了主线,以及后续迁移计划。
4.3 checkpatch 验证
内核提供了一个编码风格检查脚本,在源码根目录执行:
./scripts/checkpatch.pl --no-tree --file drivers/staging/staging_demo/staging_demo.c这个脚本会检查空格、缩进、注释、宏定义、函数声明、Signed-off-by 等问题。它不保证代码逻辑正确,但能快速过滤掉一批低级格式错误。LLM 生成的代码经常会有缩进不统一、空行位置不对、宏命名风格不符合约定等问题,checkpatch 是第一步筛选。
4.4 提交前的自检清单
在把补丁发到邮件列表之前,建议过一遍下面的清单:
| 检查项 | 工具或方法 | 通过标准 |
|---|---|---|
| 编码风格 | checkpatch.pl | 没有 error,warning 尽量清零 |
| 编译 | make M=drivers/staging/xxx modules | 无错误,无新增警告 |
| 静态分析 | sparse、smatch、make W=1 | 无新增告警 |
| 模块加载 | modprobe/insmod + dmesg | 模块可加载,设备可注册 |
| DCO | git commit -s | 补丁有 Signed-off-by |
| 源码来源 | 人工确认 | 可以说明代码出处与授权范围 |
| 测试结果 | 补充在 cover letter 里 | 说明测试环境和验证项 |
5. 内核编码规范与静态检查:LLM 补丁的高频失败点
checkpatch 只能解决“风格”问题,解决不了“逻辑”问题。对于驱动代码,逻辑问题通常出现在硬件初始化和资源释放路径上。
建议在本地先跑一轮静态检查,不要直接提交。常用的检查组合是:
# 编译时打开额外警告 make W=1 M=drivers/staging/staging_demo modules # sparse 检查 make C=2 M=drivers/staging/staging_demo modules同时还可以用 clang-format 对代码做一次批量格式化,风格使用内核配置:
clang-format --style=Kernel -i drivers/staging/staging_demo/staging_demo.c不过要注意,clang-format 只能整理格式,不能替代人工 review。LLM 生成的代码里,真正危险的是那些“语法正确但语义错误”的地方,比如读写了错误的寄存器偏移、在中断上下文里调用了会睡眠的函数、锁的顺序不一致。静态检查工具能抓一部分这些问题,但抓不全,最终还是要有人对着硬件手册核对。
6. 工作流自动化:把 LLM 接入补丁生成与检查
如果你不满足于在线聊天框里复制代码,而是想把本地 LLM 服务接入驱动开发流程,可以用本地推理服务来完成候选代码生成,然后再接 checkpatch 做自动筛选。这不是某个具体项目规定的接口,而是一种通用做法。
6.1 本地 LLM 服务调用示例
以 Ollama 为例,它的默认本地端口是 11434,接口路径为 /api/generate。下面的 curl 示例会生成一个 misc device 驱动骨架:
curl -s http://127.0.0.1:11434/api/generate \ -H "Content-Type: application/json" \ -d '{ "model": "qwen2.5-coder:7b", "prompt": "Write a Linux misc device driver skeleton with open/release/ioctl, follow kernel coding style, SPDX header first.", "stream": false }'注意,模型名只是示例,需要替换为你本地实际可用的模型。如果你使用的是其他推理引擎,请求结构可能不同,以对应文档为准。
6.2 批量生成与人工抽检
批量任务不是不能做,而是要做对。假设你要为一批类似的 USB 设备生成驱动候选代码,可以这样做:
- 每个设备单独生成一个目录,保存 LLM 返回的原始输出。
- 每个候选代码都跑一次 checkpatch,把通过的单独放一个目录。
- 每个候选代码都在最少一个真实或虚拟硬件上完成编译和模块加载测试。
- 人工抽检比例必须足够高,尤其是硬件初始化、中断处理、电源管理三类逻辑建议全部人工确认。
这里有一个重要原则:LLM 生成的代码在默认情况下应该被视为“不可信输入”。只有经过编译、静态检查、人工 review 的代码,才具备提交到内核邮件列表的资格。
7. 资源占用与性能观察:本地跑代码模型怎么选精度
如果你打算在本地跑一个代码生成模型,有一类问题绕不开:显存占用、内存占用、推理速度,以及 LLM 推理精度问题。这里单独展开讲一下 fp16、fp32、bf16 的选择。
先说结论:对内核代码生成场景,不要为了省显存把量化等级压得过于激进。代码生成任务对语义细节非常敏感,模型精度降低后,语法错误比例可能变化不大,但逻辑错误比例会明显上升。
fp32 精度最高,显存和内存占用也最大,适合显存非常充裕的场景。fp16 把显存占用减半,是目前最常见的推理精度,但 fp16 的指数范围较小,在小数值计算场景可能出现下溢。bf16 的指数范围与 fp32 一致,但尾数位更少,精度更低,优势是动态范围大,不容易溢出。三者之间的取舍没有绝对答案,要看你的显卡支持情况和模型对数值误差的敏感程度。
在驱动代码生成这个场景,更值得观察的不是单次推理的 token 速度,而是下面几个指标:
- 生成代码后的 checkpatch 通过率。
- 一次生成后仍需人工修改的代码行数。
- 补丁被维护者要求重新修改的轮次。
- 模块加载和基本功能测试的一次通过率。
这些指标比“每秒生成多少个 token”更能反映模型在你这条工作流里的真实价值。
如果你的机器同时还在跑 ComfyUI 这类图像生成工作流、本地 LLM 推理服务、内核代码编译任务,三者会争抢 GPU 显存、CPU 和磁盘 I/O。建议把不同任务错开运行,或者拆到不同机器上,避免在编译内核时出现 OOM 或频繁 swap,导致补丁验证质量下降。
8. 常见问题与排查方法
这里整理一份针对“LLM 辅助内核驱动开发”的排查表,覆盖从生成代码到提交补丁的常见问题。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| checkpatch 报错过多 | LLM 没有严格遵循内核编码风格 | 查看具体 error 行号,定位缩进、宏、注释问题 | 先用 clang-format --style=Kernel 格式化,再逐条修 checkpatch 报错 |
| 编译通过但模块无法加载 | 依赖的符号未导出,或设备树不匹配 | dmesg 查看加载报错,用 modinfo 检查依赖 | 补全依赖,检查设备树 compatible 是否匹配 |
| 模块加载后设备没有生成 | misc 设备注册失败或次设备号冲突 | 查看 /proc/misc 和 dmesg | 确认 MISC_DYNAMIC_MINOR 是否使用,检查 id_table |
| 提交补丁被退回,缺少 Signed-off-by | 没有执行 git commit -s | git log --format=fuller 查看签名 | 重新 commit 并签署 DCO |
| 维护者询问代码来源 | 补丁没有说明 LLM 辅助情况,维护者要求追责 | 准备好生成方式和审查记录 | 在 cover letter 中如实说明 AI 辅助范围,并承诺对代码负责 |
| 直接提交大量 LLM 补丁被社区拒绝 | 补丁洪泛,review 成本高 | 查看反馈邮件,确认是哪一批补丁引发问题 | 缩小每次提交流程,按驱动类型分批,附完整测试结果 |
| 本地 LLM 服务偶发返回空内容 | 上下文窗口超过限制或显存不足 | 检查推理日志和显存占用 | 缩短输入代码片段,或切换到更大显存环境 |
| 模型生成的代码使用了不存在的 API | 训练数据未覆盖最新内核接口 | 用 grep 在内核源码里搜索相关符号 | 以当前内核源码为准,人工修正后再编译 |
9. 最佳实践与合规建议
结合上面的分析,给几个实际可用的建议。
第一,把 LLM 当成“骨架生成器”和“语法助手”,而不是“内核代码作者”。你可以让模型生成驱动框架、补全重复代码、解释某个内核 API 的用法,但最终代码的每一行都应该经过你本人确认。
第二,保留完整的生成和审查记录。如果你用 LLM 生成了代码,记录下模型名称、生成时间、修改过程中人工修改的内容。这些材料不一定要主动提交给维护者,但当被问起时可以快速回应。
第三,严格遵守 DCO 和版权边界。提交补丁前确认代码来源合法,不涉及未授权的第三方代码。如果模型输出疑似与某个 GPL 项目高度相似,建议替换实现方式。
第四,批量任务必须设置人工抽检闸门。不要一次性提交几十个由 LLM 生成的补丁。每一批补丁都要有可复现的编译记录、测试记录和人工 review 记录。
第五,第一轮测试用小参数、小范围验证。先让模型生成一个最小可编译的驱动,跑通 checkpatch、编译、模块加载流程,再逐步扩大生成范围。不要一上来就让它生成几百行的完整驱动。
第六,注意端口和进程管理。如果本地推理服务和 Web 服务同时启动,要确认端口没有冲突;如果使用批量生成脚本,要检查是否有残留的推理进程占用显存。
10. 总结与下一步
回到文章开头的问题:LLM 生成代码到底能不能进 drivers/staging?
从现有的讨论方向看,答案不是简单的“能”或“不能”,而是“满足质量门槛就能,不满足就不能”。内核社区真正在意的不是代码由谁生成,而是代码能不能编译、能不能维护、出了问题能不能追责。LLM 提高了代码生成速度,但并没有改变代码质量标准。
对你来说,最先应该验证的事情是:让 LLM 生成一个最小的 Linux 驱动骨架,跑一遍 checkpatch、编译和模块加载,记录下出现的问题数量。这个流程跑通之后,再考虑把它接进批量任务和本地推理服务。
最容易踩的坑是“只看到编译通过就提交”。驱动代码的验证链路远不止编译,还包括静态检查、硬件行为核对、并发场景测试和版权确认。把这条链路固定成自己的流程,比争论“政策会怎样”更有实际价值。
后续可以继续关注内核社区对 AI 生成代码的文档更新、DCO 相关讨论,以及内核辅助开发工具的演进。如果社区最终形成明确的成文策略,大概率也是围绕“代码质量可验证、代码来源可追责、补丁责任可承担”这三个基本原则来展开的。