cpu hotplug notifier

如果你的code需要检测当前cpu 是否hotplug的话,可以通过参考下面的sample code
#include <linux/cpu.h>
static int foobar_cpu_callback(struct notifier_block *nfb,
      unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;


switch (action) {
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
foobar_online_action(cpu);
break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
foobar_dead_action(cpu);
break;
}
return NOTIFY_OK;
}


static struct notifier_block foobar_cpu_notifier =
{
  .notifier_call = foobar_cpu_callback,
};


一定要include <linux/cpu.h> 否则会报错
其次调用register_cpu_notifier(&foobar_cpu_notifier);或 register_hotcpu_notifier(&foobar_cpu_notifier); 来注册一个notify,这样当cpu online 或者dead的时候就会调用foobar_cpu_callback
register_cpu_notifier 和register_hotcpu_notifier 没有区别。register_hotcpu_notifier的定义如下:
#define register_hotcpu_notifier(nb) register_cpu_notifier(nb)
然后foobar_online_action 和 foobar_dead_action 就可以处理cpu online 和 CPU_DEAD的情况.
int register_cpu_notifier(struct notifier_block *nb)
{
int ret;
cpu_maps_update_begin();
ret = raw_notifier_chain_register(&cpu_chain, nb);
cpu_maps_update_done();
return ret;
}
register_cpu_notifier 就是将前面定义的notifier_call 添加到cpu_chain 这个list中
int raw_notifier_chain_register(struct raw_notifier_head *nh,
struct notifier_block *n)
{
return notifier_chain_register(&nh->head, n);
}
在raw_notifier_chain_register 中就得到cpu_chain 这个list的head,然后将n添加进去
static int notifier_chain_register(struct notifier_block **nl,
struct notifier_block *n)
{
while ((*nl) != NULL) {
if (n->priority > (*nl)->priority)
break;
nl = &((*nl)->next);
}
n->next = *nl;
rcu_assign_pointer(*nl, n);
return 0;
}
notifier_chain_register 在添加到cpu_chain->head 这个list的时候是分优先级的,优先级从高到低。
当发生cpu hotplug的时候会调用cpu_notify 来通知cpu_chain list上的事件.
static int cpu_notify(unsigned long val, unsigned int cpu)
{
return __cpu_notify(val, cpu, -1, NULL);
}


static int __cpu_notify(unsigned long val, unsigned int cpu, int nr_to_call,
int *nr_calls)
{
unsigned long mod = cpuhp_tasks_frozen ? CPU_TASKS_FROZEN : 0;
void *hcpu = (void *)(long)cpu;


int ret;


ret = __raw_notifier_call_chain(&cpu_chain, val | mod, hcpu, nr_to_call,
nr_calls);


return notifier_to_errno(ret);
}
__cpu_notify 得到当前hotplug的cpu number hcpu ,然后调用__raw_notifier_call_chain
int __raw_notifier_call_chain(struct raw_notifier_head *nh,
     unsigned long val, void *v,
     int nr_to_call, int *nr_calls)
{
return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
}
和注册是一样得到head,也就是list的head的
static int notifier_call_chain(struct notifier_block **nl,
      unsigned long val, void *v,
      int nr_to_call, int *nr_calls)
{
int ret = NOTIFY_DONE;
struct notifier_block *nb, *next_nb;


nb = rcu_dereference_raw(*nl);


while (nb && nr_to_call) {
next_nb = rcu_dereference_raw(nb->next);


#ifdef CONFIG_DEBUG_NOTIFIERS
if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) {
WARN(1, "Invalid notifier called!");
nb = next_nb;
continue;
}
#endif
ret = nb->notifier_call(nb, val, v);


if (nr_calls)
(*nr_calls)++;


if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
break;
nb = next_nb;
nr_to_call--;
}
return ret;
}
就会遍历整个cpu_chain->head ,分别调用notifier_call,这个例子我们注册的notifier_call == foobar_cpu_callback,然后nb = next_nb 来继续迭代进行.
注册notify 肯定是在kernel space进行的,也就是callback的函数地址,要么是在kernel buildin,要么是在module 中,因此notifier_call_chain 中可以可以进行这个判断,前提是要打开CONFIG_DEBUG_NOTIFIERS。
而func_ptr_is_kernel_text 就是判断callback的函数地址是否在kernel buildin 或者 module中
int func_ptr_is_kernel_text(void *ptr)
{
unsigned long addr;
addr = (unsigned long) dereference_function_descriptor(ptr);
if (core_kernel_text(addr))
return 1;
return is_module_text_address(addr);
}
既然是debug选项,个人认为最好通过%pF把function地址对应的symbol 打印出来更好,即改成下面这样
int func_ptr_is_kernel_text(void *ptr)
{
unsigned long addr;
addr = (unsigned long) dereference_function_descriptor(ptr);
WARN(1, "addr = %pF",addr);
if (core_kernel_text(addr))
return 1;
return is_module_text_address(addr);

}


如果想在所以的cpu上运行你的callback,可以参考下面的code,上面的文章看懂了,下面的code理解就很简单了

cpu_notifier_register_begin();
for_each_online_cpu(i) {
foobar_cpu_callback(&foobar_cpu_notifier,
   CPU_UP_PREPARE, i);
foobar_cpu_callback(&foobar_cpu_notifier,
   CPU_ONLINE, i);
}

__register_cpu_notifier(&foobar_cpu_notifier);
cpu_notifier_register_done();


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值