LWN:如何有效确保stable kernel的稳定性?

稳定内核的维护者Sasha Levin详细介绍了稳定内核的维护流程,包括补丁的筛选、测试和合并,以及如何确保稳定内核的质量。稳定内核的目标是在不引入新功能的情况下修复bug,这一过程需要严格的审查和广泛的测试。

关注了就能看到更多这么棒的文章哦~

Maintaining stable stability

By Jake Edge
July 22, 2020
OSSNA
https://lwn.net/Articles/825536/
Translation benefits from DeepL

stable kernel tree上的开发相当活跃,经常会在一周内发布好几个版本,但它们也是为了......好吧......stable,所以我们付出了很多努力来确保它们不会引入新的bug或功能倒退(regression)。stable tree的维护者之一,Sasha Levin,在Open Source Summit North America的在线峰会上做了一个演讲,描述了如何确保这些stable tree是在仔细管控的,从而为用户提供一个稳定系统的基础。

Background

Levin说,stable tree的这些主要目标,在某种程度上是相互冲突的。维护者不希望在代码tree中导致质量回退,但他们也希望尽量确保不会错过任何需要加进stable tree的bug fix。要平衡这两个目标,是 "非常棘手 "的。本讲座将展示一下bug fix patch是如何从开发者手中来到stable tree的这一过程,从而说明现在有哪些机制在尽量确保只有真正的、不会导致regression的bug fix才能够一直走到合入stable tree的这一步。

第一步,先介绍了哪些类型的patch是可以合入stable tree的。只有那种小修改、并且逻辑上非常简单直接的bug fix才可以合入,而且要求要是已经在Linus Torvalds的upstream代码tree里才行。stable tree不欢迎那些新增的复杂机制,也不欢迎新功能。这些新功能的patch已经达到了被mainline接受的 "最低标准",但有时候维护者(或patch作者)还希望backport这些patch。这种行为是stable的maintainer希望尽量避免的,这样对于mainline的测试实际上也覆盖到了stable tree中的许多代码,但是backport是无法绝对避免的。如果有一些较大的、有破坏性(intrusive)的补丁必须backport过来(比如说针对speculativ-e-execution这种处理器缺陷的一些弥补措施),那么stable tree的维护者就会要更多的测试、以及subsystem维护者的sign-off等等,以尽量保证这个backport是合理的。

Stable patch process

当有人在开发一个patch时,进入stable的流程就开始。如果他们将其提交到upstream的时候,加了stable tree的tag,那么reviewer和维护者通常会更加关注它。因为这个patch可能会很快就进入到用户手中,所以要尽量确保patch的正确性。如果提交的patch修复了一个问题但是没有打上stable的tag,那么子系统或stable tree的维护者可能会要求给它打上stable的tag,并且会要求加上 "Fixes: "tag,以帮助确定哪些branch需要backport。

 [Sasha Levin]

有一个bot自动从mailing list里提取那些标有stable tag的patch,并尝试根据所标示的stable版本或根据 Fixes: tag 将其apply到不同的stable tree上。如果patch的apply没有成功,bot会提醒patch作者来处理这个问题,同时提供的建议里面可能也会列出一些其他patch来提醒作者是不是需要先合入这些patch。Levin说,在patch还在开发的阶段就来做这些事,这是非常重要的,因为这时开发人员还对这个bug fix非常熟悉,也就会更快地做出相应处理。

"There's never a bad time to send upstream." bug fix patch跟其他类型的patch有一个不同点,就是在开发周期的任何时候都欢迎大家发送bug fix到mailing list。没有必要等待合并窗口,或者等到有特定的发布候选版本。他说:"如果你看到一个bug fix,认为它是非常有用的,就不要坐等,马上把它发出来吧"。

一旦某个patch通过review,接受到了维护者的code tree中,接下来它通常也会进入linux-next代码tree,这意味着它会开始经受一堆的测试(大部分是来自各种机器人)。另外,KernelCI这个持续集成项目也会在各位维护者的代码tree上运行测试。这些都会作为第一个测试标准,来选出那些合适的stable fix。

还有一个stable-next的测试tree,它会拉取linux-next树中被标记为stable但是尚未合入Torvalds的代码tree中的patch。这里的设想是,这个tree中的测试失败很可能会是由那些正在进入stable tree的patch引起的,所以这样一来就能尽量暴露出这些问题。Levin说:"我们不希望这些问题被linux-next中的其他问题给掩盖掉"。这样做也有助于发现那些被后来的patch修复了的patch,尽管这些patch还没有合入upstream;如果一个stable-tagged fix其实是一个新bug,那么就可以把它隔离在稳定树之外,直到它的fix合入mainline之后才会考虑它。

