Linux 内核特性演进史
鄙人不是什么大神, 只是一个对 Linux 内核非常感兴趣的内核屌丝, 在自己工作之余, 喜欢写一个总结的内容分享出来.
个人理解, 对于知识不细究, 不总结, 学到的东西永远不成系统. 不系统的知识永远只是一盘散沙.
1 Linux 内核学习方法
1.1 发问
在上学的时候一直就是内核很产生了兴趣.
刚开始本科那会搞嵌入式, 当时主要在开发上层应用, 但是偶尔也需要重新编译下内核, 改改内核参数. 虽然都是照着开发板提供的教程, 无脑操作. 但是却对内核产生了浓厚的兴趣.
硕士的时候, 靠着陈莉君老师的 《Linux内核设计与实现》 入了门, 开始自己看内核源代码. 当时也没加什么技术群, 纯粹靠着一腔热血, 阅读代码, 记记笔记, 写写博客. 遇到没想明白的, 就慢慢琢磨、码代码实践, 虽然痛苦, 倒也充实.
1.1.1 Linux 内核应该如何学习 ?
但是即使代码看了不少, 博客写了不少, 总感觉自己和内核之间隔着一层纱. 好像看的也还算清楚, 但是总有东西隔着, 模模糊糊. 一直在思考, 这层纱, 到底是什么 ? 怎么才能捅破它 ?
-
都说实践出真知. 我实践了不少, 但是真知还是没摸透, 至少只是一知半解, 甚至仔细想想, 可能一知半解都不算.
-
都说功夫不负苦心人. 功夫下了不少, 花了多少个日日夜夜, 分析代码, 做实验, 但是内核的学习还是没学到"内核".
问题出在哪里? 内核到底该怎么学, 才能让自己成长最快, 理解最深?
1.1.2 我们与社区的一些大牛的差距在哪里 ?
看着社区邮件列表里面各路大神, 各显神通. 各种 bugfix, 各种特性, 甚至各种性能优化补丁简直信手拈来. 大佬们之间侃侃而谈, 相互之间的讨论内精确到每个细节, 外扩展到对相关特性的影响. 看着每天邮件列表的一封封邮件, 让自己有一种恍惚:内核可能没那么难.
不, 难于不难, 只是对人.
想起来一句话, 人与人之间的差距, 有时候比人跟猩猩要大.
话虽然难听, 但是在理.
所以我们跟社区大佬之间的差距在哪里?
很长时间我一直在思考这个问题. 社区的大牛们, 在早期就参与内核开发, 对所负责模块及其相关, 有一个非常清楚的认知. 这个认知是形成了一个玩咸亨的体系的.
他们从这个模块最初的时候就开始参与, 一点点实现, 一点点优化, 他们清楚的了解整个开发的历史, 也知道每个子特性、子优化的实现细节.
-
包括当前模块的设计思路和整体框架, 有没有备选方案, 为什么选择当前这个方案. 所有的这些方案有什么优点, 有什么缺点. 哪里还能继续改进.
-
当前对该模块的这些改动都需要注意哪些细节, 可能影响哪些模块. 会导致什么样的问题.
总结来说, 大佬们长期参与, 对当前模块形成的知识体系, 不是简单看代码、解决几个问题, 就可以形成的. 这是对整个模块全局的把控. 这个知识体系自顶向下, 逐步细化. 包含了模块中每个子模块子特性的总体和细节.
如果把这个模块比作一颗树. 那么树干就是对整体的认知, 而每个大的树杈都代表着一个子特性, 而依附在每个树杈上细小的树枝, 则是各个子特性细节的, 每个树枝上的树叶和新芽, 则是这些细节的各种详细的描述和理解.
这棵树上结出了无数的果子, 但是只有我们爬过(学习)了买个树杈, 摸索了每个细节(果子所在的树枝), 才能收获果实.
而随着时间的推移, 内核不断发展, 这棵树(内核子模块, 不如调度、内存管理、文件系统等)也更加繁盛. 而我们攀爬它摘果子的难度就会越来越大.
如果想做内核这个模块有深入的理解. 那么我们必须构建这个模块完整的知识体系. 虽然困难, 但是也不是不可行. 我们也是需要顺着树的脉络和枝杈, 不断摸索, 不断地去了解他. 方法也是:自顶(根和树干)向下(树叶), 逐步细化. 从树根开始爬起, 慢慢的爬过一个树杈, 接着另外一个.
PS : 当然你也可以走捷径. 如果你使用工具把果实摘下来, 那么我们可以理解为, 是别的兄弟(工具)帮你摘的果实. 所以这不在我们讨论的范畴.
1.1.3 如何形成系统的内核知识 ?
因此自己在学习内核的过程中, 一直在思考怎样让自己的知识成体系, 而不是一盘散沙.
我们学习内核的过程其实和一颗颗树苗茁壮成长, 最后发展成一个森林的过程很像. 我们把内核中每个模块都当成一个小树苗, 我们学习就是呵护这些小树苗成长成参天大树. 当然我们建议, 我们先培养一颗参天大树, 这颗树会成为我们整个森林(知识体系)中最繁茂, 最稳固的根基, 为我们其他模块(树苗)遮风挡雨, 庇护他们成长.
我们是一名勤劳的护林员, 天天梦想着种出一片森林, 但是我们一直不知道该怎么办.
1.2 内核学习路线(方法论)
1.2.1 第一个阶段(萌芽)
首先你需要了解一些操作系统相关的基础概念和原理. 这种通过一些教材或者概要性的书籍来获取就可以了. 如果你是科班出身或者已经对这些概念了熟于心, 请忽略此阶段. 这个阶段完成后, 我们的森林中已经有了一颗颗破土而出的小树芽, 我们具备了内核的一些基础知识, 但是刚刚萌芽, 并不繁茂.
1.2.2 第二个阶段(繁盛)
你可以从自己感兴趣的某个模块入手, 去阅读 Linux 内核代码. 这个过程也可以结合一些书籍来看, 特别是一些附带源码分析的书籍. 这对你对整个模块的体系和原理有一些深入的理解. 这个过程由浅入深.
-
首先抓总概, 结合一些书籍和博客等的内容, 去阅读代码, 要对整个内核各个模块的思路和框架有一个比较清楚的认知. 这里推荐看陈莉君老师的 《Linux内核设计与实现》. 这个阶段完成后, 我们的小树芽已经开始成长, 成长为一颗颗小树苗, 依旧不繁盛, 但是已经有了自己的树干, 一些枝叶,
-
接着抠细节, 这个阶段, 针对某个单独的模块, 某个单独的特性, 结合书籍的内容, 精读代码, 不要只是看懂代码的实现, 要多思考为什么这么设计. 遇到想不通的问题, 多问, 多想. 不要放过一些关键的细节. 这个阶段辅助看一些附带内核源代码注解的书籍, 帮助自己理解. 比如《深入理解 linux 内核》、《奔跑吧 Linux 内核》、《深入linux内核架构》、《linux内核源代码情景分析》等. 这个阶段完成后, 我们的小树苗已经长大了, 枝繁叶茂, 能够撑起自己的一小片天地.
-
实践是检验真理的为一真谛, 也是你巩固知识的必走途径. 这个阶段, 看到不懂的, 没想明白的, 多做一些实验, 多码一些代码, 看现象, 分析流程. 这样会让你对特性的理解更深刻, 细节也更清楚. 必走途径. 这个阶段, 看到不懂的, 没想明白的, 多做一些实验, 多码一些代码, 看现象, 分析流程. 这样会让你对特性的理解更深刻, 细节也更清楚. 这个阶段完成后, 我们的小树苗已经是一颗大树, 有了自己的一片天地, 可以遮风挡雨(定位问题, 解决BUG).
-
3 过程中对某个特性, 一定多翻阅邮件列表中对该特性的讨论, 同时要多看 git log 的历史. ①一个特性合入主线往往是经历了多个版本的, 而越早期的讨论, 对设计方案上的讨论可能更多. 甚至有一些讨论是在相关联的补丁中. 因此翻阅邮件列表的讨论会让你了解为什么这么设计, 以及设计方案的更多细节. ②一个特性自合入后, 不可能一成不变, 或 bugfix、或优化、或重构, 翻阅 git log 历史, 查看该特性的相关修改, 相关合入, 能让你对该特性有一个更全面的认识.
-
随着这个阶段的不断深入, 我们可以找一些项目练手, 找一些内核相关的开源项目. 通过项目我们将了解更多的细节. 有了这些项目的加持, 我们的大树, 枝叶将更加繁盛.
-
从最感兴趣的模块看起, 将这颗树苗培养成大树之后, 以这颗树为根基, 逐渐扩展到其他模块, 内核的设计思想和理念很相似, 而且很多模块之间剪不断理还乱的联系, 有了这颗大树作为根基, 可以庇护我们了解更多的模块吗, 将其他树苗也培育成参天大树. 然后不断循环往复 2.1, 2.2, 2.3 节的内容. 第二个阶段的目标是, 对所学习的内核模块的实现逻辑有一个清晰的认知. 并且知道整个模块内部的框架, 以及它在整个内核中所处的位置和作用. 当这个阶段不断的往复, 我们将会有一颗最繁茂的大树, 然后伴随着其他繁盛的树木.
-
这个阶段, 主要是一些代码细节和代码细节的掌控和理解, 并且通过一些开发实战, 巩固自己的知识.
关于本章的内容, 我 GitHub 和 CSDN 都有汇总, 也在不断完善和更新.
1.2.3 根基(本章的重点内容)
通过第二个阶段学习, 你已经对代码的实现有一个比较深刻的认识. 在学习的过程中我们不光要知道内核当前的设计, 知道它为什么这么设计, 更要清楚他之前还有哪些设计, 之前的设计存在哪些缺陷, 现在的设计解决了哪些问题, 又存在哪些问题.
在第二个阶段的学习过程中, 一定要善于总结. 这就是我们现在想要说的内容, 这个严格其实来说不能作为一个单独阶段, 因为这个总结的过程应该发生在第二个阶段学习的过程中. 但是它是那么重要, 以至于我们有必要把它拿出来单独讲.
-
第二个阶段我们了解了代码实现, 并很多细节, 同时也通过实践让自己的知识更扎实. 但是他们仍然还没有形成体系. 我们逐渐爬过了树木的每个枝杈, 走过了每个路径. 但是指到每个枝杈上我们可以看到细节, 但是没有一个全局的把握. 通过总结我们把知识点串联起来, 形成一个网. 而这个树木也在我们脑子里面形成了一个图像, 我们知道它总体的样子, 知道它每个枝杈的位置和形状, 知道每个果实的大小和位置.
-
这个阶段的目标是, 让你对各个模块有一个全局的把握. 第二个阶段你已经知道内核的具体实现了, 这个阶段, 我们不光了解到的是整个内核特性演进的历史和现状, 更对所关注模块的发展方向, 优化方向, 会有一个全局的把控. 我们的知识将更加系统, 构成一个知识体系. 在这个阶段, 我们的大树的根会越扎越深, 深入到整个森林土壤的最深处, 亘古不变.
-
社区有很多 Maintainer, 我们跟他们的差距不光是编码水平上的, 更是历史的. 这些 Maintainer 大多数都是在内核早期开发过程中, 不断开发, 不断演进的过程中实战出来的. 他们懂的, 不光是当前的代码实现, 他们更清楚历史上的一些问题. 所以他们对内核整个模块有一个清晰的脉络, 更对这个模块的发展和演进, 有一个清楚的认知. 而这些我们是欠缺的, 也正是我们需要补齐的. 当然跟 Maintainer 肯定会有差距, 但是至少对我们的眼界会十分有益.
1.2.4 历史的眼光和发展的眼光
要带着发展的眼光看内核代码,你现在看到的代码是这个样子的。
-
那它历史上可不一定是这样子的,需要你去回顾它。
-
它以后也不一定还是它现在的样子,需要你去不断的关注。
-
这个阶段可以跟踪下社区的进展, 内核代码是在不断发展和演进的, 要带着发展的眼光看, 时刻关注社区的动向. 完善和丰富我们的知识体系. 这些信息可以通过关注社区邮件列表、kernelnewbies 和 LWN 来获取.
-
关于已经合入的特性的历史信息, 同样可以从邮件列表的归档记录和 Patchwork 等地方获取. 主线合入的内核的特性, 往往都是通过不断的改进, 经过了 N 轮重构和 review 才合入的主线, 而越早期的讨论, 涉及的内容可能更多, 也更容易大家理解. 对于一些特性, 不理解它为什么这么实现的时候, 去找当时社区邮件列表的讨论, 往往是最直接有效的途径.
博客本章以及其展开的内容, 就是为了帮助大家构建内核的知识体现,了解内核各个模块的前世今生, 有了这个知识体系, 我们在不断继续第 2 阶段的学习迭代时, 会更加融会贯通.
本章的内容, 将不断更新 :
* 采用 TOPDOWN 自顶向下的学习方法, 从每个内核子模块入手, 将每个子模块不断细化. 完善整个内核的技能树.
* 不断更新各个模块, 各个特性的历史特性
* 不管跟进社区最新的进展;
由于工作的原因, 更新可能不会太快, 但是我有时间就会写.
2 Linux 内核特性演进史
本文
-
最早的启发来自于 2017 年淘宝内核组内核月报的断更.
-
最直接的导火索来自于知乎上的一个问答.
2.1 启发(内核月报)
这里的内容, 最早的想法和计划来自于 2017 年. 起因是当时一直关注的阿里淘宝内核组的 "内核月报" 忽然出现网络下线, 停止更新. 其中缘由不得而知, 但是萌生了自己维护 "内核月报" 的想法. 虽然后来改团队改组后, 在该域名的重新上线了新博客 阿里云智能基础软件部-技术博客, 但是之前 "内核月报" 的内容 不复存在.
现在我最懊悔的事情, 就是:
当时内核淘宝组的 "内核月报" 我嘴上一直说要本地归档下, 本地归档下, 但是因为自己的 "懒惰" 和 "借口", 未付诸实施.
导致现在全网估计只剩下一些 CSDN 和 博客园上一些零星的转载, 不成气候......
"内核月报" 的下线和停更, 不止是惋惜. 满满的干货, 就这样消失, 心中甚是不甘. 但是他们的精神和对技术的追求, 将引领我不断成长.
2021 年 05 月 01 日 更新
宋宝华老师的 <Linux 阅码场> 近期开始更新 "内核月报" 的内容
不过目前 <Linux 阅码场> 只维持了几期更新, 断更中, 鄙人将持续关注.
2.2 自身原因(自顶向下的分析方法)
之后一直处于筹划阶段, 未进行实质的开展, 其中主要纠结的地方有两点:
-
其中的工作量几何, 自己还是拎得清的, 自知以自己的能力和精力, 难以为继.
-
Linux Kernel Newbies 已经有各个 Kernel 版本的 ChangeLog LinuxVersions - Linux Kernel Newbies, 自己之前也是淘宝内核月报和 Kernel Newbies 结合着一起看的. 即使内核月报停止更新, Kernel Newbies 也还在, 自己维护一套是否有必要, 是不是在浪费自己的宝贵时间.
后来纠结良久, 决定开始整理一套与 淘宝内核月报和 Kernel Newbies 不同的一套 ChangeLog.
内核月报的形式基本是以内核版本为界, 分析当时版本的主线内核合入, 是属于一种平行化的分析方法. 可以通过分析内核社区的动态, 扩充知识面, 开阔自己的眼界. 但是对自己的知识体系的构建帮助意义不是很好.
但是如果换一种思路, 改成垂直化的分析方法, 利用 TOPDOWN 自顶向下的分析方法, 垂直化的分析内核各个模块的 ChangeLog.
-
不光能够达到内核月报同样的效果, 更重要的是, 对各个模块的历史和发展会更加清晰, 知识体系会更加完善. 一举岂止多得.
-
不仅限于所有合入主线的特性, 也要分析所有邮件列表中公开的, 以及邮件列表中未公开, 但是各个厂商和发行版开源的一些优质特性.
有了这个想法后, 种子埋下了, 慢慢的生根, 萌芽.
因为工作的原因, 时间很少挤得出来. 时间一转眼来到了 2020 年, 逛某呼, 发现了 知乎大神 larmbr宇 2015 年对知乎提问 现在的 Linux 内核和 Linux 2.6 的内核有多大区别 的回答.
额 ? 等等, 这不就是我一直想做的. 额......
不忘初心, 方得始终, 而我一直以工作忙的原因, 放弃了自己当初的想法, 这不是一个对技术有执着追求的人该做的事情.
所以, 观众朋友们, 我鸡血已经备足了, 干饭, 搞起......
2.3 导火索-一个知乎的问答引发的"干饭"激情
本文最早是 知乎大神 larmbr宇 2015 年对知乎提问 现在的 Linux 内核和 Linux 2.6 的内核有多大区别 的回答, 鄙人当时看到后, 叹为观止, 这不正是我一直希望做的, 但是作者已经不再维护, 甚是惋惜, 因此接手维护, 希望能尽自己的一份微薄之力.
注:
鄙人不是什么大神, 只是一个对 Linux 内核非常感兴趣的人肉转码机, 在自己工作之余, 不希望原作者的神作, 因为时间的推移, 随着 Linux 社区的不断壮大而蒙尘.
接手更新原作者的这篇神作, 我只是站在巨人的肩膀上, 让这篇文章不断的与时俱进.
因个人能力有限, 文章内容有错误再所难免, 请您一定要批评指正. 欢迎随时叨扰, 联系方式我稍后奉上.
gatieme 记于 2020/10/07 22:51.
联系方式:
WeChat : gatieme
EMAIL : gatieme@163.com
这个问题挺大的.
2.6 时代跨度非常大, 从2.6.0 (2003年12月发布[36]) 到 2.6.39(2011年5月发布), 跨越了 40 个大版本. 3.0(原计划的 2.6.40, 2011年7月发布) 到 3.19(2015年2月发布). 4.0(2015年4月发布)到4.2(2015年8月底发布).
总的来说, 从进入2.6之后, 每个大版本跨度开发时间大概是 2 - 3 个月. 2.6.x , 3.x, 4.x, 数字的递进并没有非常根本性, 非常非常非常引人注目的大变化, 但每个大版本中都有一些或大或小的功能改变. 主版本号只是一个数字而已. 不过要直接从 2.6.x 升级 到 3.x, 乃至 4.x, 随着时间间隔增大, 出问题的机率当然大很多.
个人觉得 Linux 真正走入严肃级别的高稳定性, 高可用性, 高可伸缩性的工业级别内核大概是在 2003 年后吧. 一是随着互联网的更迅速普及, 更多的人使用、参与开发. 二也是社区经过11年发展, 已经慢慢摸索出一套很稳定的协同开发模式, 一个重要的特点是 社区开始使用版本管理工具进入管理, 脱离了之前纯粹手工(或一些辅助的简陋工具)处理代码邮件的方式, 大大加快了开发的速度和力度.
因此, 我汇总分析一下从 2.6.12 (2005年6月发布, 也就是社区开始使用 git 进行管理后的第一个大版本), 到 4.2 (2015年8月发布)这中间共 51个大版本, 时间跨度10年的主要大模块的一些重要的变革.
感谢知友 @costa 提供无水印题图)
2.4 其他类似资料
Linux 内核学习资料:200 + 篇经典内核文章,100 + 篇内核论文,50 + 内核项目,500 + 道内核面试题,80 + 内核讲解视频
3 内容目录
| 内容 | GITHUB |
|---|---|
| 调度子系统(Scheduling) [DOING] | SCHEDULER |
| 内存管理子系统(Memory Management) [DOING] | MEMORY_MANAGER |
| 热补丁(Live Patching) [DOING] | LIVE_PATCH |
| 中断与异常子系统(interrupt & exception)[填坑中] | |
| 时间子系统(timer & timekeeping) | |
| 同步机制子系统(synchronization) | |
| 块层(block layer) | |
| 文件子系统(Linux 通用文件系统层VFS, various fs) | |
| 网络子系统(networking) | |
| 调试和追踪子系统(debugging, tracing) | |
| 虚拟化子系统(kvm) | |
| 控制组(cgroup) |

