我有一个内核模块和一个使用Netlink进行通信的相应用户空间模块。内核模块中使用以下代码将数据发送到用户空间:
int msglen = len - FRAME_PACKET_HEADER_SIZE;
struct sk_buff* skb = nlmsg_new(msglen, GFP_ATOMIC);
if (skb)
{
struct nlmsghdr* nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, msglen, GFP_ATOMIC);
nlh->nlmsg_flags = NLM_F_REQUEST;
NETLINK_CB(skb).dst_group = 0;
memcpy(nlmsg_data(nlh), &buf[FRAME_PACKET_HEADER_SIZE], msglen);
status = nlmsg_unicast(mod_data->netlink_sock, skb, mod_data->netlink_pid);
}
在高数据活动期间(从内核发送到用户空间的Netlink消息),nlmsg_new
开始返回NULL
并且无法分配。高数据活动与文件传输有关,文件传输以16k块的形式推送到用户空间。经过一些调试后,我发现当nlmsg_new
失败时,我可以成功地分配比我实际需要分配的消息略小的消息(所需大小为16336字节,分配为16000个工作)。
问题:
我读过的文档表明,为每封要发送的邮件调用nlmsg_new
是正确的。似乎没有办法重用sk_buff
对象,因为它可能在队列中等待一段时间,并且nlmsg_unicast
在实际发送消息时处理释放(因此没有手动nlmsg_free
是需要)。这绝对是这样吗?有没有办法可以重用nlmsg_new
分配的缓冲区?
我想知道是否有一堆ACK消息正在排队,这些消息在某处填满了一些缓冲区。我将nlmsg_flags
设置为NLM_F_REQUEST
,因此用户空间模块不应该发送ACK。这是对的吗?
分配失败的其他任何想法?
对于上下文,这是在具有256 MiB RAM的嵌入式ARM上运行。内核是3.14.28。
用户空间模块通过调用recvmsg
不断为接收队列提供服务,因此我不认为接收缓冲区已满。我认为如果是这种情况,内核模块将成功分配缓冲区,但对nlmsg_unicast
的调用将返回-EAGAIN
(不会发生)。
编辑:
我在linux/netlink.h
看到了一个有趣的注释:
/*
* skb should fit one page. This choice is good for headerless malloc.
* But we should limit to 8K so that userspace does not have to
* use enormous buffer sizes on recvmsg() calls just to avoid
* MSG_TRUNC when PAGE_SIZE is very large.
*/
所以我尝试减小邮件大小,以便netlink邮件和标题是< 8192个字节,但仍然发生相同的故障(稍后,正如预期的那样)。
编辑2:
查看报告的可用内存后,看起来永远不会释放通过sk_buff
分配的nlmsg_new
个对象。当引用计数(users
的{{1}})变为0时,它们似乎应该被释放。是否有任何理由说Netlink正在保持缓冲区,等待永远不会到来的ACK?