Into the mainline

一旦patch合并到mainline,就会经过更多的,其中许多测试都是由内核开发者而不是机器人运行的。这是也将有更多的机会接触到不同的workload和硬件。他说,stable tree的维护者对人们在测试mainline方面所做的所有工作都非常感谢,因为这有助于使stable tree变得更好。

如果mainline中的patch没有打上stable tag,但是看起来像是一个bug fix,它就会被提交给 AUTOSEL 这个bot,它其实是一个用于寻找bug fix的神经网络工具。AUTOSEL 会查看补丁的各个部分:它的作者、commit message、signoff、所更改的文件以及某些代码的结构,来确定这个patch是否是一个应该加上stable tag的bug fix。

他说,当一个patch到达mainline时,才是stable tree维护者真正开始工作的时候。每一个被带入stable tree的patch,都会有一位维护者进行review。他们人工查看每一个patch,试图确保它是正确的、并且适合stable kernel。来自AUTOSEL推荐的patch会有一周的额外review时间,希望能剔除AUTOSEL误选出来的patch。当patch在排队进入stable tree时,我们会给作者发一封邮件,通知他们patch已经准备好合入了,这样他们如果认为patch不合适合入stable tree、或选错了stable tree的话,就可以提出异议。

stable tree的维护者会尽量避免修改那些不能干净利落地apply到特定代码tree上的patch。Levin指出,可以利用他的dependency-chain Git repository来找到一组能不经过修改就合入patch。他说:"我们宁可多打几个patch来让某个patch可以直接apply从而基于这个干净的环境来进行编译和测试,也不愿意来直接修改这个patch"。还可以通过检查这个dependency chain来帮忙找到其他一些没有被打上stable tag的bug fix patch。

一旦一个补丁进入队列等待合入某个stable release,它就会被许多自动测试系统(就是linux-next上运行的同样一批测试)来再次测试一次。这些代码tree会随着新补丁的加入而不断创建出来,所以每个测试失败都很可能是来自最新加入的patch。与linux-next相比,stable queue tree上的patch要少得多,所以更容易对它们进行检查来看看是不是缺失某些patch,是否导致regression等。

每周里面,会tag标记处移到两个release candidate。这 "又会发出一封邮件",通知开发者他们的补丁已经进入stable release candidate。这给了开发者又一次机会来提出反对意见,或者纠正patch和stable tree不适用的错误。Levin说,release candidate也会用真实的workload来进行测试:stable tree的用户在他们的数据中心和测试现场中对它们进行测试。他说,这些测试通常比mainline的release canddiate所经受的测试更加全面,因为这里"实际最终用户"也参与了进来。

担心稳定版内核出现regression的人都会被鼓励来参与到这个过程中,直接适用它们自己的workload来进行测试。stable tree的维护者不希望发布有regression问题的kernel,所以他们很期待听到用户提出的问题,任何问题都好。他说,这个过程是相当 "free form" (形式多样),所以那些不想公开介绍自己workload的公司仍然可以私下向stable tree的维护者报告他们遇到的问题。他们会尽一切努力在版本发布前解决所发现的问题,以便最大限度地减少或消除regression。

Aftermath

stable kernel发布出去之后,维护者还有更多的工作要做。他们要监控mailing list中的fix和bug report,看哪些会也影响到stable kernel里的新增patch的。发现这类问题的话,维护者会迅速地把它们加入到下一个stable release中,以减少regression或bug在stable kernel中停留的时间。

Levin说,stable 维护者的目标之一是对kernel的测试和验证策略整体上进行改进。有一种观点认为,稳定内核应该只合入尽量少的改动,"因为它需要是稳定的"。但如果是这样的话,就意味着这个stable tree上缺少了许多很重要的bug fix。解决这个问题的方法不是少打补丁,而是 "加强内核的测试方案"。维护者在和KernelCI和0-Day testing service等项目合作来帮助确保它们能正常工作的同时也拥有所需的资源。

stable tree的维护者还需要监控downstream的代码tree,比如Ubuntu和Fedora的kernel tree。如果一个patch在发行版的内核中,但是不在upstream的内核中,那么也许它其实应该加到upstream kernel中,尤其是我们确认它真的做了有效的fix的话。同样,他们也会监控各个厂商和发行版的bug跟踪系统,从中寻找可能需要添加到stable kernel的bug fix。最近,他们一直在研究一些比较老的stable kernel,看看是否有应该打的bug fix还没有打上去。每当发现一个,他们就会添加到那些较老的stable tree中。

