Notifier 一文搞懂Linux内核通知链( 二 )

static int notifier_chain_unregister(struct notifier_block **nl,struct notifier_block *n){ while ((*nl) != NULL) {if ((*nl) == n) {rcu_assign_pointer(*nl, n->next);return 0;}nl = &((*nl)->next); } return -ENOENT;}上述的注销函数,就是先找到此节点,然后从链表中删除的一个操作 。
因为插入/删除操作都是临界资源,需要使用rcu机制保护起来 。
同样,内核通过包装核心的注册/注销函数,实现了上述说的四种notifier chain
int atomic_notifier_chain_register(struct atomic_notifier_head *nh,struct notifier_block *n)int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,struct notifier_block *n)int blocking_notifier_chain_register(struct blocking_notifier_head *nh,struct notifier_block *n)int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,struct notifier_block *n)int raw_notifier_chain_register(struct raw_notifier_head *nh,struct notifier_block *n)int raw_notifier_chain_unregister(struct raw_notifier_head *nh,struct notifier_block *n)int srcu_notifier_chain_register(struct srcu_notifier_head *nh,struct notifier_block *n).int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,struct notifier_block *n)通知函数当某种事件需要发生的时候,就需要调用内核提供的通知函数notifier call函数,来通知注册过相应时间的子系统 。
/** * notifier_call_chain - Informs the registered notifiers about an event. * @nl:Pointer to head of the blocking notifier chain * @val:Value passed unmodified to notifier function * @v:Pointer passed unmodified to notifier function * @nr_to_call: Number of notifier functions to be called. Don't care *value of this parameter is -1. * @nr_calls: Records the number of notifications sent. Don't care *value of this field is NULL. * @returns: notifier_call_chain returns the value returned by the *last notifier function called. */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);ret = nb->notifier_call(nb, val, v);//调用注册的回调函数if (nr_calls)(*nr_calls)++;if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)//有停止的mask就返回,否则继续break;nb = next_nb;nr_to_call--; } return ret;}同样内核也提供了四个不同类型的通知函数
int atomic_notifier_call_chain(struct atomic_notifier_head *nh,unsigned long val, void *v)int blocking_notifier_call_chain(struct blocking_notifier_head *nh,unsigned long val, void *v)int raw_notifier_call_chain(struct raw_notifier_head *nh,unsigned long val, void *v)int srcu_notifier_call_chain(struct srcu_notifier_head *nh,unsigned long val, void *v)示例分析通过编写两个文件,一个用来注册事件,另一个用来通知事件 。
notifier.c用来注册事件
#include <linux/kernel.h>#include <linux/module.h>#include <linux/notifier.h>BLOCKING_NOTIFIER_HEAD(test_chain_head);EXPORT_SYMBOL_GPL(test_chain_head);int register_test_notifier(struct notifier_block *nb){ return blocking_notifier_chain_register(&test_chain_head, nb);}int unregister_test_notifier(structnotifier_block *nb){ return blocking_notifier_chain_unregister(&test_chain_head, nb);}static int test_chain_notify(struct notifier_block *nb,unsigned long mode, void *_unused){ printk(KERN_EMERG "notifier: test_chain_notify!n");//回调处理函数 return 0;}static struct notifier_block test_chain_nb = { .notifier_call = test_chain_notify,};static int notifier_test_init(void){ printk(KERN_EMERG "notifier: notifier_test_init!n");register_test_notifier(&test_chain_nb);//注册notifier事件 return 0;}static void notifier_test_exit(void){ printk(KERN_EMERG "notifier: notifier_test_exit!n"); unregister_test_notifier(&test_chain_nb);}module_init(notifier_test_init);module_exit(notifier_test_exit);MODULE_LICENSE("GPL v2");call.c用来触发事件 。
#include <linux/kernel.h>#include <linux/module.h>#include <linux/notifier.h>extern struct blocking_notifier_head test_chain_head;static int call_notifier_call_chain(unsigned long val){ int ret = blocking_notifier_call_chain(&test_chain_head, val, NULL); return notifier_to_errno(ret);}static int call_test_init(void){ printk(KERN_EMERG "notifier: call_test_init!n"); call_notifier_call_chain(123); //在init函数中触发事件 return 0;}static void call_test_exit(void){ printk(KERN_EMERG "notifier: call_test_exit!n");}module_init(call_test_init);module_exit(call_test_exit);MODULE_LICENSE("GPL v2");测试结构如下:
root@test:/data # insmod notifier.koroot@test:/data # insmod call.koroot@test:/data # dmesg | grep "notifier"[89.644596] c7 notifier: notifier_test_init![95.956801] c6 notifier: call_test_init![95.960624] c6 notifier: test_chain_notify!


推荐阅读