从kprobe注销场景来探讨一下synchronize_sched的使用

首先抛出我的问题:

当我在编译一个kprobe内核插桩模块时,我是这样实现的,先动态申请一块内存,用于存放我的kprobe结构体,然后执行kprobe的注册,完成一系列的内核数据收集之后,执行kprobe注销操作,最后释放内存,那么大家觉得我这个设计有问题吗?

对于初学者可能觉得:没有什么问题呀?kprobe有注册和有注销,内存有申请有释放,怎么出问题的,实际上正确答案就是没有问题。。。哈哈,是不是感觉被我忽悠了一下。

下面我来说说我当时的顾虑,由于我是动态申请的内存,kprobe机制是这样的,注册了对应kprobe handler,那么kprobe找到对应的地址,并且替换int3指令,(当然也可以使用基于ftrace实现的,这里暂时不考虑)。那么当我执行了注销kprobe操作,那么就相当于这个函数又恢复了,入口处的int3指令又被替换回去了,那么后续对该函数与的调用就不会执行我注册的hook函数。那么假设这样一种场景:

如果有一个CPU上正在执行我注销的kprobe handler,那么我的注销动作实际上并不会阻止这个handler的继续运行,那么如果我紧接着把kprobe handler要使用的动态内存给释放掉了,是不是会引发异常?

以上就是我的疑惑,那么到底是不是这样呢?实际上面我也给出了答案了,内核工程师足够优秀,做的足够稳定了。实际上unregister_kprobe在实现时就已经考虑到这种场景了。它在恢复了函数入口处的指令后,并没有立即退出,而是执行了一个函数synchronize_sched,该函数就是保证没有其他在运行的handler的一个关键所在。

那么此时你就更加疑惑了,synchronize_sched到底做了什么操作,它如何知道另外一个handler运行何时退出呢?

这个函数在静默期状态开始执行,并且会等待一个宽限期的时间后返回。所谓的静默期和宽限期,熟悉RCU的应该都多少有些了解,我这里就不做展开了,只针对我的问题场景。

首先需要明确的是synchronize_sched是属于RCU功能的其中一个API,它属于RCU的形式之一(Sched Flavor)。参考如下内核文档:

https://www.kernel.org/doc/Documentation/RCU/Design/Requirements/Requirements.html

内核对于他的实现由两种,一个针对UP架构上使用的,另一种是SMP架构上使用的,也就是多核心机器,现在基本上都是SMP系统了,去看一下相关的实现:

 void synchronize_sched(void)
 {
     rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) &&
                !lock_is_held(&rcu_lock_map) &&
                !lock_is_held(&rcu_sched_lock_map),
                "Illegal synchronize_sched() in RCU-sched read-side critical section");
     if (rcu_blocking_is_gp())
         return;
     if (rcu_expedited)
         synchronize_sched_expedited();
     else
         wait_rcu_gp(call_rcu_sched);
 }
 EXPORT_SYMBOL_GPL(synchronize_sched);

对于sched RCU来说,这个同步操作会等待所有处于读临界区的操作。对于常规的RCU来说,我们可以根据rcu相关的API来找到临界区,而在sched RCU中,则是指的就是所有禁止了抢占的临界区(disable_preempt),因此很多API都可以成为一个RCU读临界区,比如local_irq_save() 、 preempt_disable() 等等以及包含有它们的一些函数。

上面解释了这么多,实际上都是做铺垫,保证kprobe不出问题的关键就是kprobe handler的执行是禁止抢占的,所以它属于上述的一个RCU读临界区。因此它的执行是可以由synchronize_sched来保证同步的。

参考:

https://www.kernel.org/doc/Documentation/RCU/Design/Requirements/Requirements.html
https://manpages.debian.org/jessie-backports/linux-manual-4.8/synchronize_sched.9.en.html
http://linuxperf.com/?p=38

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值