内核中的notification chain浅析

内核中的很多子系统都是联系很紧密的,因此有可能某个子系统的某些事件,其他多个子系统都很感兴趣,此时就需要用到notification chain.

举个具体的例子,比如说一台主机由于某个网卡的损坏或其他原因不能使用,从而导致连接此网卡的网络不能使用,这个时侯就是notification chain.来通知路由表去除这个网络的路由表项。

notification chain就是一个链表,包括了所有当某个事件发生时当前子系统所需要执行的函数,而这些函数是被其他的子系统注册到nc(下面notification chain就简称nc了)里。


下面来看源码.

首先来看nc的数据结构(include/linux/notifier.h):

notifier_call也就是将会执行的回调函数,next指向下一个nc节点,priority是优先级,优先级高的节点会先执行。

struct notifier_block {
int (*notifier_call)(struct notifier_block *, unsigned long, void *);
struct notifier_block *next;
int priority;
};


注册到一个nc上:
这里我们使用notifier_chain_register来实现注册。

这里遍历nc然后按照优先级来插入相应的位置(也就是插入到优先级比自己小的之前)
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;
}


在nc上唤醒一个事件,也就是执行相对应的函数:

notifier_call_chain方法.

第一个参数为nc,第二个参数为事件类型,第三个参数为传给回调函数的参数,第三个和第四个参数分别为nc已经遍历的数目。

事件类型值可以看notifier.h中定义的。
流程很简单就是遍历此nc,然后调用相应的回调函数。

static int __kprobes 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(*nl);

while (nb && nr_to_call) {
next_nb = rcu_dereference(nb->next);
///基本上所有的回调函数里面都会使用switch语句,通过判断不同的event值来执行不同的操作。
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;
}



这里还要注意下,一般上来说内核都会对上面的注册和执行函数进行包装。

内核中至少有10种不同的nc,比如inetaddr_chain就是本地网络地址的改变等等事件所触发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值