stable kernel process这个工作流程中有许多保障措施,来确保不要在这些kernel中导致regression。stable kernel比mainline "way better tested(测试得更好)",因为他们的测试中利用到了真实有效的workload,而不是 "just developers trying it on their laptops(只是开发人员在笔记本电脑上试玩)"。他说,可以看到regression发生概率很低,尤其是与mainline相比。所以大家应该放心地接受每一个新的stable kernel release。另外,旧的stable kernel中已经fix的问题,在新的stable kernel中一定是也有了fix的,所以升级到新的stable release至少不会引入来自stable process中的质量回退问题。

 [Sasha Levin和会议UI]

讲座结束时,穿着变了样的Levin出现在了视频会议会场中,回答了会议系统中聊天界面所提交给他的一些问题。其中一个人问到了stable maintainer和Civil infrastructure Platform这种项目之间的合作问题,这些项目也在维护kernel,并且会支持更长的时间。Levin表示,他们和这些项目之间的patch会有双向传递,并且围绕KernelCI和其他测试计划也有很多合作。在回答另一个问题时,Levin说,他希望来自syzbot fuzz测试的failure reproducer工具可以今后加到stable tree中来作为测试的一部分。他还承认,未来可能需要一个 "not for stable"的tag,不过目前在commit message中的注解现在也可以达到类似的作用,不过希望能附带上原因来解释为何不适用于stable tree。

虽然演讲很有趣,但还是让人有些不满意,视频会议还是比不上面对面的会议。但这是一个趋势,至少在一段时间内是这样的。甚至可能在疫病结束之后也是如此。大家聚在一起还是会导致相当多的碳排放的。从各个方面来看,stable kernel的流程看起来进来运行的非常不错,维护者都很用心,也有许多测试,有大量的bug fix都发送到了用户手中。Levin的演讲绝对是一个受人欢迎的内情介绍。

全文完

LWN文章遵循CC BY-SA 4.0许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注LWN深度文章以及开源社区的各种新近言论~

