全部博文(19)
分类: LINUX
2009-03-01 20:55:37
35 struct notifier_block {当我们初始化子系统的时候,应该知道自己到底对哪些事件比较敏感,也就是说知道哪些事件的发生会对自己的功能发生影响,如果有的话,就注册自己到这个特定的notification chain里面去,我们举一个例子来看看:
36 int (*notifier_call)(struct notifier_block *, unsigned long, void *);
37 struct notifier_block *next;
38 int priority;
39 };
1242 void __init arp_init(void)这个取自arp的初始化,我们注意最后一行的函数register_netdevice_notifier,这个就是注册函数,当然它还会有多层的调用,而arp_netdev_notifier就是一个notifier_block的结构,其中回调函数初始化为arp_netdev_event。我们先来看一下这个回调函数的实现
1243 {
1244 neigh_table_init(&arp_tbl);
1245
1246 dev_add_pack(&arp_packet_type);
1247 arp_proc_init();
1248 #ifdef CONFIG_SYSCTL
1249 neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4,
1250 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
1251 #endif
1252 register_netdevice_notifier(&arp_netdev_notifier);
1253 }
1201 static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)我们看到了,它只关心一种event,那就是NETDEV_CHANGEADDR,其他的事件发生它就并不在意了,当网络设备发生任何已经定义好的事件时,会遍历notification chain来进行遍历通知,如果是我们关心的事件发生,我们就作出相应的反应进行处理,如果不是,那么就当什么都没有发生。
1202 {
1203 struct net_device *dev = ptr;
1204
1205 switch (event) {
1206 case NETDEV_CHANGEADDR:
1207 neigh_changeaddr(&arp_tbl, dev);
1208 rt_cache_flush(0);
1209 break;
1210 default:
1211 break;
1212 }
1213
1214 return NOTIFY_DONE;
1215 }
105 static int notifier_chain_register(struct notifier_block **nl,这个函数的作用就是把一个notifier_block加入到chain中去,不过这个链表的插入方法有点诡异,因为它直接利用了二级指针的一个巧妙应用,一般我们插入链表都需要有一个指针来保存前一个位置,然后再插入表元,而在这里,它只利用了一个指针就完成了这些工作,也就是把这个二级指针保存了前一个表元的next指针。
106 struct notifier_block *n)
107 {
108 while ((*nl) != NULL) {
109 if (n->priority > (*nl)->priority)
110 break;
111 nl = &((*nl)->next);
112 }
113 n->next = *nl;
114 rcu_assign_pointer(*nl, n);
115 return 0;
116 }
131 static int __kprobes notifier_call_chain(struct notifier_block **nl,这个函数应该很容易理解,就是调用回调函数进行处理。
132 unsigned long val, void *v)
133 {
134 int ret = NOTIFY_DONE;
135 struct notifier_block *nb;
136
137 nb = rcu_dereference(*nl);
138 while (nb) {
139 ret = nb->notifier_call(nb, val, v);
140 if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
141 break;
142 nb = rcu_dereference(nb->next);
143 }
144 return ret;
145 }