nlmsg_new无法分配缓冲区

时间:2017-07-18 12:24:44

标签: c linux linux-kernel netlink

我有一个内核模块和一个使用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个工作)。

问题:

  1. 我读过的文档表明,为每封要发送的邮件调用nlmsg_new是正确的。似乎没有办法重用sk_buff对象,因为它可能在队列中等待一段时间,并且nlmsg_unicast在实际发送消息时处理释放(因此没有手动nlmsg_free是需要)。这绝对是这样吗?有没有办法可以重用nlmsg_new分配的缓冲区?

  2. 我想知道是否有一堆ACK消息正在排队,这些消息在某处填满了一些缓冲区。我将nlmsg_flags设置为NLM_F_REQUEST,因此用户空间模块不应该发送ACK。这是对的吗?

  3. 分配失败的其他任何想法?

  4. 对于上下文,这是在具有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?

0 个答案:

没有答案