<think>我们正在讨论如何系统性地学习Linux kernel原生接口。用户之前的问题涉及dma_alloc_coherent函数,但当前问题转向了更广泛的学习方法。参考站内引用,我们有几个关键点: 引用[1]提到了内核同步机制和临界区域,这是内核编程的重要基础。 引用[2]提到内核开发包(kernel-devel)包含头文件和链接库,这是开发内核模块所必需的。 引用[3]介绍了虚拟化技术,这是内核的一个重要功能模块。 引用[4]则提出了一些内核级问题,如Kubernetes调度器、eBPF等,这些是内核的高级应用。 因此,系统性学习Linux内核原生接口需要从基础到高级,逐步深入。以下是一个分阶段的学习路径: 第一阶段:基础准备 1. 掌握C语言和数据结构:内核开发主要使用C语言,需要熟练掌握指针、结构体、内存管理等。 2. 了解操作系统原理:进程管理、内存管理、文件系统、设备驱动等概念。 3. 熟悉Linux基本使用:命令行操作、编译、调试工具(如gcc, gdb, make等)。 第二阶段:内核基础知识 1. 内核源码获取与编译: - 下载源码(如从kernel.org) - 编译内核(配置、编译、安装) - 安装内核开发包(如引用[2]提到的kernel-devel) 2. 内核模块编程: - 编写简单的模块(Hello World) - 模块的加载和卸载 - 模块参数传递 3. 内核基础API: - 内存管理(kmalloc, vmalloc, kfree等) - 进程管理(进程创建、调度等) - 同步机制(如引用[1]提到的,学习自旋锁、信号量、互斥锁等) 第三阶段:深入内核子系统 1. 设备驱动开发: - 字符设备驱动 - 块设备驱动 - 网络设备驱动 - 学习使用DMA(如之前讨论的dma_alloc_coherent) 2. 文件系统:VFS接口,实现简单文件系统。 3. 网络协议栈:socket实现,网络设备驱动。 4. 虚拟化技术:如引用[3]提到的,学习KVM、容器技术等。 第四阶段:高级主题 1. 性能优化:分析内核性能瓶颈,使用perf等工具。 2. 安全机制:SELinux、AppArmor等。 3. 实时内核(PREEMPT_RT)。 4. 最新技术:如引用[4]提到的eBPF、Firecracker微VM等。 学习资源推荐: - 书籍:《Linux设备驱动程序》、《深入理解Linux内核》、《Linux内核设计与实现》 - 在线资源:kernelnewbies.org, lwn.net - 实践:动手编写内核模块,参与开源项目(如为内核提交补丁) 注意事项: - 内核开发需要谨慎,错误的代码可能导致系统崩溃。 - 使用版本控制(如git)管理代码。 - 调试工具:printk, gdb, kgdb, kdump等。 最后,学习内核是一个长期的过程,需要不断实践和阅读源码。 下面,我们将按照这个思路给出详细回答。</think>要系统性地学习Linux内核原生接口,需要结合理论、实践和源码分析。以下是分阶段的学习路径: --- ### 一、基础准备阶段 1. **掌握核心知识** - **C语言**:精通指针、结构体、内存管理(如`kmalloc`/`kfree`) - **操作系统原理**:进程调度、内存管理、文件系统、中断处理 - **硬件基础**:CPU架构(如x86/ARM)、内存映射、DMA机制(参考引用[1]同步机制) 2. **环境搭建** - 安装内核开发包(如`kernel-devel`,包含头文件与符号表[^2]) - 配置QEMU虚拟机 + GDB调试内核 - 获取内核源码:`git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git` --- ### 二、内核接口学习路径 #### 1. **模块编程入门** ```c // 示例:Hello World模块 #include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("GPL"); static int __init hello_init(void) { printk(KERN_INFO "Hello Kernel!\n"); return 0; } static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye Kernel!\n"); } module_init(hello_init); module_exit(hello_exit); ``` - 编译加载:`insmod hello.ko` - 关键接口:`printk`、`module_init`、`module_exit` #### 2. **核心子系统实践** | **子系统** | **关键接口** | **实践项目** | |------------------|----------------------------------|-----------------------------| | **进程管理** | `fork()` `sched_setscheduler()` | 实现实时优先级进程 | | **内存管理** | `kmalloc()` `vmalloc()` | 分配DMA内存(如引用[1]场景) | | **设备驱动** | `file_operations`结构体 | 字符设备驱动(如虚拟键盘) | | **网络协议栈** | `net_device_ops` | 虚拟网卡驱动 | | **虚拟化** | KVM API(参考引用[3]) | 创建微虚拟机 | #### 3. **同步机制深入** - **原子操作**:`atomic_t`类型与`atomic_inc()` - **锁机制**: ```c spinlock_t my_lock; spin_lock_init(&my_lock); spin_lock(&my_lock); // 临界区开始 /* 操作共享数据 */ spin_unlock(&my_lock); // 临界区结束 ``` - **场景分析**:解决引用[1]中的抢占问题(关闭抢占`preempt_disable()`) --- ### 三、进阶学习:源码与工具 1. **源码阅读方法** - 使用`cscope`/`ctags`跳转函数定义(如查`dma_alloc_coherent`实现) - 重点目录: - 内存管理:`/mm/` - 进程调度:`/kernel/sched/` - 设备驱动:`/drivers/` 2. **调试与性能工具** | **工具** | **用途** | |---------------|----------------------------------| | `printk` | 内核日志输出(需`dmesg`查看) | | `ftrace` | 函数调用跟踪 | | `perf` | 性能分析(CPU缓存、调度延迟) | | `eBPF` | 动态追踪(参考引用[4]) | --- ### 四、学习资源推荐 1. **书籍** - 《Linux设备驱动程序》(O'Reilly) - 《深入理解Linux内核》(Understanding the Linux Kernel) 2. **在线资源** - [Kernel Newbies](https://kernelnewbies.org/):内核API文档 - [LWN.net](https://lwn.net/):内核技术文章 3. **实践平台** - 参与Linux内核邮件列表(LKML) - 提交简单内核补丁(如文档修复) --- ### 五、关键注意事项 1. **安全规范** - 内核代码无内存保护,指针错误直接导致Oops - 用户空间数据必须用`copy_from_user()`验证 2. **版本兼容性** - 接口可能随内核版本变化(如`request_irq()`参数变化) - 使用`#if LINUX_VERSION_CODE`处理兼容性 3. **性能陷阱** - 避免在中断上下文中阻塞(如用`spin_lock`替代`mutex`) - DMA内存必须对齐(`dma_alloc_coherent`自动处理) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值