一 通知链概述:
大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣。为了满足这个需求,也即是让某个子系统在发生某个事件时通知其它的子系统,
Linux内核提供了通知链的机制。通知链表只能够在内核的子系统之间使用,而不能够在内核与用户空间之间进行事件的通知。通知链表是一个函数链表,链表上的每一个节点都注册了一个函数。当某个事情发生时,链表上所有节点对应的函数就会被执行。所以对于通知链表来说有一个通知方与一个接收方。在通知这个事件时所运行的函数由被通知方决定,实际上也即是被通知方注册了某个函数,在发生某个事件时这些函数就得到执行。其实和系统调用signal的思想差不多。
注意:通知链只在内核子系统之间使用。
二 定义:
为了方便相互联系紧密的子系统之间的互交,内核中应用了通知链。通知链表的节点类型为notifier_block,其定义如下:
struct notifier_block {
int (*notifier_call)(struct notifier_block *, unsigned long, void *);
struct notifier_block __rcu *next;
int priority;
};
其中最重要的就是notifier_call这个函数指针,表示了这个节点所对应的要运行的那个函数。next指向下一个节点,即当前事件发生时还要继续执行的那些节点。该函数在: include/linux/notifier.h
三 通知链的注册与解注册:
通知链的注册与解注册分别由函数:int notifier_chain_register(struct notifier_block **nl, struct notifier_block *n) 和函数:int notifier_chain_unregister(strut notifier_block **nl, struct notifier_block *n) 来实现的,由于上面的两个函数用法极其简单,就不在详细介绍了。
四 通知链上的事件:
当有事件发生时,就使用notifier_call_chain向某个通知链表发送消息。该函数的定义和解释如下所示:
/**
* 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 __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_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;
}
函数路径:kernel/kernel/notifier.c
五 内核实际例子:
代码路径:kernel/net/ipv4/fib_frontend.c
六 测试实例:
代码一它的作用是自定义一个通知链表test_chain,然后再自定义两个函数分别向这个通知链中加入或删除节点,最后再定义一个函数通知这个test_chain链。
#include <asm/uaccess.h>
2: #include <linux/types.h>
3: #include <linux/kernel.h>
4: #include <linux/sched.h>
5: #include <linux/notifier.h>
6: #include <linux/init.h>
7: #include <linux/types.h>
8: #include <linux/module.h>
9: MODULE_LICENSE("GPL");
10:
11: /*
12: * 定义自己的通知链头结点以及注册和卸载通知链的外包函数
13: */
14:
15: /*
16: * RAW_NOTIFIER_HEAD是定义一个通知链的头部结点,
17: * 通过这个头部结点可以找到这个链中的其它所有的notifier_block
18: */
19:
20: static RAW_NOTIFIER_HEAD(test_chain);
21:
22: /*
23: * 自定义的注册函数,将notifier_block节点加到刚刚定义的test_chain这个链表中来
24: * raw_notifier_chain_register会调用notifier_chain_register
25: */
26:
27: int register_test_notifier(struct notifier_block *nb)
28: {
29: return raw_notifier_chain_register(&test_chain, nb);
30: }
31: EXPORT_SYMBOL(register_test_notifier);
32:
33: int unregister_test_notifier(struct notifier_block *nb)
34: {
35: return raw_notifier_chain_unregister(&test_chain, nb);
36: }
37: EXPORT_SYMBOL(unregister_test_notifier);
38:
39: /*
40: * 自定义的通知链表的函数,即通知test_chain指向的链表中的所有节点执行相应的函数
41: */
42:
43: int test_notifier_call_chain(unsigned long val, void *v)
44: {
45: return raw_notifier_call_chain(&test_chain, val, v);
46: }
47: EXPORT_SYMBOL(test_notifier_call_chain);
48:
49: /*
50: * init and exit
51: */
52:
53: static int __init init_notifier(void)
54: {
55: printk("init_notifier\n");
56: return 0;
57: }
58:
59: static void __exit exit_notifier(void)
60: {
61: printk("exit_notifier\n");
62: }
63: module_init(init_notifier);
64: module_exit(exit_notifier);
代码二:该代码的作用是将test_notifier1 test_notifier2 test_notifier3这三个节点加到之前定义的test_chain这个通知链表上,同时每个节点都注册了一个函数。
#include <asm/uaccess.h>
2: #include <linux/types.h>
3: #include <linux/kernel.h>
4: #include <linux/sched.h>
5: #include <linux/notifier.h>
6: #include <linux/init.h>
7: #include <linux/types.h>
8: #include <linux/module.h>
9: MODULE_LICENSE("GPL");
10:
11: /*
12: * 注册通知链
13: */
14:
15: extern int register_test_notifier(struct notifier_block*);
16:
17: extern int unregister_test_notifier(struct notifier_block*);
18:
19: static int test_event1(struct notifier_block *this, unsigned long event, void *ptr)
20: {
21: printk("In Event 1: Event Number is %d\n", event);
22: return 0;
23: }
24:
25: static int test_event2(struct notifier_block *this, unsigned long event, void *ptr)
26: {
27: printk("In Event 2: Event Number is %d\n", event);
28: return 0;
29: }
30:
31: static int test_event3(struct notifier_block *this, unsigned long event, void *ptr)
32: {
33: printk("In Event 3: Event Number is %d\n", event);
34: return 0;
35: }
36:
37: /*
38: * 事件1,该节点执行的函数为test_event1
39: */
40:
41: static struct notifier_block test_notifier1 =
42: {
43: .notifier_call = test_event1,
44: };
45:
46: /*
47: * 事件2,该节点执行的函数为test_event1
48: */
49:
50: static struct notifier_block test_notifier2 =
51: {
52: .notifier_call = test_event2,
53: };
54:
55: /*
56: * 事件3,该节点执行的函数为test_event1
57: */
58:
59: static struct notifier_block test_notifier3 =
60: {
61: .notifier_call = test_event3,
62: };
63:
64: /*
65: * 对这些事件进行注册
66: */
67:
68: static int __init reg_notifier(void)
69: {
70: int err;
71: printk("Begin to register:\n");
72:
73: err = register_test_notifier(&test_notifier1);
74: if (err)
75: {
76: printk("register test_notifier1 error\n");
77: return -1;
78: }
79: printk("register test_notifier1 completed\n");
80:
81: err = register_test_notifier(&test_notifier2);
82: if (err)
83: {
84: printk("register test_notifier2 error\n");
85: return -1;
86: }
87: printk("register test_notifier2 completed\n");
88:
89: err = register_test_notifier(&test_notifier3);
90: if (err)
91: {
92: printk("register test_notifier3 error\n");
93: return -1;
94: }
95: printk("register test_notifier3 completed\n");
96: return err;
97: }
98:
99: /*
100: * 卸载刚刚注册了的通知链
101: */
102:
103: static void __exit unreg_notifier(void)
104: {
105: printk("Begin to unregister\n");
106: unregister_test_notifier(&test_notifier1);
107: unregister_test_notifier(&test_notifier2);
108: unregister_test_notifier(&test_notifier3);
109: printk("Unregister finished\n");
110: }
111: module_init(reg_notifier);
112: module_exit(unreg_notifier);
代码三:该代码的作用就是向test_chain通知链中发送消息,让链中的函数运行。
1: #include <asm/uaccess.h>
2: #include <linux/types.h>
3: #include <linux/kernel.h>
4: #include <linux/sched.h>
5: #include <linux/notifier.h>
6: #include <linux/init.h>
7: #include <linux/types.h>
8: #include <linux/module.h>
9: MODULE_LICENSE("GPL");
10:
11: extern int test_notifier_call_chain(unsigned long val, void *v);
12:
13: /*
14: * 向通知链发送消息以触发注册了的函数
15: */
16:
17: static int __init call_notifier(void)
18: {
19: int err;
20: printk("Begin to notify:\n");
21:
22: /*
23: * 调用自定义的函数,向test_chain链发送消息
24: */
25:
26: printk("==============================\n");
27: err = test_notifier_call_chain(1, NULL);
28: printk("==============================\n");
29: if (err)
30: printk("notifier_call_chain error\n");
31: return err;
32: }
33:
34:
35: static void __exit uncall_notifier(void)
36: {
37: printk("End notify\n");
38: }
39: module_init(call_notifier);
40: module_exit(uncall_notifier);
分别注册三个驱动,查看打印,可以看到如下打印:
1: init_notifier
2: Begin to register:
3: register test_notifier1 completed
4: register test_notifier2 completed
5: register test_notifier3 completed
6: Begin to notify:
7: ==============================
8: In Event 1: Event Number is 1
9: In Event 2: Event Number is 1
10: In Event 3: Event Number is 1
11: ==============================