Linux内核中如何确保销毁kmem_cache前所有call_rcu()回调完成?
确保销毁kmem_cache前所有RCU保护数据已释放的正确做法
针对你遇到的场景——要销毁包含RCU保护数据的kmem_cache,但无法通过synchronize_rcu()保证所有call_rcu()释放回调完成的问题,以下是符合内核标准语义的可靠解决方法:
推荐方案(内核5.10+)
直接调用synchronize_rcu_mult() API。这个接口的设计目的就是等待所有已提交的call_rcu()回调执行完毕,不管这些回调是在哪个宽限期提交的。调用完成后,所有之前通过call_rcu()注册的释放slab元素的回调都已经执行完成,此时可以安全调用kmem_cache_destroy()。
兼容旧内核的替代方案
如果你的内核版本不支持synchronize_rcu_mult(),可以采用两步同步的方法:
- 第一步:调用
synchronize_rcu(),等待当前RCU宽限期结束,确保所有正在进行的RCU读操作都已退出。 - 第二步:提交一个空的
call_rcu()回调(比如定义一个空函数作为回调),然后再次调用synchronize_rcu()。 - 原理:RCU回调虽然不保证全局FIFO,但同一个RCU回调链表内的回调是按提交顺序执行的。空回调会排在所有之前提交的释放回调之后,第二次
synchronize_rcu()等待空回调完成时,就意味着前面所有释放slab的回调都已经执行完毕。
关键注意事项
- 执行同步操作前,必须确保已经停止向该
kmem_cache分配新对象,并且所有RCU保护指针的更新操作都已全部完成。 - 绝对不要依赖x86-64架构下的非标准行为,必须遵循内核文档定义的API语义,避免内核版本升级后出现兼容性问题。
内容的提问来源于stack exchange,提问作者Rost
相关产品推荐
相关产品推荐

