一 通知链概述:
大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣。为了满足这个需求,也即是让某个子系统在发生某个事件时通知其它的子系统,
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: ==============================