我有一个要维护的模块,并且似乎在内核中保留了引用计数器存在问题,这导致在我杀死打开模块的 3 个原始套接字的守护程序后,我无法对我的模块进行 rmmod。有趣的是,在加载守护进程 'lsmod' 后显示存在 6 个对模块的引用,我预计只有三个。
这发生在带有 Linux-2.6.31 的基于 ARM 的嵌入式系统上,并且 rmmod 没有“强制”模式来尝试强制卸载模块(这无论如何都不是好主意)。
我已经分析了代码,这就是我所拥有的: 1) 模块创建新的套接字地址系列 AF_HSL 并向内核注册:
static struct proto_ops SOCKOPS_WRAPPED (hsl_ops) = {
family: AF_HSL,
owner: THIS_MODULE,
release: hsl_sock_release,
bind: _hsl_sock_bind,
connect: sock_no_connect,
socketpair: sock_no_socketpair,
accept: sock_no_accept,
getname: _hsl_sock_getname,
poll: datagram_poll,
ioctl: sock_no_ioctl,
listen: sock_no_listen,
shutdown: sock_no_shutdown,
setsockopt: sock_no_setsockopt,
getsockopt: sock_no_getsockopt,
sendmsg: _hsl_sock_sendmsg,
recvmsg: _hsl_sock_recvmsg,
mmap: sock_no_mmap,
sendpage: sock_no_sendpage,
};
static struct net_proto_family hsl_family_ops = {
family: AF_HSL,
create: _hsl_sock_create,
owner: THIS_MODULE
};
...
static int
_hsl_sock_create (struct net *net, struct socket *sock, int protocol)
{
struct sock *sk = NULL;
sock->state = SS_UNCONNECTED;
sk = sk_alloc (current->nsproxy->net_ns, AF_HSL, GFP_KERNEL, &_prot);
if (sk == NULL)
goto ERR;
sock->ops = &SOCKOPS_WRAPPED(hsl_ops);
sock_init_data (sock,sk);
sock_hold (sk); /* XXX */
...
}
static void
_hsl_sock_destruct (struct sock *sk)
{
struct hsl_sock *hsk, *phsk;
if (!sk)
return;
...
sock_orphan (sk);
skb_queue_purge (&sk->sk_receive_queue);
sock_put (sk);
}
int
hsl_sock_release (struct socket *sock)
{
struct sock *sk = sock->sk;
/* Here goes logic to destroy net_devices */
...
_hsl_sock_destruct (sk);
sock->sk = NULL;
return 0;
}
2) 守护进程以这种方式创建套接字
fd = socket(AF_HSL, SOCK_RAW, 0);;
bind();
getsockname();
但是我不认为 _hsl_sock_create() 应该调用 sock_hold(),这会增加套接字的引用计数,但是它已经被 sock_init_data() 设置为 1,并且在套接字删除阶段 sock_put() 会减 1,但是这会没有空闲的插座;d 并从系统中完全删除。
所以我试验并删除了 sock_hold(); 现在杀死所有引用中的守护进程产生并且“rmmod”成功,但是启动守护进程后的引用数量仍然是3。
我还检查了 socket_create() 的代码,它调用了内部函数 __socket_create(),而后者又调用了 try_module_get() 并保存了模块的引用计数。这似乎是我发现的唯一显式增加模块的 refcnt 的地方。
我仍然很困惑。有人会尝试帮助了解正在发生的事情吗?
期待您的回音。
标记