linux 内核中的一个老角色——tasklets

大家好,今天咱们来聊聊Linux内核中的一个老角色——Tasklets。它们从2.3时代就陪着咱们走过来,一直在处理那些需要延迟执行的活儿。虽然API有点旧了,但因为用起来简单,加上那会儿没别的好法子,所以一直拖着没换。 最近Kees Cook搞了个安全补丁,把tasklet的回调参数给改了,从unsigned long换成了指向tasklet_struct的指针。这一改,直接让它们的一些老毛病暴露了出来,比如不能休眠、不能碰用户空间的数据。特别是在GPU或者网络这种高性能的场景下,这就成了瓶颈。 Peter Zijlstra就站出来说,“我看不如让tasklets像渡渡鸟一样彻底消失”,这话一出,大伙儿就都跟着附和了。大家觉得与其老是打补丁修补漏洞,还不如直接把它们给废掉。 到底为啥非得赶它们走呢?原因有俩。一个是它们在软件中断的原子上下文里跑,这就把它们的手脚给捆住了,没办法像其他线程那样自由切换任务或者访问数据。对于那些要处理网络包、加密数据的驱动来说,这就是个过不去的坎儿。另一个是现在内核里早就有了workqueues、threaded interrupts、timers这些更灵活更安全的新机制。把它们留下只会让代码库变得乱七八糟,维护起来费劲又不划算。 不过要想把这事儿给办成也不容易,得慢慢来。首先得让驱动的作者把原来的DECLARE_TASKLET宏改成tasklet_setup;然后慢慢把剩下的用旧方法的地方都改掉;最后再把剩下的代码全清理掉。比如声音子系统已经把内部的tasklet迁移完了,正在等树外评审呢。 为了照顾还在用老API的驱动作者,补丁里特意加了点兼容的功能。比如定义了一个新的DECLARE_TASKLET宏,回调函数就只认一个tasklet_struct指针;原来的DECLARE_TASKLET改成了DECLARE_TASKLET_OLD,数据字段默认是0;还有个tasklet_setup接口,可以让子系统在运行时按需切换新旧模式。这样一来,开发者就不用从头重写所有代码了,旧项目还能接着跑。 最后咱们再看看相关资源:LWN上有原帖讨论;内核源码里定义了DMA Engine;Linux内核自我保护项目还有GitHub上的issue都在讨论这事;还有LWN那篇旧文。Tasklets的终点可能就在不远的将来某个版本号之后了。不过在这之前,咱们还得一起努力:把最后那几个tasklet用户给清除掉,让内核代码变得更轻盈、更安全、更有未来。