LWN: 5.14 中支持了core scheduling!
共 3626字,需浏览 8分钟
·
2021-07-17 06:03
关注了就能看到更多这么棒的文章哦~
Core scheduling lands in 5.14
By Jonathan Corbet
July 1, 2021
DeepL assisted translation
https://lwn.net/Articles/861251/
core scheduling 这个功能已经讨论了三年多了。对于那些需要这个功能的人来说,好消息是终于不用再继续等待了。它已经被合入了 mainline,会随着 5.14 内核版本发布。现在这项工作(可能)已经到达了最终版,我们有必要再看一下这项功能为什么是有意义的、它的工作机制是什么。core scheduling 功能并不适合每个人,但它对一些用户群体来说已经证明是很有用的了。
同步多线程(SMT,simultaneous multithreading,或称 "超线程,hyperthreading")是一种可以在一个处理器中实现两个或更多的在执行的线程的硬件功能,这样一来,单个 CPU 看起来就像是有一组 "sibling(兄弟)" 的 CPU。当其中一个兄弟 CPU 在执行时,其他的就必须等待了。SMT 很有用,因为 CPU 在等待某些 event 时经常会空闲下来,通常是在等待从内存获取到的数据。当一个 CPU 在等待时另一个就可以执行了。SMT 并不是对所有 workload 的性能都有提升,但对大多数 workload 来说它都是一个重大的改进。
SMT 中的这些兄弟 CPU 共享了 CPU 内部几乎所有硬件,其中也包括 CPU 在维护的这些 cache。这就提供了一种可能性,即其中一个 sibling CPU 可以通过观察 cache 中可以观察到的一些变动,从而提取来自另一个 sibling CPU 操作的数据。Spectre 硬件漏洞使得这个问题变得更加严重了,而且几乎没有办法解决。要想用目前的内核来安全地运行两个互不信任的进程的话,唯一可靠的办法就是完全禁用 SMT,这可是很多人(尤其是云计算供应商)明显感到很不爽的一种做法。
虽然人们可能会争辩说,云计算供应商总是看什么都不满意,不用去管他们的抱怨。但实际上如果有办法能让他们满意的话,那就非常有价值了。其中一种可能性就是允许他们在自己的系统上启用 SMT,同时又能避免他们的一些客户利用其缺陷来攻击其他人。只要能相互不信任的进程不在同一 CPU core 上同时运行,就可以实现这个效果了。云服务的客户经常同时有许多进程在运行(毕竟,大规模地向互联网用户发送垃圾邮件就需要很多并发活动)。如果这些进程可以被限制起来,使得任何一个 CPU core 中的所有 sibling CPU 都只会运行来自同一客户的进程的话,那么我们就可以避免某个垃圾邮件发送者来窃取另一位垃圾邮件发送者的客户列表了,当然也会保护了其他用户的私钥等重要信息。
core scheduling 就可以提供这种隔离。抽象来说,每个进程都被分配了一个 "cookie",代表了它的某种特性。比如可以给每个用户分配一个独特的 cookie。然后,scheduler 会确保实行一条规则:进程只有在具有相同的 cookie 值时才能共享 SMT core,换句话说,也就是只有在它们能相互信任的情况下。
更具体地来说,core scheduling 是通过 prctl() 系统调用来管理的,该系统调用通常定义如下:
int prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
在 core-scheduling 这种操作的情况下,option 值为 PR_SCHED_CORE,其余参数定义为:
int prctl(PR_SCHED_CORE, int cs_command, pid_t pid, enum pid_type type,
unsigned long *cookie);
通过 cs_command 可以选择四种可能的操作:
PR_SCHED_CORE_CREATE,使内核生成一个新的 cookie,并将其分配给进程号为 pid 的进程。type 参数控制这个分配动作的影响范围。例如,PIDTYPE_PID 就是指明只改变它所代表的进程,而 PIDTYPE_TGID 则将 cookie 分配给整个 thread group 线程组。cookie 参数的值必须为 NULL。
PR_SCHED_CORE_GET,查找 pid 对应的 cookie 值,将其存放在 cookie 中。注意,用户空间进程就算拿到 cookie 值,也没有太多用处,仅仅能够用来检查两个进程是否有相同的 cookie。
PR_SCHED_CORE_SHARE_TO,将调用者进程的 cookie 值分配给 pid(如上所述,也是使用 type 来控制影响范围)。
PR_SCHED_CORE_SHARE_FROM,根据 pid 获取 cookie 并将其分配给调用者进程。
当然,一个进程不能随意获取和分配 cookie,这里的判断条件跟一般人们考虑的 "这个进程能否对目标进程调用 trace() " 的条件差不多。它也不可能在用户空间生成 cookie 值,这个限制确保了不相关的进程只会获得完全不相同的 cookie 值。内核只允许 cookie 值在已经有一定程度相互信任的进程之间传播,这样一来就可以阻止恶意进程将自己的 cookie 改为跟目标进程一样的 cookie 值来进行攻击了。
每当一个 CPU 来执行 scheduler 代码时,会先挑出最高优先级的任务,按正常方式运行。如果 core scheduling 启用了,那么接下来就会向 sibling CPU 发送一个 IPI 中断(inter-processor interrupt),每个 sibling CPU 就会相应地来检查这个刚刚得到调度的进程的 cookie 值与本地已经在运行进程的 cookie 值是否相等。如果有必要的话,被中断打断的 CPU 就会切换到另一个拥有相同 cookie 的进程去执行,即使当前正在运行的进程具有更高的优先级也不影响这个结果。如果没有能互相信任的其他进程,那么这个 sibling CPU 就直接闲置下来,直到情况发生变化为止。如果可能的话,scheduler 会在各个 CPU 之间迁移进程来避免这个 sibling CPU 被强制空闲下来。
core scheduling 早期 patch 中的内核调度代码对整个系统来说会引起很大的开销。有时测出来甚至比完全禁用 SMT 更糟糕,这就违反了本来的目标了。不过,在那之后这部分代码已经经历了多次修订,现在显然表现得更好了。不过,毕竟这个机制在极端情况下会导致 CPU 明明有进程等着执行的情况下也会被闲置,因此这个方案总是会有代价的。由于这个原因,Linus Torvalds 也说 core scheduling "对大多数人来说基本没有意义"。不过,针对那些必须要关闭 SMT 不可的情况下,现在这个替代方案很可能是有好处的。
虽然,安全相关的使用场景在推动 core scheduling 的开发,但其实也有其他的场景也迫切希望能拥有这个功能。例如,运行实时进程的系统通常必须要禁用 SMT,因为当 CPU 在需要跟 sibling CPU 争夺硬件资源时,完全无法保证这个 response-time。core-scheduling 可以确保实时进程会独立拥有一个 CPU,同时系统的其他部分可以继续使用 SMT。还有其他情况一些情况也需要这种能控制同一 CPU 上的进程是否可以混合着运行的能力。
因此,尽管 core scheduling 对大多数 Linux 用户来说可能并没有什么用处,但还是有一些用户团体会很高兴看到这个功能最终进入了 mainline。对类似 scheduler 这样的核心、性能敏感的组件上添加这种复杂的逻辑,从来就不是一件容易的事情。但是,只要有足够的决心总能找到办法。参与到这个功能的开发中的开发者们肯定为推动这项工作的成功完成而得到了应有的 cookie。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~