我有一个内核模块和一个使用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:查看报告的可用内存后,看起来通过 nlmsg_new
分配的 sk_buff
对象永远不会被释放 . 当引用计数( sk_buff
为 sk_buff
)变为0时,它们似乎应该被释放 . 是否有任何理由Netlink持有缓冲区,等待永远不会到来的ACK?