Linux|龙蜥开源Plugsched:首次实现 Linux kernel 调度器热升级( 三 )


对于函数而言 , 调度器模块对外呈现了一些关键的函数 , 以这些函数为入口就可以进入模块中 , 我们称之为接口函数 。 通过替换内核中的这些接口函数 , 内核就可以绕过原有的执行逻辑进入新的调度器模块中执行 , 即可完成函数的升级 。 模块中的函数 , 除了接口函数外 , 还有内部函数 , 其它的则是外部函数 。
对于数据 , 调度器模块默认使用并继承内核中原有的数据 , 对于调度器重要的数据 , 比如运行队列状态等 , 可以通过状态重建技术自动重新初始化 , 这类数据属于私有数据 , 而其它则是共享数据 。 为了灵活性 , plugsched 允许用户手动设置私有数据 , 手动设置的私有数据会在模块中保留定义 , 但需要对它们进行初始化 。 对于结构体而言 , plugsched 将只被调度器访问的结构体成员分类为内部成员 , 其它为非内部成员 。 调度器模块允许修改内部成员的语义 , 禁止修改非内部成员的语义 。 如果结构体所有成员都是内部成员 , 则调度器模块允许修改整个结构体 。 但是 , 建议优先使用结构体中的保留字段 , 而不是修改现有成员 。
设计方案
Plugsched 主要包含两大部分 , 第一部分是调度器模块边界划分与代码提取部分 , 第二部分是调度器模块热升级部分 , 这两部分是整个方案的核心 。 其整体设计方案如下:
图2 plugsched 整体架构
首先进行的是调度器模块边界划分和代码提取流程 , 由于调度器本身并不是模块 , 因此需要明确调度器的边界才能将它模块化 。 边界划分程序会根据边界配置信息(主要包含代码文件、接口函数等信息)从内核源代码中将调度器模块的代码提取到指定目录 , 然后开发人员可在此基础上进行调度器模块的开发 , 最后编译生成调度器 RPM 包 , 并可安装在对应内核版本的系统中 。 安装后会替换掉内核中原有的调度器 , 安装过程会经历以下几个关键过程:
符号重定位:解析模块对部分内核符号的访问 栈安全检查:类似于 kpatch , 函数替换前必须进行栈安全检查 , 否则会出现宕机的风险 。 plugsched 对栈安全检查进行了并行和二分优化 , 提升了栈安全检查的效率 , 降低了停机时间 接口函数替换:用模块中的接口函数动态替换内核中的函数 调度器状态重建:采用通用方案自动同步新旧调度器的状态 , 极大的简化数据状态的一致性维护工作 总结:基于以上介绍 , 整体来看 , Plugsched 使得调度器从内核中解放出来 , 开发人员可以对调度器进行专项定制 , 而不局限于内核通用调度器;内核维护也变得更加轻松 , 因为开发人员只需要关注通用调度器的开发与迭代 , 定制化调度器可通过 RPM 包的形式进行发布;内核调度器代码也会变得简洁 , 无需再被各个场景的优化混淆起来 。
未来 , plugsched 会支持新版本内核和其它平台 , 持续对其易用性进行优化 , 并提供更多的应用案例 。 最后 , 欢迎更多的开发者能参与到 plugsched 中 。
本文为阿里云原创内容 , 未经允许不得转载 。