1、netlink_kernel_create()函数分析
/*
* We export these functions to other modules. They provide a
* complete set of kernel non-blocking support for message
* queueing.
*/
struct sock *
netlink_kernel_create(struct net *net, int unit, unsigned int groups,
void (*input)(struct sk_buff *skb),
struct mutex *cb_mutex, struct module *module)
//net参数是新引入的,可用&init_net。这个init_net结构体是在linux/net/core/net_namespace.c 中定义的,此外在linux/include/net/net_namespace.h中也有外部定义,直接作为参数使用
//即可。unit即netlink接口类型,有ROUTE,FIREWALL,IP6_FW,XFRM等,最大值为MAX_LINKS。groups为具体各种类型netlink接口中的组号。input是消息处理函数,只要用户程序发送一个NETLINK_TEST类型的netlink消息到内核的话,通过netlink_kernel_create()函数注册的回调函数input()都会被调用。cb_mutex和module都是新添加的参数,具体功能不了解。
{
struct socket *sock;
struct sock *sk;
struct netlink_sock *nlk;
unsigned long *listeners = NULL;
BUG_ON(!nl_table);
// unit范围检查
if (unit < 0 || unit >= MAX_LINKS)
return NULL;
// 建立netlink的socket
if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))
return NULL;
/*
* We have to just have a reference on the net from sk, but don't
* get_net it. Besides, we cannot get and then put the net here.
* So we create one inside init_net and the move it to net.
*/
// 建立unit类型的netlink的sock
if (__netlink_create(&init_net, sock, cb_mutex, unit) < 0)
goto out_sock_release_nosk;
//第一个参数net,在这里使用
sk = sock->sk;
sk_change_net(sk, net);
// 小于32的组号都设置为32
// ip_queue中该参数为0, nfnetlink中该参数为NFNLGRP_MAX,都不超过32
// 所以实际两者等价
if (groups < 32)
groups = 32;
// 监听者
listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL);
if (!listeners)
goto out_sock_release;
sk->sk_data_ready = netlink_data_ready;
// netlink接口输入函数,也就是处理用户空间发送到内核方向的数据
if (input)
nlk_sk(sk)->netlink_rcv = input;
// 将该sock插入HASH表,这里和net参数有关,在没有net参数的内核版本中的命令是if (netlink_insert(sk, 0))
if (netlink_insert(sk, net, 0))
goto out_sock_release;
// 设置该netlink sock的一些基本参数
nlk = nlk_sk(sk);
nlk->flags |= NETLINK_KERNEL_SOCKET;
netlink_table_grab();
if (!nl_table[unit].registered) {
nl_table[unit].groups = groups;
nl_table[unit].listeners = listeners;
//最新的两个参数cb_mutex和module在这里使用
nl_table[unit].cb_mutex = cb_mutex;
nl_table[unit].module = module;
nl_table[unit].registered = 1;
} else {
kfree(listeners);
nl_table[unit].registered++;
}
netlink_table_ungrab();
return sk;
out_sock_release:
kfree(listeners);
netlink_kernel_release(sk);
return NULL;
out_sock_release_nosk:
sock_release(sock);
return NULL;
}
2、解决 rmmod出错的问题
卸载出错后的stack信息如下:
-----------[ cut here ]------------
kernel BUG at mm/slub.c:2743!
invalid opcode: 0000 [#1] SMP
last sysfs file: /sys/devices/pci0000:00/0000:00:1c.1/0000:3f:00.0/irq
Dumping ftrace buffer:
(ftrace buffer empty)
Modules linked in: nltimer_k(-) ppp_async crc_ccitt arc4 ecb ppp_mppe ppp_generic slhc vfat fat fuse radeon drm ipt_MASQUERADE iptable_nat nf_nat bridge stp bnep sco l2cap bluetooth sunrpc ipv6 cpufreq_ondemand acpi_cpufreq dm_multipath uinput snd_hda_intel snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd_page_alloc snd_hwdep snd tg3 iTCO_wdt ppdev iTCO_vendor_support r8169 parport_pc libphy parport mii soundcore pcspkr serio_raw floppy wmi ata_generic pata_acpi [last unloaded: microcode]
Pid: 4192, comm: rmmod Not tainted (2.6.28 #1) HP Compaq dc7608 Convertible Minitower
EIP: 0060:[<c04907a0>] EFLAGS: 00210246 CPU: 0
EIP is at kfree+0x33/0xd9
EAX: 00000000 EBX: c16febe0 ECX: 00000007 EDX: 00000007
ESI: f7f5fd84 EDI: cbd34f58 EBP: cbd34f48 ESP: cbd34f34
DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
Process rmmod (pid: 4192, ti=cbd34000 task=e4080cc0 task.ti=cbd34000)
Stack:
cbd34f3c c042eaf2 00000000 f7f5ec00 cbd34f58 cbd34f50 f7f5e01f cbd34fb0
c044dee9 69746c6e 5f72656d cbd3006b c04806ed cbc81f78 cbcdf200 cbd34fa0
f3726360 f3726000 cbd34f88 c049a27e 00000000 00000000 f3726000 00d34fb4
Call Trace:
[<c042eaf2>] ? put_online_cpus+0x42/0x44
[<f7f5e01f>] ? nltimer_exit+0xd/0x6a [nltimer_k]
[<c044dee9>] ? sys_delete_module+0x1ae/0x1f8
[<c04806ed>] ? remove_vma+0x55/0x5b
[<c049a27e>] ? path_put+0x15/0x18
[<c04039bb>] ? sysenter_do_call+0x12/0x34
Code: 83 ec 08 83 f8 10 0f 86 bd 00 00 00 e8 05 dd ff ff 89 c2 89 c3 b8 07 00 00 00 e8 dc dc ff ff 85 c0 75 18 f7 03 00 60 00 00 75 04 <0f> 0b eb fe 89 d8 e8 42 62 fe ff e9 8e 00 00 00 8b 45 04 89 45
EIP: [<c04907a0>] kfree+0x33/0xd9 SS:ESP 0068:cbd34f34
---[ end trace d95ab8b25dc766c7 ]---
Google了一下,猜测是kfree()函数的问题,于是将例子中的kfree()都屏蔽掉,于是卸载就没有问题了